基于Kafka的分布式日志收集平台

项目环境:CentOS 7.9   Kafka 3.6.1   Celery5.0   redis   Nginx   Filebeat 7.x。

项目描述:设计并部署高可用日志收集与分析平台,实现从nginx反向代理、采集nginx日志数据(Filebeat)、传输到(Kafka)、到设置定时任务(Celery+redis)进行监控告警的全链路自动化。

  1. 基于Kafka KRaft模式构建无ZooKeeper集群,支持高吞吐日志存储与多消费者并发处理。

  2. 利用Nginx反向代理后端的flask程序,保障服务高可用性。

  3. 通过Filebeat实时采集Nginx日志并推送至Kafka。

  4. 使用python-kafka并发消费数据,并把清洗后的数据存入MySQL数据库。

  5. 结合Celery+Redis定时监控日志数据中的流量,超过阈值时发送邮件警告。

目录

项目规划图

项目步骤

1. 环境准备

2.部署kafka集群

3.nginx反向代理集群搭建

4.后端flask程序

5.部署filebeat(在nginx服务器上)

6.celery+redis


项目规划图

项目步骤

1. 环境准备

  • 依赖软件安装

yum源配置:
    cd /etc/yum.repos.d
    mkdir repo
    mv *.repo repo/
    下载阿里云源:
    curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo

下载依赖软件:
yum install epel-release -y
yum install wget vim java-11-openjdk.x86_64  -y
  • 配置静态ip地址,修改/etc/sysconfig/network-scripts/ifcfg-ens33

[root@wcw ~]# vim /etc/sysconfig/network-scripts/ifcfg-ens33

TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO="none"
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=ens33
UUID=246e853f-0055-482d-b669-4d3d97bf163a
DEVICE=ens33
ONBOOT=yes
IPADDR=192.168.10.146
PREFIX=24
#NETMASK=255.255.255.0
GATEWAY=192.168.10.2
DNS1=114.114.114.114
DNS2=192.168.10.2
  • 配置主机名(以kafka1为例)

hostnamectl set-hostname kafka1
  • 修改/etc/hosts文件,添加主机名和ip地址映射

192.168.10.146  kafka1
192.168.10.147  kafka2
192.168.10.148  kafka3
  • 关闭防火墙与selinux

关闭防火墙:
  iptables -F                #清空防火墙规则
  systemctl stop firewalld   #关闭防火墙服务
  systemctl disable firewalld  #设置开机不自启
关闭selinux,编辑/etc/selinux/config 文件
    [root@kafka1 kafka_2.13-3.6.1]# vim /etc/selinux/config 

    # This file controls the state of SELinux on the system.
    # SELINUX= can take one of these three values:
    #     enforcing - SELinux security policy is enforced.
    #     permissive - SELinux prints warnings instead of enforcing.
    #     disabled - No SELinux policy is loaded.
    #SELINUX=enforcing
    SELINUX=disabled
    # SELINUXTYPE= can take one of three values:
    #     targeted - Targeted processes are protected,
    #     minimum - Modification of targeted policy. Only selected processes are protected. 
    #     mls - Multi Level Security protection.
    SELINUXTYPE=targeted
重启系统:
  reboot

2.部署kafka集群

使用kafka的好处:

高吞吐:支持海量日志实时写入,避免数据丢失。

持久化:日志可保留多天,供后续回溯或批量分析。

分区与副本:通过分区提升并行处理能力,副本机制保障高可用性。

  • 下载kafka

cd /opt
wget https://archive.apache.org/dist/kafka/3.6.1/kafka_2.13-3.6.1.tgz
  • 解压缩

tar xf kafka_2.13-3.6.1.tgz 
cd kafka_2.13-3.6.1
  • 修改配置文件,位于kafka目录下config/kraft/server.properties

[root@kafka1 opt]# cd kafka_2.13-3.6.1
[root@kafka1 kafka_2.13-3.6.1]# ls
bin  config  libs  LICENSE  licenses  logs  NOTICE  site-docs  tmp_random
[root@kafka1 kafka_2.13-3.6.1]# vim /etc/selinux/config 
[root@kafka1 kafka_2.13-3.6.1]# vim config/kraft/server.properties

        三个节点都需要配置(每个节点id唯一) 

    #修改节点id,每个节点唯一
    node.id=1
    
    #修改控制器投票列表
    controller.quorum.voters=1@192.168.10.146:9093,2@192.168.10.147:9093,3@192.168.10.148:9093
    
    #修改监听器和控制器,绑定ip。其中kafka1为主机名,可用本机ip地址代替
    listeners=PLAINTEXT://kafka1:9092,CONTROLLER://kafka1:9093
    
    # 侦听器名称、主机名和代理将向客户端公布的端口.(broker 对外暴露的地址)
    # 如果未设置,则使用"listeners"的值.
    advertised.listeners=PLAINTEXT://kafka1:9092
      • 配置文件详解

      ############################# Server Basics #############################
      
      # 此服务器的角色。设置此项将进入KRaft模式(controller 相当于主机、broker 节点相当于从机,主机类似 zk 功能)
      process.roles=broker,controller
      
      # 节点 ID
      node.id=1
      
      # 全 Controller 列表
      controller.quorum.voters=1@192.168.10.146:9093,2@192.168.10.147:9093,3@192.168.10.148:9093
      
      ############################# Socket Server Settings #############################
      
      # 套接字服务器侦听的地址.
      # 组合节点(即具有`process.roles=broker,controller`的节点)必须至少在此处列出控制器侦听器
      # 如果没有定义代理侦听器,那么默认侦听器将使用一个等于java.net.InetAddress.getCanonicalHostName()值的主机名,
      # 带有PLAINTEXT侦听器名称和端口9092
      #   FORMAT:
      #     listeners = listener_name://host_name:port
      #   EXAMPLE:
      #     listeners = PLAINTEXT://your.host.name:9092
      #不同服务器绑定的端口
      listeners=PLAINTEXT://kafka1:9092,CONTROLLER://kafka1:9093
      
      # 用于代理之间通信的侦听器的名称(broker 服务协议别名)
      inter.broker.listener.name=PLAINTEXT
      
      # 侦听器名称、主机名和代理将向客户端公布的端口.(broker 对外暴露的地址)
      # 如果未设置,则使用"listeners"的值.
      advertised.listeners=PLAINTEXT://kafka1:9092
      
      # controller 服务协议别名
      # 控制器使用的侦听器名称的逗号分隔列表
      # 如果`listener.security.protocol.map`中未设置显式映射,则默认使用PLAINTEXT协议
      # 如果在KRaft模式下运行,这是必需的。
      controller.listener.names=CONTROLLER
      
      # 将侦听器名称映射到安全协议,默认情况下它们是相同的。(协议别名到安全协议的映射)有关更多详细信息,请参阅配置文档.
      listener.security.protocol.map=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,SSL:SSL,SASL_PLAINTEXT:SASL_PLAINTEXT,SASL_SSL:SASL_SSL
      
      # 服务器用于从网络接收请求并向网络发送响应的线程数
      num.network.threads=3
      
      # 服务器用于处理请求的线程数,其中可能包括磁盘I/O
      num.io.threads=8
      
      # 套接字服务器使用的发送缓冲区(SO_SNDBUF)
      socket.send.buffer.bytes=102400
      
      # 套接字服务器使用的接收缓冲区(SO_RCVBUF)
      socket.receive.buffer.bytes=102400
      
      # 套接字服务器将接受的请求的最大大小(防止OOM)
      socket.request.max.bytes=104857600
      
      
      ############################# Log Basics #############################
      
      # 存储日志文件的目录的逗号分隔列表(kafka 数据存储目录)
      log.dirs=/usr/kafka/kafka_2.13-3.6.1/datas
      
      # 每个主题的默认日志分区数。更多的分区允许更大的并行性以供使用,但这也会导致代理之间有更多的文件。
      num.partitions=1
      
      # 启动时用于日志恢复和关闭时用于刷新的每个数据目录的线程数。
      # 对于数据目录位于RAID阵列中的安装,建议增加此值。
      num.recovery.threads.per.data.dir=1
      
      ############################# Internal Topic Settings  #############################
      # 组元数据内部主题"__consumer_offsets"和"__transaction_state"的复制因子
      # 对于除开发测试以外的任何测试,建议使用大于1的值来确保可用性,例如3.
      offsets.topic.replication.factor=1
      transaction.state.log.replication.factor=1
      transaction.state.log.min.isr=1
      
      ############################# Log Flush Policy #############################
      
      # 消息会立即写入文件系统,但默认情况下,我们只使用fsync()进行同步
      # 操作系统缓存延迟。以下配置控制将数据刷新到磁盘.
      # 这里有一些重要的权衡:
      #    1. Durability(持久性): 如果不使用复制,未清理的数据可能会丢失
      #    2. Latency(延迟): 当刷新发生时,非常大的刷新间隔可能会导致延迟峰值,因为将有大量数据要刷新.
      #    3. Throughput(吞吐量): 刷新通常是最昂贵的操作,较小的刷新间隔可能导致过多的寻道.
      # 下面的设置允许配置刷新策略,以便在一段时间后或每N条消息(或两者兼有)刷新数据。这可以全局完成,并在每个主题的基础上覆盖
      
      # 强制将数据刷新到磁盘之前要接受的消息数
      #log.flush.interval.messages=10000
      
      # 在我们强制刷新之前,消息可以在日志中停留的最长时间
      #log.flush.interval.ms=1000
      
      ############################# Log Retention Policy #############################
      
      # 以下配置控制日志段的处理。可以将该策略设置为在一段时间后删除分段,或者在累积了给定大小之后删除分段。
      # 只要满足这些条件中的任意一个,segment就会被删除。删除总是从日志的末尾开始
      
      # 日志文件因使用年限而有资格删除的最短使用年限
      log.retention.hours=168
      
      # 基于大小的日志保留策略。除非剩余的段低于log.retention.bytes,否则将从日志中删除段。独立于log.retention.hours的函数。
      #log.retention.bytes=1073741824
      
      # 日志segment文件的最大大小。当达到此大小时,将创建一个新的日志segment
      log.segment.bytes=1073741824
      
      # 检查日志segments以查看是否可以根据保留策略删除它们的间隔
      log.retention.check.interval.ms=300000
        • 创建集群

        cd   /opt/kafka_2.13-3.6.1
        # 在其中一台执行,生成集群UUID命令,拿到集群UUID保存在当前tmp_random文件中
        bin/kafka-storage.sh random-uuid >tmp_random
        # 查看uuid
        [root@kafka1 kafka_2.13-3.6.1]# cat tmp_random 
        GYTCxaoiRRidOSrStGI20g
        
        # 在所有机器上执行,它会初始化存储区域,为 Kafka 集群的元数据存储和后续操作做好准备。GYTCxaoiRRidOSrStGI20g为自己生成的集群uuid
        
        bin/kafka-storage.sh format -t GYTCxaoiRRidOSrStGI20g -c /opt/kafka_2.13-3.6.1/config/kraft/server.properties
            • 启动

            1. 命令行启动:

            启动:
            bin/kafka-server-start.sh -daemon /opt/kafka_2.13-3.6.1/config/kraft/server.properties
            关闭:
            bin/kafka-server-stop.sh

            2. 使用systemctl管理服务 -- systemd(更推荐)

            ## 编辑文件  /usr/lib/systemd/system/kafka.service 
            [root@kafka1 kafka_2.13-3.6.1]# vim /usr/lib/systemd/system/kafka.service 
            [Unit]
            Description=Apache Kafka server (KRaft mode)
            Documentation=http://kafka.apache.org/documentation.html
            After=network.target
            [Service]
            Type=forking
            User=root
            Group=root
            Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/usr/lib/jvm/java-11-openjdk-11.0.23.0.9-2.el7_9.x86_64/bin/"
            ExecStart=/opt/kafka_2.13-3.6.1/bin/kafka-server-start.sh -daemon /opt/kafka_2.13-3.6.1/config/kraft/server.properties
            ExecStop=/opt/kafka_2.13-3.6.1/bin/kafka-server-stop.sh
            Restart=on-failure
            [Install]
            WantedBy=multi-user.target
            
              
            #重新加载systemd配置
            systemctl daemon-reload
            
            #启动kafka服务
            systemctl  start  kafka
            
            #关闭kafka服务
            systemctl  stop  kafka
            
            #设置开机自启
            systemctl enable kafka

            确认Kafka已启动 

            • 测试集群

            # 创建topic 
            bin/kafka-topics.sh --create --bootstrap-server kafka3:9092 --replication-factor 3 --partitions 3 --topic test_topic
            
            ** --replication-factor指定副本因子,--partitions指定分区数,--topic指定主题名称。
            
            # 查看topic
            bin/kafka-topics.sh --list --bootstrap-server kafka3:9092
            
            #创建生产者,发送消息,测试用
            bin/kafka-console-producer.sh --broker-list kafka3:9092 --topic test_topic
            
            #创建消费者,获取数据,测试用
            bin/kafka-console-consumer.sh --bootstrap-server kafka2:9092 --topic test_topic --from-beginning
            

            在kafka3 消费数据

            3.nginx反向代理集群搭建

            反向代理:代理服务器

            目的:隐藏后端真实服务器,更加安全负载均衡和高可用。

            例如:

            • 安装nginx

            yum install epel-release -y
            yum install nginx -y
            • 编辑配置文件 /etc/nginx/conf.d/sc.conf

            upstream flask {
               server 192.168.10.147:5000;
               server 192.168.10.148:5000;
            
            }
            
            server {
                listen 80;
                server_name www.sc.com;
                location / {
                   proxy_pass http://flask;
                }
            
            }
              • 启动nginx
              systemctl start nginx

              4.后端flask程序

              • 安装flask环境
              yum install python3 -y
              pip3 install flask -i https://pypi.tuna.tsinghua.edu.cn/simple
              • 编辑/opt/python-flask/app.py文件(kafka2)
              from flask import Flask
              
              app = Flask(__name__)
              
              @app.route("/")
              def index():
                  return "this is flask web kafka2"
              
              app.run(host = "0.0.0.0")
              • 编辑/opt/python-flask/app.py文件(kafka3)
              from flask import Flask
              
              app = Flask(__name__)
              
              @app.route("/")
              def index():
                  return "this is flask web kafka3"
              
              app.run(host = "0.0.0.0")
              • 启动flask
              python3 app.py

              可以通过nginx访问kafka2和kafka3。 

              5.部署filebeat(在nginx服务器上)

              Filebeat是用于转发和集中日志数据的轻量级传送工具。属于 Elastic Stack(ELK Stack)的一部分,主要用于从服务器、容器、云服务等环境中收集日志数据,并将其传输到 Elasticsearch 或 Logstash 进行存储、分析和可视化。

              这里是用来实时采集nginx日志数据并推到kafka集群中。好处是日志集中方便管理,不需要登录到每一台服务器上查看日志,同时对日志处理解耦,不影响到nginx。

              • 安装
              1、rpm --import https://packages.elastic.co/GPG-KEY-elasticsearch
              2、编辑 vim /etc/yum.repos.d/fb.repo
              [elastic-7.x]
              name=Elastic repository for 7.x packages
              baseurl=https://artifacts.elastic.co/packages/7.x/yum
              gpgcheck=1
              gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
              enabled=1
              autorefresh=1
              type=rpm-md
              3、yum安装
              yum  install  filebeat -y

              rpm -qa  |grep filebeat  可以查看filebeat有没有安装  rpm -qa 是查看机器上安装的所有软件包

              rpm -ql  filebeat  查看filebeat安装到哪里去了,牵扯的文件有哪些

              • 配置,修改配置文件/etc/filebeat/filebeat.yml
              filebeat.inputs:
              - type: log
                # Change to true to enable this input configuration.
                enabled: true
                # Paths that should be crawled and fetched. Glob based paths.
                paths:
                  - /var/log/nginx/access.log
                  - /var/log/nginx/error.log
              #==========------------------------------kafka-----------------------------------
              output.kafka:
                hosts: ["192.168.10.146:9092","192.168.10.147:9092","192.168.10.148:9092"]
                topic: nginxlog
                keep_alive: 10s
              • 创建主题
              cd /opt/kafka_2.13-3.6.1
              bin/kafka-topics.sh --create --bootstrap-server  kafka3:9092 --replication-factor 3 --partitions 3 --topic nginxlog
              • 启动服务
              systemctl start  filebeat
              systemctl enable filebeat  #设置开机自启

              • 使用kafka-python并发消费日志

              使用kafka-python并发消费日志数据,并对日志数据进行清洗,提取(时间,IP地址,省份,运营商,流量数据),其中省份和运营商通过解析ip得到。

              解析IP地址的网页:http://whois.pconline.com.cn/ipJson.jsp?ip=123.123.123.123&json=true

              config.py文件:

              IP_URL = "http://whois.pconline.com.cn/ipJson.jsp?json=true&ip=" 
              DB_HOST = 数据库IP
              DB_PORT = 端口号
              DB_USER = 用户名
              DB_PASSWD = 密码
              DB = 数据库名称

              lib.py文件:

              import json
              import requests
              from config import *
              import time
              
              # message --> dict
              def json_to_dict(message: str) ->dict:  # 期望输入为str类型,返回值为dict类型
                  d1 = {}
                  try:
                      d1 = json.loads(message)
                  except:
                      print("传递非json格式字符串")
                  return d1
              
              def resolv_ip(ip):
                  # 使用requests库 --相当于python浏览器,请求网址
                  url =  IP_URL+ip
                  response  =requests.get(url)
                  # print( dir(response) )
                  prov = response.json().get("pro")
                  isp = response.json().get("addr").split()[1]
                  return prov,isp
              
              # 时间格式转换
              def time_format(time_str):
                  # 处理带时区的时间字符串
                  struct_time = time.strptime(time_str, "%d/%b/%Y:%H:%M:%S")
                  return time.strftime("%Y-%m-%d %H:%M:%S", struct_time)
              
              # 192.168.10.1 - - [10/Mar/2025:20:47:24 +0800] \"GET / HTTP/1.1\" 200 24 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36 Edg/134.0.0.0\" \"-\"
              def handler_log(log_str):
                  # 修复格式问题
                  log_str = log_str.replace('--[', '- - [')
                  log_str = log_str.replace('\"\"-\"', '""-"')
              
                  log_lst = log_str.split()
                  if len(log_lst) < 10:
                      raise ValueError("日志格式不完整")
              
                  ip = log_lst[0]
                  time_str = log_lst[3][1:]  # 移除开头的[
                  status_code = log_lst[8]
                  flow = int(log_lst[9]) if len(log_lst) >= 10 else 0
              
                  prov, isp = resolv_ip(ip)
                  resukt_time = time_format(time_str)
              
                  return resukt_time, ip, prov, isp, flow
              
              

              consum.py文件:

              from kafka import KafkaConsumer
              from multiprocessing import Process, current_process
              import time
              import lib
              import pymysql
              from config import *
              
              def consume_kafka_partition(topic, group_id, partition):
                  """
                  进程执行的函数,用于消费指定分区的Kafka消息
                  """
                  consumer = KafkaConsumer(
                      group_id=group_id,
                      bootstrap_servers=['192.168.10.146:9092', '192.168.10.147:9092', '192.168.10.148:9092',],
                      auto_offset_reset='earliest',  # 可按需调整偏移量重置策略
                      enable_auto_commit=True,       # 自动提交偏移量
                      auto_commit_interval_ms=5000,  # 每5秒提交一次偏移量
                      value_deserializer=lambda x: x.decode('utf-8')  # 将消息值解码为UTF-8字符串  -  (反序列化)
                  )
                  # 为消费者订阅的主题
                  consumer.subscribe(topic)
              
                  # 初始化数据库连接
                  conn = pymysql.connect(
                      host=DB_HOST,
                      user=DB_USER,
                      password=DB_PASSWD,
                      db=DB,
                      port=DB_PORT)
              
                  cursor = conn.cursor()
              
                  # 创建表(如果不存在)
                  create_table_sql = """
                      CREATE TABLE IF NOT EXISTS nginx_logs (
                          id INT AUTO_INCREMENT PRIMARY KEY,
                          timestamp DATETIME,
                          ip VARCHAR(45),
                          province VARCHAR(45),
                          isp VARCHAR(45),
                          flow INT
                      )
                      """
                  cursor.execute(create_table_sql)
                  conn.commit()
              
                  try:
                      for message in consumer:
                          log_str = message.value
                          try:
                              # 处理日志数据
                              resukt_time, ip, prov, isp, flow = lib.handler_log(log_str)
              
                              # 插入数据库
                              insert_sql = """
                                  INSERT INTO nginx_logs (timestamp, ip, province, isp, flow)
                                  VALUES (%s, %s, %s, %s, %s)
                                  """
                              cursor.execute(insert_sql, (resukt_time, ip, prov, isp, flow))
                              conn.commit()
              
                              print(f"成功插入数据: {ip} - {resukt_time}")
              
                          except Exception as e:
                              print(f"处理日志失败: {e}")
                              conn.rollback()
              
                  except Exception as e:
                      print(f"消费者异常: {e}")
                  finally:
                      # 关闭连接
                      cursor.close()
                      conn.close()
                      consumer.close()
              
              
              if __name__ == "__main__":
                  topic = "nginxlog"  # 根据实际情况修改要消费的主题名称
                  group_id = "message_group3"  # 根据实际情况修改消费组名称  只要更改消费组的名称就可以重新拿取数据(所有的旧数据)
                  partitions = [0, 1, 2]  # 定义要消费的分区列表,可按需调整
              
                  # 设置进程名称(可选)
                  def start_process(target, args):
                      p = Process(target=target, args=args)
                      p.name = f"Consumer-Partition-{args[2]}"  # 设置进程名称
                      p.start()
                      return p
              
                  processes = []
                  for partition in partitions:
                      p = start_process(consume_kafka_partition, (topic, group_id, partition))
                      processes.append(p)
              
                  for p in processes:
                      p.join()
              
                  print("所有进程已结束,指定分区消费完成")
              

                6.celery+redis

                Celery为异步任务队列,Redis作为消息代理和缓存,实现日志的并行处理与加速。

                • redis安装
                yum install redis -y
                • redis 配置文件修改 /etc/redis.conf
                bind 0.0.0.0   #监听本机任意ip
                • 启动服务
                systemctl start redis
                systemctl restart redis # 如果已经启动就restart重启
                • redis详解

                端口:6379

                redis:key-value 存储系统,是跨平台的非关系型数据库。

                redis支持的存储类型:
                String: 字符串
                Hash: 散列
                List: 列表
                Set: 集合
                Sorted Set: 有序集合

                不同的数据类型对应不同的指令

                可以做消息中间件,可以做消息队列,可以做缓存  -- memcache

                redis持久化:
                RDB 持久化是通过对 Redis 中的数据进行快照(snapshot)来实现的。在指定的时间间隔内,Redis 会将内存中的数据集快照写入磁盘上的一个临时文件,成功后再将这个临时文件替换为之前的 RDB 文件。
                AOF 持久化是以日志的形式记录 Redis 服务器所执行的每一个写操作(如 SET、LPUSH 等命令)。这些写操作命令会按照执行的先后顺序追加到 AOF 文件的末尾。

                小示例:

                [root@kafka1 ~]# redis-cli
                字符串类型的存储:
                127.0.0.1:6379> set www "hello world"		键值对的方式存储
                OK
                127.0.0.1:6379> get www
                "hello world"
                127.0.0.1:6379> key *
                (error) ERR unknown command 'key'
                127.0.0.1:6379> keys *
                1) "www"
                127.0.0.1:6379> set www1 "xxx"
                OK
                127.0.0.1:6379> keys www*
                1) "www1"
                2) "www"
                哈希类型:
                127.0.0.1:6379> hmset root name "root" age 18
                OK
                127.0.0.1:6379> hgetall root
                1) "name"
                2) "root"
                3) "age"
                4) "18"
                127.0.0.1:6379> hget root name
                "root"
                • python库安装
                pip3 install celery -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple
                pip3 install redis
                • celery配置
                cd /opt
                mkdir monitor/celery_app -p

                在celery_app中
                编辑配置文件  config.py

                from celery.schedules import crontab
                
                BROKER_URL = 'redis://192.168.10.146:6379/0'  # Broker配置,使用Redis作为消息中间件
                CELERY_RESULT_BACKEND = 'redis://192.168.10.146:6379/1'  # BACKEND配置,这里使用redis
                CELERY_RESULT_SERIALIZER = 'json'  # 结果序列化方案
                CELERY_TASK_RESULT_EXPIRES = 60 * 60 * 24  # 任务过期时间
                CELERY_TIMEZONE = 'Asia/Shanghai'   # 时区配置
                CELERY_IMPORTS = (     # 指定导入的任务模块,可以指定多个
                    'celery_app.task',
                )
                
                # 添加阈值配置
                TRAFFIC_THRESHOLD = 1000
                
                CELERYBEAT_SCHEDULE = {
                    'celery_app.task.monitor_traffic': {
                        'task': 'celery_app.task.monitor_traffic',
                        'schedule': crontab(minute='*/1'),
                        'args': ()
                    }
                }

                编辑__init__.py  (双下划线开头,双下划线结尾)

                # 初始化模块,运行包之前会先运行__int__.py
                from celery import Celery
                
                app = Celery('task')
                app.config_from_object('celery_app.config')

                编辑task.py

                import sqlite3
                from . import app
                from .smtp_send import send_email
                from .config import TRAFFIC_THRESHOLD
                
                @app.task
                def monitor_traffic():
                    print("Monitoring traffic...")
                    # 连接数据库
                    conn = sqlite3.connect('traffic.db')
                    cursor = conn.cursor()
                    # 查询最近一分钟的流量总和
                    cursor.execute("SELECT SUM(traffic) FROM traffic_data WHERE timestamp >= datetime('now', '-1 minute')")
                    total_traffic = cursor.fetchone()[0]
                    conn.close()
                
                    if total_traffic is not None and total_traffic > TRAFFIC_THRESHOLD:
                        content = f"流量已超过阈值,当前流量值为: {total_traffic}"
                        send_email(content)
                        print(content)
                    else:
                        print("流量未超过阈值")

                编辑smtp-send.py

                # smtplib 发邮件   email 构建邮件内容
                import smtplib
                from email.mime.text import MIMEText
                from email.header import Header
                from email.utils import formataddr
                
                def send_email(content, sender=发送者邮箱, password=密码, receiver=接收者邮箱, subject='流量告警'):
                    # 邮件内容
                    mail_content = content
                    message = MIMEText(mail_content, 'plain', 'utf-8')
                    message['From'] = formataddr((str(Header('wcw', 'utf-8')), sender))
                    message['To'] = Header("lf", 'utf-8')
                    message['Subject'] = Header(subject, 'utf-8')
                
                    try:
                        # 使用SSL加密连接(以QQ邮箱为例)
                        smtpObj = smtplib.SMTP_SSL("smtp.qq.com", 465)
                        smtpObj.login(sender, password)
                        smtpObj.sendmail(sender, receiver, message.as_string())
                        print("邮件发送成功")
                    except smtplib.SMTPException as e:
                        print("邮件发送失败:", e)
                • celery 启动beat (在monitor目录下执行)
                celery -A celery_app beat
                • celery 启动worker
                celery -A celery_app worker -l info -c 4

                评论
                添加红包

                请填写红包祝福语或标题

                红包个数最小为10个

                红包金额最低5元

                当前余额3.43前往充值 >
                需支付:10.00
                成就一亿技术人!
                领取后你会自动成为博主和红包主的粉丝 规则
                hope_wisdom
                发出的红包
                实付
                使用余额支付
                点击重新获取
                扫码支付
                钱包余额 0

                抵扣说明:

                1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
                2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

                余额充值