基于kafka,zookeeper日志收集平台搭建

项目环境

在这里插入图片描述

centos7.9(6台1核2G),zookeeper(3.6.3),kafka(2.12),filebeat,nginx(2.20)

hostnameip
web-nginx01192.168.222.125
web-nginx02192.168.222.126
web-nginx03192.168.222.127
nginx-kafka01192.168.222.134
nginx-kafka02192.168.222.135
nginx-kafka03192.168.222.136
zookeeper01192.168.222.134
zookeeper02192.168.222.135
zookeeper03192.168.222.136
项目描述

该项目主要从数据产生,收集,缓存,清洗,入库五部分组成,利用filebeat收集前端web服务器产生的日志,使用zookeeper来管理kafka,使收集的数据集中缓存到kafka中,最后数据清洗,提取重要字段写入数据库中

项目步骤
  • 1. 规划整个项目的拓扑结构
  • 2. 搭建nginx集群作为web服务
  • 3.搭建kafka集群实现日志统一管理
  • 4. 搭建zooke集群管理kafka
  • 5.搭建filebeat,调试生产者,和消费者
  • 6.编写消费者,清洗nginx日志,收集带宽信息存入数据库
  • 7. 基于流量进行告警监控
项目搭建

前提首先关闭服务器的firewalld和selinux

[root@nginx-kafka01 ~]# systemctl stop firewalld
[root@nginx-kafka01 ~]# systemctl disable firewalld
==============
# 关闭selinux
vim /etc/selinux/config
SELINUX=disabled
# 关闭selinux 需要重启服务器
# getenforce 查看是否生效
[root@nginx-kafka01 ~]# getenforce
Disabled
nginx搭建(3台centos7服务器)

1. 安装nginx

# 安装好epel源
yum install epel-release -y
yum install nginx -y
# 启动
systemctl start nginx 
# 设置开机自启
systemctl enable nginx

2. 修改nginx配置文件

[root@nginx-kafka01 opt]# vim /etc/nginx/nginx.conf
将 
   listen       80 default_server;
修改成:
   listen       80[root@nginx-kafka01 opt]# vim  /etc/nginx/conf.d/sc.conf
server {
    listen 80 default_server;
    server_name  www.sc.com;

    root         /usr/share/nginx/html;

    access_log  /var/log/nginx/sc/access.log main;

    location  / {

    }
}

nginx.conf配置文件,主要由全局块,events块,http块构成。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XeDBQbi9-1661781401038)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20220822204847961.png)]

#语法检测
[root@nginx-kafka01 html]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: [emerg] open() "/var/log/nginx/sc/access.log" failed (2: No such file or directory)
nginx: configuration file /etc/nginx/nginx.conf test failed
[root@nginx-kafka01 html]# mkdir /var/log/nginx/sc
[root@nginx-kafka01 html]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

#重新加载nginx
nginx -s  reload
kafka,zk集群搭建(3台centos7服务器)
1. 安装
安装java:yum install java wget  -y
安装kafka: wget   https://mirrors.bfsu.edu.cn/apache/kafka/2.8.1/kafka_2.12-2.8.1.tgz
解包: tar  xf  kafka_2.12-2.8.1.tgz
安装zookeeper:wget   https://mirrors.bfsu.edu.cn/apache/zookeeper/zookeeper-3.6.3/apache-zookeeper-3.6.3-bin.tar.gz
2. 配置kafka
[root@nginx-kafka01 kafka_2.12-2.8.1]# vim config/server.properties
############################# Server Basics #############################

# The id of the broker. This must be set to a unique integer for each broker.
broker.id=1 
############################# Socket Server Settings #############################

# The address the socket server listens on. It will get the value returned from 
# java.net.InetAddress.getCanonicalHostName() if not configured.
#   FORMAT:
#     listeners = listener_name://host_name:port
#   EXAMPLE:
#     listeners = PLAINTEXT://your.host.name:9092
#listeners=PLAINTEXT://:9092
listeners=PLAINTEXT://nginx-kafka01:9092
############################# Zookeeper #############################

# Zookeeper connection string (see zookeeper docs for details).
# This is a comma separated host:port pairs, each corresponding to a zk
# server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002".
# You can also append an optional chroot string to the urls to specify the
# root directory for all kafka znodes.
zookeeper.connect=192.168.222.134:2181,192.168.222.135:2181,192.168.222.136:2181

3. 配置zk
# 进入/opt/apache-zookeeper-3.6.3-bin/conf
[root@nginx-kafka01 conf]# cp zoo_sample.cfg  zoo.cfg
# 修改zoo.cfg, t添加如下三行:
[root@nginx-kafka01 conf]# vim zoo.cfg
# 3888和4888都是端口  一个用于数据传输,一个用于检验存活性和选举
server.1=192.168.222.134:3888:4888
server.2=192.168.222.135:3888:4888
server.3=192.168.222.136:3888:4888

创建/tmp/zookeeper目录 ,在目录中添加myid文件,文件内容就是本机指定的zookeeper id内容
如:在192.168.222.134机器上
echo 1 > /tmp/zookeeper/myid

启动zookeeper:
bin/zkServer.sh start

开启zk和kafka的时候,一定是先启动zk,再启动kafka
关闭服务的时候,kafka先关闭,再关闭zk

查看
[root@nginx-kafka03 apache-zookeeper-3.6.3-bin]# bin/zkServer.sh status
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /opt/apache-zookeeper-3.6.3-bin/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost. Client SSL: false.
Mode: leader
启动kafka
bin/kafka-server-start.sh -daemon config/server.properties
测试
# 创建topic
bin/kafka-topics.sh --create --zookeeper 192.168.0.95:2181 --replication-factor 1 --partitions 1 --topic sc
# 查看topic
 bin/kafka-topics.sh --list --zookeeper 192.168.0.95:2181
# 创建生产者
[root@localhost kafka_2.12-2.8.0]# bin/kafka-console-producer.sh --broker-list 192.168.0.94:9092 --topic sc
>hello
>sanchuang tongle
>nihao
>world !!!!!!1
>
# 创建消费者
[root@localhost kafka_2.12-2.8.0]# bin/kafka-console-consumer.sh --bootstrap-server 192.168.0.96:9092 --topic sc --from-beginning

bin/kafka-console-consumer.sh --bootstrap-server 192.168.222.134:9092 --topic nginxlog --from-beginning

连接zk
[zk: localhost:2181(CONNECTED) 0] ls /
[admin, brokers, cluster, config, consumers, controller, controller_epoch, feature, isr_change_notification, latest_producer_id_block, log_dir_event_notification, zookeeper]
[zk: localhost:2181(CONNECTED) 1] ls /brokers
[ids, seqid, topics]
[zk: localhost:2181(CONNECTED) 2] ls /brokers/ids
[0, 1, 2]
[zk: localhost:2181(CONNECTED) 3] get /brokers/ids
null
[zk: localhost:2181(CONNECTED) 4] get /brokers/ids/0
{"listener_security_protocol_map":{"PLAINTEXT":"PLAINTEXT"},"endpoints":["PLAINTEXT://nginx-kafka02:9092"],"jmx_port":9999,"features":{},"host":"nginx-kafka02","timestamp":"1642300427923","port":9092,"version":5}
[zk: localhost:2181(CONNECTED) 5] ls /brokers/ids/0
[]
[zk: localhost:2181(CONNECTED) 6] get /brokers/ids/0
{"listener_security_protocol_map":{"PLAINTEXT":"PLAINTEXT"},"endpoints":["PLAINTEXT://nginx-kafka02:9092"],"jmx_port":9999,"features":{},"host":"nginx-kafka02","timestamp":"1642300427923","port":9092,"version":5}

filebeat部署
1. 安装
rpm --import https://packages.elastic.co/GPG-KEY-elasticsearch
2. 编译/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. 设置开机自启
systemctl enable filebeat
4. 配置
# 修改配置文件/etc/filebeat/filebeat.yml
[root@nginx-kafka01 conf]# vim /etc/filebeat/filebeat.yml

filebeat.inputs:
- type: log
  enabled: true
  paths:
   - /var/log/nginx/sc/access.log

#--------------------kafka-------------------------
output.kafka:
   hosts: ["192.168.222.134:9092","192.168.222.135:9092","192.168.222.136:9092"]
   topic: nginxlog
   keep_alive: 10s

创建主题nginxlog
bin/kaa-topics.sh --create --zookeeper 192.168.77.132:2181 --replication-factor 3 --partitions 1 --topic nginxlog
启动filebeat服务
systemctl start  filebeat

[root@nginx-kafka01 opt]# ps -ef |grep filebeat
root        5537       1  0 15:32 ?        00:00:08 /usr/share/filebeat/bin/filebeat --environment systemd -c /etc/filebeat/filebeat.yml --path.home /usr/share/filebeat --path.config /etc/filebeat --path.data /var/lib/filebeat --path.logs /var/log/filebeat
filebeat数据文件
[root@nginx-kafka01 conf]# cd /var/lib/filebeat/registry/filebeat/
[root@nginx-kafka01 filebeat]# ls
log.json  meta.json
[root@nginx-kafka01 filebeat]# less log.json 

数据入库
1、需求分析
   需要nginx日志的ip,时间,带宽字段  
   将ip字段解析成相应的省份、运营商
   存入数据库的字段:  id, 时间, 省份, 运营商, 带宽

#步骤
1、创建数据表
2、编写python脚本, 从kafka获取nginx日志
3、获取好的nginx日志,提取出ip,时间,带宽字段
4、提取出的ip字段通过淘宝的一个接口解析出省份和运营商
url = "https://ip.taobao.com/outGetIpInfo?accessKey=alibaba-inc&ip=114.114.114.114"
5、格式化时间字段  "2021-10-12 12:00:00"
6、存入数据库
#创建表
create table nginxlog (
id  int primary key auto_increment,
dt  datetime not null,
prov int ,
isp  int,
bd  float
) CHARSET=utf8;

create table prov_index(
id  int primary key auto_increment,
prov_name  varchar(256)
) charset=utf8;

create table isp_index(
id int primary key auto_increment,
isp_name varchar(256)
) charset=utf8;

消费者脚本
import json
import requests
import time

taobao_url = "https://ip.taobao.com/outGetIpInfo?accessKey=alibaba-inc&ip="
#查询ip地址的信息(省份和运营商isp),通过taobao网的接口
def resolv_ip(ip):
    response = requests.get(taobao_url+ip)
    if response.status_code == 200:
       tmp_dict = json.loads(response.text)
       prov = tmp_dict["data"]["region"]
       isp = tmp_dict["data"]["isp"]
       return prov,isp
    return None,None

#将日志里读取的格式转换为我们指定的格式
def trans_time(dt):
     #把字符串转成时间格式
    timeArray = time.strptime(dt, "%d/%b/%Y:%H:%M:%S")
    #timeStamp = int(time.mktime(timeArray))
    #把时间格式转成字符串
    new_time = time.strftime("%Y-%m-%d %H:%M:%S", timeArray)    
    return new_time

#从kafka里获取数据,清洗为我们需要的ip,时间,带宽
from pykafka import KafkaClient
client = KafkaClient(hosts="192.168.222.134:9092,192.168.222.135:9092,192.168.222.136:9092")
topic = client.topics['nginxlog'] 
balanced_consumer = topic.get_balanced_consumer(
  consumer_group='testgroup',
  auto_commit_enable=True,
  managed=True
  # zookeeper_connect='nginx-kafka01:2181,nginx-kafka02:2181,nginx-kafka03:2181'
) 
#consumer = topic.get_simple_consumer() 
for message in balanced_consumer:
   if message is not None: 
       line = json.loads(message.value.decode("utf-8"))
       log = line["message"]
       tmp_lst = log.split()
       ip = tmp_lst[0]
       dt = tmp_lst[3].replace("[","")
       bt = tmp_lst[9]
       dt = trans_time(dt)
       prov, isp = resolv_ip(ip)
       if prov and isp:
          print(prov, isp,dt)

在这里插入图片描述

kafka的原理

生产者生产的消息会不断追加到 .log文件的末尾,为防止log文件过大导致数据定位效率低下, kafka采用 分片索引的机制,将每个partition分为多个 segment ,每个segment对应 2个文件, index文件和log文件

[root@nginx-kafka01 data]# cd nginxlog-0/
[root@nginx-kafka01 nginxlog-0]# ls
00000000000000000000.index  00000000000000000000.log  00000000000000000000.timeindex  00000000000000000209.snapshot  leader-epoch-checkpoint  partition.metadata
[root@nginx-kafka01 nginxlog-0]# pwd 
/data/nginxlog-0
[root@nginx-kafka01 nginxlog-0]# 

index 和 log 的文件的文件名是当前这个索引是最小的数据的offset

kafka的生产者和消费者
kafka的生产者
kafka的partition的分区的作用

kafka的topic分区的原因主要就是提供并发,提高性能,因为读写是以partition为单位读写的

生产者发送消息是发送到哪个partition中呢?

A . 在客户机中指定partition

B . 轮询 消息1去p1 , 消息2 去 p2 , 消息3 去 p3 , 消息4 去p1, 消息5 去 p2, 消息6 去 p3

kafka如何保证数据可靠性呢? 通过ack来保证 ----》 消息确认机制

保证生产者发送的数据,能可靠的发送到指定的topic, topic 的每个partition收到生产者发送的数据后, 都需要向生产者发送 ack (确认收到),如果生产者收到 ack ,就会进行下一轮的发送, 否则重新发送数据。

那么kafka什么时候向生产者发送ack

确保follower和leader同步完成,leader在发送ack给生产者,这样才能确保leader挂掉之后,能再follower中选举出新的leader后,数据不会丢失

那么多少个follower同步完成后发送ack

方案1: 半数已经完成同步, 就发送ack

方案2 :全部完成同步,才发送ack(kafka采用这种方式)

kafka如何保证消费数据的一致性? 通过 HW机制 来保证

在这里插入图片描述

LEO :指每个follower的最大的offset

HW (高水位):消费者能看到的最大的offset,LSR队列中最小的LEO,也就是说消费者只能看到 1~ 6的数据,后面的数据看不到,也消费不了

避免leader挂掉后,比如当前消费者消费8这个数据后,leader挂 了, 此时比如 f2成为 leader, f2 根本就没有 9 这条数据,那么消费者就会报错,所以设计了 HW 这个参数, 只暴露最少的数据给消费者,避免上面的问题

HW 保证数据存储的一致性

A . Follower 故障

Follower发生故障后会被临时踢出LSR,待该follower恢复后,follower会读取本地的磁盘记录的上次的HW,并将该log文件高于HW的部分截取掉,从HW开始向leader进行同步,等该follower的LEO大于等于该Partition的hw,即follower追上leader后,就可以重新加入LSR

B . Leader 故障

Leader发生故障后,会从ISR中选出一个新的leader, 之后, 为了保证多个副本之间的数据一致性,其余的follower会先将各自的log文件高于HW的部分截掉(新leader自己不会截掉),然后从新的leader同步数据。

注意:这个是为了保证多个副本间的数据存储的一致性,并不能保证数据不丢失或者不重复

精准一次(幂等性),保证数据不重复

Ack设置为 -1,则可以保证数据不丢失,但是会出现数据重复(at least once)

Ack设置为0,则可以保证数据不重复,但是不能保证数据不丢失(at most once)

如何做到鱼和熊掌兼得呢? 引入了 Exactl one (精确一次)

如果启用幂等性,则ack默认就是 -1 ,kafka就从每个生产者分配一个pid,并为每条消息分配 seqnumber,如果pid, partition, seqnumber三者一样,则kafka认为是数据重复,就不会落盘保存;但是如果生产者挂掉后,也会出现有数据重复的现象;所以幂等性解决在单次会话的单个分区的数据重复,但是在分区间或者跨会话的数据重复 问题是无法解决的

zookeeper在kafka中的作用

kafka集群中有一个broker会被选举为controller,负责管理集群broker的上下线,所有的topic的分区 副本分配和leader选举等工作

broker的每个topic为什么要有多个的partition
  1. 消息的存储就不会受到单一服务器存储空间大小的限制
  2. 消息的处理也可在多个服务器上并行
  3. 可以保证高可用,每个分区都会有一定数量的副本(replica)。如果有服务器不可用,副本所在的服务器就会接替上来,保持应用的持续性。

在这里插入图片描述

leader与follower是相对于replica(副本)而言的

确定消息的读写是在哪个replica上完成。

但是,为了保证较高的处理效率,消息的读写都是固定的一个副本上完成。这个副本就是所谓的leader,而其他副本则是follower。follower则会定期的到leader上同步数据。

那么在这些replica中leader是如何选举出来的呢?

​ 假如某个分区所在的服务器出来问题, 不可用, kafka会从该分区的其他的副本中选择一个作为新的leader。之后所有的读写就会转移到这个新的leader上。现在的问题是应当选择哪个作为新的leader。显然,只有哪些根leader保持同步的follower才应该被选举为新的leader。

​ kafka会在Zookeeper上针对每个Topic维护一个称为ISR(in-sync replica, 已同步的副本)的集合,该集合中时一些分区的副本。只有当这些副本都跟leader中的副本同步了之后,kafka才会认为消息已提交,并反馈给消息的生产者。如果这个集合有增减,kafka会跟新zookeeper上的记录。

​ 如果某个分区的leader不可用,kafka就会从ISR集合中选择一个副本作为新的leader

显然通过ISR,kafka需要的冗余度较低,可以容忍的失败数比较高。假设某个topic有 f+1 个副本。kafka可以容忍 f 个服务器不可用。

为什么不采用少数服从多数的算法?

​ 选择leader时也是从超过半数的同步的副本中选择

这种算法需要较高的冗余度

譬如只允许一台机器失败,需要有三个副本;而如果只容忍两台机器失败,则需要五个副本

kafka如何保证高可用?

多个broker + 多个partition + 多个 replica

ISR (in-sync-replica) 集合列表 需要同步的follower集合

​ 比如说 5 个副本, 1个leader, 4个follower 都在ISR中

有一条消息来了, leader怎么知道要同步哪些副本呢?

​ 根据ISR来,如果一个follower挂了。那就从这个列表里删除

如果一个follower卡住了或者同步过慢, 它也会从ISR里删除

eeper上的记录。

​ 如果某个分区的leader不可用,kafka就会从ISR集合中选择一个副本作为新的leader

显然通过ISR,kafka需要的冗余度较低,可以容忍的失败数比较高。假设某个topic有 f+1 个副本。kafka可以容忍 f 个服务器不可用。

为什么不采用少数服从多数的算法?

​ 选择leader时也是从超过半数的同步的副本中选择

这种算法需要较高的冗余度

譬如只允许一台机器失败,需要有三个副本;而如果只容忍两台机器失败,则需要五个副本

kafka如何保证高可用?

多个broker + 多个partition + 多个 replica

ISR (in-sync-replica) 集合列表 需要同步的follower集合

​ 比如说 5 个副本, 1个leader, 4个follower 都在ISR中

有一条消息来了, leader怎么知道要同步哪些副本呢?

​ 根据ISR来,如果一个follower挂了。那就从这个列表里删除

如果一个follower卡住了或者同步过慢, 它也会从ISR里删除

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值