zookeeper+kafka

93 阅读10分钟

zookeeper

什么是zookeeper

zookeeper是一个开源的分布式存储服务,给分布式框架服务提供协调服务的Apache项目

zookeeper特点

  1. Zookeeper:一个领导者(Leader),多个跟随者(Follower)组成的集群。
  2. Zookeepe集群中只要有半数以上节点存活,Zookeeper集群就能正常服务。所以Zookeeper适合安装奇数台服务器。
  3. 全局数据一致:每个Server保存一份相同的数据副本,Client无论连接到哪个Server,数据都是一致的。
  4. 更新请求顺序执行,来自同一个Client的更新请求按其发送顺序依次执行,即先进先出。
  5. 数据更新原子性,一次数据更新要么成功,要么失败。
  6. 实时性,在一定时间范围内,Client能读到最新数据。

zookeeper工作原理

  • Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步以后,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。
  • 为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。所有的提议(proposal)都在被提出的时候加上了zxid。实现中zxid是一个64位的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的统治时期。第32位用于递增计数。

zookeeper提供的服务

  • 统一命名服务
    • 分布式环境中,使用统一的文字命名,方便识别。
  • 统一配置管理
    • 配置文件同步
    • 配置文件管理有zookeeper实现
  • 统一群集管理
    • 统一管理集群,方便掌握每个节点的的状态
    • 可以实现实时监控节点的状态变化
  • 服务器动态上下线
    • 客户端实时观察服务器上下线变化
  • 软负载均衡
    • 记录每台服务器访问数,被访问数最少的去处理最新的客户端请求

选举机制

第一次选举

  • 服务器1启动,给自己投票,然后发投票信息,由于其它机器还没有启动所以它收不到反馈信息,服务器1的状态一直属于Looking(选举状态)。
  • 服务器2启动,给自己投票,同时与之前启动的服务器1交换结果,由于服务器2的编号大所以服务器2胜出,但此时投票数没有大于半数,所以两个服务器的状态依然是LOOKING。
  • 服务器3启动,给自己投票,同时与之前启动的服务器1,2交换信息,由于服务器3的编号最大所以服务器3胜出,此时投票数正好大于半数,所以服务器3成为领导者,服务器1,2成为小弟。
  • 服务器4启动,给自己投票,同时与之前启动的服务器1,2,3交换信息,尽管服务器4的编号大,但之前服务器3已经胜出,所以服务器4只能成为小弟。
  • 服务器5启动,后面的逻辑同服务器4成为小弟。

非第一次启动选举机制

  1. 当ZooKeeper 集群中的一台服务器出现以下两种情况之一时,就会开始进入Leader选举:
    1. 服务器初始化启动。
    2. 服务器运行期间无法和Leader保持连接。
  2. 而当一台机器进入Leader选举流程时,当前集群也可能会处于以下两种状态:
    1. 集群中本来就已经存在一个Leader。
    2. 对于已经存在Leader的情况,机器试图去选举Leader时,会被告知当前服务器的Leader信息,对于该机器来说,仅仅需要和 Leader机器建立连接,并进行状态同步即可。

zookeeper工作原理

524427577562acebcfe9280a6ec1127.png 首先client向Follwer发出一个写的请求;Follwer会把请求发送给Leader;Leader接收到以后开始发起投票并通知Follwer进行投票;Follwer把投票结果发送给Leader;Leader将结果汇总后如果需要写入,则开始写入同时把写入操作通知给Leader,然后commit;Follwer把请求结果返回给client。

选举leader规则

  1. EPOCH大的直接胜出
  2. EPOCH相同,事务id大的胜出
  3. 事务id相同,服务器id大的胜出

部署zookeeper集群

环境

  • 192.168.42.11
  • 192.168.42.12
  • 192.168.42.13
systemctl stop firewalld
systemctl disable firewalld
setenforce 0

所有节点都安装

安装jdk

root@localhost ~]# yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-devel
[root@localhost ~]# java -version

image.png

image.png

安装zookeeper

将zookeeper安装包下载到opt目录下
[root@localhost opt]# tar -zvxf apache-zookeeper-3.5.7-bin.tar.gz
[root@localhost opt]# mv apache-zookeeper-3.5.7-bin /usr/local/zookeeper-3.5.7

image.png

image.png

修改配置文件

[root@localhost opt]# cd /usr/local/zookeeper-3.5.7/conf/
[root@localhost conf]# cp zoo_sample.cfg zoo_sample.cfg.bak

[root@localhost conf]# vim zoo_sample.cfg
#添加和修改一下内容
dataDir=/usr/local/zookeeper-3.5.7/data
dataLogDir=/usr/local/zookeeper-3.5.7/logs
server.1=192.168.42.11:3188:3288
server.2=192.168.42.12:3188:3288
server.3=192.168.42.13:3188:3288

解释:
tickTime=2000   
#通信心跳时间,Zookeeper服务器与客户端心跳时间,单位毫秒
initLimit=10    
#Leader和Follower初始连接时能容忍的最多心跳数(tickTime的数量),这里表示为10*2s
syncLimit=5     
#Leader和Follower之间同步通信的超时时间,这里表示如果超过5*2s,Leader认为Follwer死掉,并从服务器列表中删除Follwer
dataDir=/usr/local/zookeeper-3.5.7/data      
#修改,指定保存Zookeeper中的数据的目录,目录需要单独创建
dataLogDir=/usr/local/zookeeper-3.5.7/logs   
#添加,指定存放日志的目录,目录需要单独创建
clientPort=2181   
#客户端连接端口

其他两个机子按照上述下载解压
将配置文件远程拷贝一份给其他两个机子
[root@localhost conf]# scp /usr/local/zookeeper-3.5.7/conf/zoo_sample.cfg 192.168.42.12:/usr/local/zookeeper-3.5.7/conf/
[root@localhost conf]# scp /usr/local/zookeeper-3.5.7/conf/zoo_sample.cfg 192.168.42.13:/usr/local/zookeeper-3.5.7/conf/

image.png

image.png

创建数据目录和日志目录

[root@localhost conf]# mkdir /usr/local/zookeeper-3.5.7/data
#数据目录
[root@localhost conf]# mkdir /usr/local/zookeeper-3.5.7/logs
#日志目录

image.png

在每个节点的dataDir指定的目录下创建一个 myid 的文件

[root@localhost conf]# echo 1 > /usr/local/zookeeper-3.5.7/data/myid
#这个是1机子的
#二号和3号机子就可以将echo的序号改一下
echo 2 > /usr/local/zookeeper-3.5.7/data/myid
echo 3 > /usr/local/zookeeper-3.5.7/data/myid

image.png

配置zookeeper启动脚本

[root@localhost conf]# vim /etc/init.d/zookeeper
#加入一下内容
#!/bin/bash
#chkconfig:2345 20 90
#description:Zookeeper Service Control Script
ZK_HOME='/usr/local/zookeeper-3.5.7'
case $1 in
start)
        echo "---------- zookeeper 启动 ------------"
        $ZK_HOME/bin/zkServer.sh start
;;
stop)
        echo "---------- zookeeper 停止 ------------"
        $ZK_HOME/bin/zkServer.sh stop
;;
restart)
        echo "---------- zookeeper 重启 ------------"
        $ZK_HOME/bin/zkServer.sh restart
;;
status)
        echo "---------- zookeeper 状态 ------------"
        $ZK_HOME/bin/zkServer.sh status
;;
*)
    echo "Usage: $0 {start|stop|restart|status}"
esac

image.png

image.png

设置开机自启,并且启动

[root@localhost conf]# chmod +x /etc/init.d/zookeeper
[root@localhost conf]# chkconfig --add zookeeper
[root@localhost conf]# service zookeeper start
[root@localhost conf]# service zookeeper status

image.png

image.png

image.png

image.png image.png

kafka

什么是kafka

  • kafka是一个分布式的基于发布/订阅模式的消息队列,主要应用于大数据实时处理领域。
  • Kafka是一个分布式消息队列。Kafka对消息保存时根据Topic进行归类,发送消息者称为Producer,消息接受者称为Consumer,此外kafka集群有多个kafka实例组成,每个实例(server)称为broker。

为什么需要消息队列

  • 主要原因是由于在高并发环境下,同步请求来不及处理,请求往往会发生阻塞。比如大量的请求并发访问数据库,导致行锁表锁,最后请求线程会堆积过多,从而触发 too many connection 错误,引发雪崩效应。
  • 我们使用消息队列,通过异步处理请求,从而缓解系统的压力。消息队列常应用于异步处理,流量削峰,应用解耦,消息通讯等场景。

使用消息队列的好处

  • 解耦
  • 可恢复性
  • 缓冲
  • 灵活性 & 峰值处理能力
  • 异步通信

消息队列的两种模式

  • 点对点模式(一对一,消费者主动拉取数据,消息收到后消息清除)
  • 发布/订阅模式(一对多,又叫观察者模式,消费者消费数据之后不会清除消息)

kafka的特性

  • 高吞吐量、低延迟
  • 可扩展性
  • 持久性、可靠性
  • 容错性
  • 高并发

kafka系统架构

  • Broker
  • Topic
  • Partition
  • Replica
  • Leader
  • Follower
  • producer
  • Consumer
  • Consumer Group(CG)
  • offset 偏移量
  • Zookeeper

部署kafka集群

使用上面的机器,也是每台机器都安装

安装kafka,并修改配置文件

将kafka安装包下载到opt目录
[root@server1 opt]# tar zvxf kafka_2.13-2.7.1.tgz
#解压
[root@server1 opt]# mv kafka_2.13-2.7.1 /usr/local/kafka
#将系统可以识别kafka命令

[root@server1 opt]# cd /usr/local/kafka/config/
[root@server1 config]# cp server.properties{,.bak}
[root@server1 config]# vim server.properties
··············
21 broker.id=0 #broker是全局唯一的编号,每个节点不能重复
31 listeners=PLAINTEXT://192.168.42.17:9092 #指定监听的ip端口,也可以保持默认不修改,但是这边修改一下
42 num.network.threads=3 #broker处理网络请求的线程数量,一般不需要修改
60 log.dirs=/usr/local/kafka/logs
#kafka运行日志存放路径,也是数据的存放路径
123 zookeeper.connect=192.168.42.11:2181,192.168.42.12:2181,192.168.42.13:2181
#配置连接Zookeeper集群地址

image.png

image.png

image.png

image.png

image.png

修改环境变量

[root@server1 ~]# vim /etc/profile
#添加以下内容
···············
export KAFKA_HOME=/usr/local/kafka
export PATH=$PATH:$KAFKA_HOME/bin

[root@server1 ~]# source /etc/profile
#刷新脚本

image.png

image.png

image.png

编辑kafka启动脚本

[root@server1 ~]# vim /etc/init.d/kafka
#添加以下内容
#!/bin/bash
#chkconfig:2345 22 88
#description:Kafka Service Control Script
KAFKA_HOME='/usr/local/kafka'
case $1 in
start)
        echo "---------- Kafka 启动 ------------"
        ${KAFKA_HOME}/bin/kafka-server-start.sh -daemon ${KAFKA_HOME}/config/server.properties
;;
stop)
        echo "---------- Kafka 停止 ------------"
        ${KAFKA_HOME}/bin/kafka-server-stop.sh
;;
restart)
        $0 stop
        $0 start
;;
status)
        echo "---------- Kafka 状态 ------------"
        count=$(ps -ef | grep kafka | egrep -cv "grep|$$")
        if [ "$count" -eq 0 ];then
        echo "kafka is not running"
    else
        echo "kafka is running"
    fi
;;
*)
    echo "Usage: $0 {start|stop|restart|status}"
esac

[root@server1 init.d]# chmod +x /etc/init.d/kafka
[root@server1 init.d]# chkconfig --add kafka
[root@server1 init.d]# service kafka start
#给出权限并且开启服务
[root@server1 init.d]# service kafka status
#查看状态

image.png

image.png

image.png

kafka命令操作


[root@server1 init.d]# kafka-topics.sh --create --zookeeper 192.168.42.11:2181,192.168.42.12:2181,192.168.42.13:2181 --replication-factor 1 --partitions 3 --topic test
#创建topic
[root@server1 init.d]# kafka-topics.sh --list --zookeeper 192.168.42.11:2181,192.168.42.12:2181,192.168.42.13:2181
#查看当前服务器中的所有 topic
[root@server1 init.d]# kafka-topics.sh --describe --zookeeper 192.168.42.11:2181,192.168.42.12:2181,192.168.42.13:2181
#查看某个 topic 的详情
[root@server1 init.d]# kafka-console-producer.sh --broker-list 192.168.42.11:9092,192.168.42.12:9092,192.168.42.13:9092 --topic test
#发布消息
[root@server1 init.d]# kafka-console-consumer.sh --bootstrap-server 192.168.42.11:9092,192.168.42.12:9092,192.168.42.13:9092 --topic test --from-beginning
#消费消息(相当于查看消息)

image.png

kafka工作流程

  1. Kafka 中消息是以 topic 进行分类的,生产者生产消息,消费者消费消息,都是面向 topic 的。
  2. topic 是逻辑上的概念,而 partition 是物理上的概念,每个 partition 对应于一个 log 文件,该 log 文件中存储的就是 producer 生产的数据。Producer 生产的数据会被不断追加到该 log 文件末端,且每条数据都有自己的 offset。 消费者组中的每个消费者,都会实时记录自己消费到了哪个 offset,以便出错恢复时,从上次的位置继续消费。
  3. 由于生产者生产的消息会不断追加到 log 文件末尾,为防止 log 文件过大导致数据定位效率低下,Kafka 采取了分片和索引机制,将每个 partition 分为多个 segment。每个 segment 对应两个文件:“.index” 文件和 “.log” 文件。这些文件位于一个文件夹下,该文件夹的命名规则为:topic名称+分区序号。例如,test 这个 topic 有三个分区, 则其对应的文件夹为 test-0、test-1、test-2。
  4. index 和 log 文件以当前 segment 的第一条消息的 offset 命名。
  5. “.index” 文件存储大量的索引信息,“.log” 文件存储大量的数据,索引文件中的元数据指向对应数据文件中 message 的物理偏移地址。

部署Filebeat+Kafka+ELK

部署 Filebeat

cd /usr/local/filebeat

vim filebeat.yml
filebeat.prospectors:
- type: log
  enabled: true
  paths:
    - /var/log/httpd/access_log
  tags: ["access"]
  
- type: log
  enabled: true
  paths:
    - /var/log/httpd/error_log
  tags: ["error"]
  
  #添加输出到 Kafka 的配置
output.kafka:
  enabled: true
  hosts: ["192.168.42.11:9092","192.168.42.12:9092","192.168.42.13:9092"]    #指定 Kafka 集群配置
  topic: "httpd"    #指定 Kafka 的 topic
  
#启动filebeat
./filebeat -e -c filebeat.yml

部署 ELK,在 Logstash 组件所在节点上新建一个 Logstash 配置文件

cd /etc/logstash/conf.d/

vim kafka.conf
input {
    kafka {
        bootstrap_servers => "192.168.42.11:9092,192.168.42.12:9092,192.168.42.13:9092"  #kafka集群地址
        topics  => "httpd"     #拉取的kafka的指定topic
        type => "httpd_kafka"  #指定 type 字段
        codec => "json"        #解析json格式的日志数据
		auto_offset_reset => "latest"  #拉取最近数据,earliest为从头开始拉取
		decorate_events => true   #传递给elasticsearch的数据额外增加kafka的属性数据
    }
}

output {
  if "access" in [tags] {
    elasticsearch {
      hosts => ["192.168.42.16:9200"]
      index => "httpd_access-%{+YYYY.MM.dd}"
    }
  }
  
  if "error" in [tags] {
    elasticsearch {
      hosts => ["192.168.42.16:9200"]
      index => "httpd_error-%{+YYYY.MM.dd}"
    }
  }
  
  stdout { codec => rubydebug }
}

#启动 logstash
logstash -f kafka.conf

验证

浏览器访问 http://192.168.42.16:5601 登录 Kibana,单击“Create Index Pattern”按钮添加索引“filebeat_test-*”,单击 “create” 按钮创建,单击 “Discover” 按钮可查看图表信息及日志信息。