zookeeper
什么是zookeeper
zookeeper是一个开源的分布式存储服务,给分布式框架服务提供协调服务的Apache项目
zookeeper特点
- Zookeeper:一个领导者(Leader),多个跟随者(Follower)组成的集群。
- Zookeepe集群中只要有半数以上节点存活,Zookeeper集群就能正常服务。所以Zookeeper适合安装奇数台服务器。
- 全局数据一致:每个Server保存一份相同的数据副本,Client无论连接到哪个Server,数据都是一致的。
- 更新请求顺序执行,来自同一个Client的更新请求按其发送顺序依次执行,即先进先出。
- 数据更新原子性,一次数据更新要么成功,要么失败。
- 实时性,在一定时间范围内,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成为小弟。
非第一次启动选举机制
- 当ZooKeeper 集群中的一台服务器出现以下两种情况之一时,就会开始进入Leader选举:
- 服务器初始化启动。
- 服务器运行期间无法和Leader保持连接。
- 而当一台机器进入Leader选举流程时,当前集群也可能会处于以下两种状态:
- 集群中本来就已经存在一个Leader。
- 对于已经存在Leader的情况,机器试图去选举Leader时,会被告知当前服务器的Leader信息,对于该机器来说,仅仅需要和 Leader机器建立连接,并进行状态同步即可。
zookeeper工作原理
首先client向Follwer发出一个写的请求;Follwer会把请求发送给Leader;Leader接收到以后开始发起投票并通知Follwer进行投票;Follwer把投票结果发送给Leader;Leader将结果汇总后如果需要写入,则开始写入同时把写入操作通知给Leader,然后commit;Follwer把请求结果返回给client。
选举leader规则
- EPOCH大的直接胜出
- EPOCH相同,事务id大的胜出
- 事务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
安装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
修改配置文件
[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/
创建数据目录和日志目录
[root@localhost conf]# mkdir /usr/local/zookeeper-3.5.7/data
#数据目录
[root@localhost conf]# mkdir /usr/local/zookeeper-3.5.7/logs
#日志目录
在每个节点的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
配置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
设置开机自启,并且启动
[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
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集群地址
修改环境变量
[root@server1 ~]# vim /etc/profile
#添加以下内容
···············
export KAFKA_HOME=/usr/local/kafka
export PATH=$PATH:$KAFKA_HOME/bin
[root@server1 ~]# source /etc/profile
#刷新脚本
编辑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
#查看状态
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
#消费消息(相当于查看消息)
kafka工作流程
- Kafka 中消息是以 topic 进行分类的,生产者生产消息,消费者消费消息,都是面向 topic 的。
- topic 是逻辑上的概念,而 partition 是物理上的概念,每个 partition 对应于一个 log 文件,该 log 文件中存储的就是 producer 生产的数据。Producer 生产的数据会被不断追加到该 log 文件末端,且每条数据都有自己的 offset。 消费者组中的每个消费者,都会实时记录自己消费到了哪个 offset,以便出错恢复时,从上次的位置继续消费。
- 由于生产者生产的消息会不断追加到 log 文件末尾,为防止 log 文件过大导致数据定位效率低下,Kafka 采取了分片和索引机制,将每个 partition 分为多个 segment。每个 segment 对应两个文件:“.index” 文件和 “.log” 文件。这些文件位于一个文件夹下,该文件夹的命名规则为:topic名称+分区序号。例如,test 这个 topic 有三个分区, 则其对应的文件夹为 test-0、test-1、test-2。
- index 和 log 文件以当前 segment 的第一条消息的 offset 命名。
- “.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” 按钮可查看图表信息及日志信息。