简介
常用消息队列对比
1. kafka简介
需要java环境
kafka下载地址:
http://kafka.apache.org/downloads.html
kafka用于消息队列,解耦,和缓存redis没任何关系
主要用来处理大量数据状态下的消息队列,一般用来做日志的处理
Kafka 被称为下一代分布式消息系统
,是非营利性组织ASF(Apache Software Foundation,简称为ASF)基金会中的一个开源项目,比如HTTP Server、Hadoop、ActiveMQ、Tomcat等开源软件都属于Apache基金会的开源软件,类似的消息系统
还有RbbitMQ、ActiveMQ、ZeroMQ
,最主要的优势是其具备分布式功能
、并且结合zookeeper可以实现动态扩容
。
消息队列的好处
①解耦合
耦合的状态表示当你实现某个功能的时候,是直接接入当前接口
,
而利用消息队列,可以将相应的消息发送到消息队列
,这样的话,如果接口出了问题,将不会影响到当前的功能。
②异步处理
异步处理替代了之前的同步处理,异步处理不需要让流程走完就返回结果
,可以将消息发送到消息队列中,然后返回结果,剩下让其他业务处理接口从消息队列中拉取消费处理即可。
③流量削峰
高流量的时候,使用消息队列作为中间件可以将流量的高峰保存在消息队列中
,从而防止了系统的高请求,减轻服务器的请求处理压力
官方介绍
http://www.infoq.com/cn/articles/apache-kafka
Kafka消费模式
Kafka的消费模式主要有两种:
一对一
的消费,也即点对点的通信,即一个发送一个接收。
一对多
的消费,即一个消息发送到消息队列,消费者根据消息队列的订阅拉取消息消费。
①一对一
消息生产者发布消息到Queue队列中,通知消费者从队列中拉取消息进行消费。消息被消费之后则删除,Queue支持多个消费者
,但对于一条消息而言,只有一个消费者可以消费,即一条消息只能被一个消费者消费。
② 一对多
发布/订阅模式,即利用Topic存储消息,消息生产者将消息发布到Topic中,同时有多个消费者订阅此topic,消费者可以从中消费消息,注意发布到Topic中的消息会被多个消费者消费,消费者消费数据之后,数据不会被清除,Kafka会默认保留一段时间,然后再删除。
组件
Kafka像其他Mq一样,也有自己的基础架构,主要存在生产者Producer、Kafka集群Broker、消费者Consumer、注册消息Zookeeper.
- Producer:消息生产者,向Kafka中发布消息的角色。
- Consumer:消息消费者,即从Kafka中拉取消息消费的客户端。
- Consumer Group:消费者组,消费者组则是一组中存在多个消费者,消费者消费Broker中当前Topic的不同分区中的消息,消费者组之间互不影响,所有的消费者都属于某个消费者组,即消费者组是逻辑上的一个订阅者。某一个分区中的消息只能够一个消费者组中的一个消费者所消费
- Broker:经纪人,一台Kafka服务器就是一个Broker,一个集群由多个Broker组成,一个Broker可以容纳多个Topic。
- Topic:主题,可以理解为一个
队列
,生产者和消费者都是面向一个Topic - Partition:分区,为了实现
扩展性
,一个非常大的Topic可以分布到多个Broker
上,一个Topic可以分为多个Partition,每个Partition是一个有序的队列(分区有序,不能保证全局有序) - Replica:副本Replication,为保证集群中某个节点发生故障,节点上的Partition数据不丢失,Kafka可以正常的工作,Kafka提供了副本机制,一个Topic的每个分区有若干个副本,一个Leader和多个Follower
- Leader:每个分区多个副本的
主角色
,生产者发送数据的对象,以及消费者消费数据的对象都是Leader。 - Follower:每个分区多个副本的
从角色
,实时的从Leader中同步数据,保持和Leader数据的同步,Leader发生故障的时候,某个Follower会成为新的Leader。
2. ZooKeeper简介
zookeeper 下载地址:
http://zookeeper.apache.org/releases.html
主要用于注册信息
ZooKeeper是一个分布式且开源的分布式应用程序协调服务
。
zookeeper集群特性:整个集群种只要有超过集群数量一半的zookeeper工作只正常的,那么整个集群对外就是可用的
,
-
2台服务器做了一个zookeeper集群,只要有任何一台故障或宕机,那么这个zookeeper集群就不可用了,因为剩下的一台没有超过集群一半的数量,
-
三台zookeeper组成一个集群,那么损坏一台就还剩两台,大于3台的一半,所以损坏一台还是可以正常运行的,但是再损坏一台就只剩一台集群就不可用了。
-
四台组成一个zookeeper集群,损坏一台集群肯定是正常的,那么损坏两台就还剩两台,那么2台不大于集群数量的一半,所以3台的zookeeper集群和4台的zookeeper集群损坏两台的结果都是集群不可用,一次类推5台和6台以及7台和8台都是同理,所以这也就是为什么集群一般都是奇数的原因。
ZooKeeper本质上是一个分布式的小文件存储系统。提供基于类似于文件系统的目录树方式的数据存储,并且可以对树中的节点进行有效管理。从而用来维护和监控你存储的数据的状态变化。通过监控这些数据状态的变化,从而可以达到基于数据的集群管理
全局数据一致:集群中每个服务器保存一份相同的数据副本,client无论连接到哪个服务器,展示的数据都是一致的,这是最重要的特征;
可靠性:如果消息被其中一台服务器接受,那么将被所有的服务器接受。
顺序性:包括全局有序和偏序两种:全局有序是指如果在一台服务器上消息a在消息b前发布,则在所有Server上消息a都将在消息b前被发布;偏序是指如果一个消息b在消息a后被同一个发送者发布,a必将排在b前面。
数据更新原子性:一次数据更新要么成功(半数以上节点成功),要么失败,不存在中间状态;
实时性:Zookeeper保证客户端将在一个时间间隔范围内获得服务器的更新信息,或者服务器失效的信息
主为: Mode: leader
从为: Mode: follower
Leader
Zookeeper集群工作的核心
事务请求(写操作)的唯一调度和处理者
,保证集群事务处理的顺序性;
集群内部各个服务器的调度者
。
对于create,setData,delete等有写操作的请求,则需要统一转发给leader处理,leader
需要决定编号、执行操作,这个过程称为一个事务
Follower
处理客户端非事务(读操作
)请求,转发事务请求给Leader;
参与集群Leader选举投票
。
此外,针对访问量比较大的zookeeper集群,还可新增观察者角色。
Observer
观察者角色,观察Zookeeper集群的最新状态变化并将这些状态同步过来,其对于非事务请求可以进行独立处理,对于事务请求,则会转发给Leader服务器进行处理。
不会参与任何形式的投票只提供非事务服务,通常用于在不影响集群事务处理能力的前提下提升集群的非事务处理能力
3. 安装环境
redis与kafka功能类似都是数据的存储服务
kafka分布式消息队列用于保存数据
,kafka本身不支持集群
,所以需要与zookeeper一起用
zookeeper 下载地址:
http://zookeeper.apache.org/releases.html
kafka下载地址:
http://kafka.apache.org/downloads.html
三台服务器:
IP分别是:192.168.15.211 192.168.15.212 192.168.15.213
三台服务器分别配置hosts文件:
# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.15.211 linux-host1.exmaple.com
192.168.15.212 linux-host2.exmaple.com
192.168.15.213 linux-host3.exmaple.com
一. 安装zookeeper
先安装zookeeper
官网https://zookeeper.apache.org/
因为zk是java写的,所以启动zk就是执行java
文件,看了下小同事的zk目录都是源文件,并不是编译后的包,显然需要下载带bin
的包
配置java环境(都要配置)
Serer1 配置
cd /usr/local/src/
[root@linux-host1 src]# yum install jdk-8u151-linux-x64.tar.gz -y
[root@linux-host1 src]# tar xvf zookeeper-3.4.11.tar.gz
[root@linux-host1 src]# ln -sv /usr/local/src/zookeeper-3.4.11 /usr/local/zookeeper
[root@linux-host1 src]# mkdir /usr/local/zookeeper/data
[root@linux-host1 src]# cp /usr/local/zookeeper/conf/zoo_sample.cfg /usr/local/zookeeper/conf/zoo.cfg
[root@linux-host1 src]# grep "^[a-Z]" /usr/local/zookeeper/conf/zoo.cfg
tickTime=2000 #服务器与服务器之间和客户端与服务器之间的单次心跳检测时间间隔,单位为毫秒
initLimit=5 #集群中leader服务器与follower服务器初始连接心跳次数,即多少个2000毫秒
syncLimit=5 # leader与follower之间连接完成之后,后期检测发送和应答的心跳次数,如果该follower 在设置的时间内(5*2000)不能与leader 进行通信,那么此 follower 将被视为不可用。
clientPort=2181 #客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求
dataDir=/usr/local/zookeeper/data #自定义的zookeeper保存数据的目录
autopurge.snapRetainCount=3 #设置zookeeper保存保留多少次客户端连接的数据
autopurge.purgeInterval=1 #设置zookeeper间隔多少小时清理一次保存的客户端数据
#服务器编号=服务器IP:LF数据同步端口:LF选举端口
指定所有服务器的id,都不一样
注意这里的端口一定要确认没有被占用
#记住 前后不能有空格,否则会出错
server.1=192.168.66.103:2888:3888
server.2=192.168.66.104:2888:3888
server.3=192.168.66.105:2888:3888
#server.NUM=IP:port1:port2 NUM表示本机为第几号服务器;
IP为本机ip地址;
#port1为leader与follower通信端口;port2为参与竞选leader的通信端口
#多个实例的端口配置不能重复
# id号,必须与本机配置文件的id一样,只能有id号
[root@linux-host1 src]# echo "1" > /usr/local/zookeeper/data/myid
Server2 配置
cd /usr/local/src/
[root@linux-host2 src]# yum install jdk-8u151-linux-x64.tar.gz -y
[root@linux-host2 src]# tar xvf zookeeper-3.4.11.tar.gz
[root@linux-host2 src]# ln -sv /usr/local/src/zookeeper-3.4.11 /usr/local/zookeeper
[root@linux-host2 src]# mkdir /usr/local/zookeeper/data
[root@linux-host2 src]# cp /usr/local/zookeeper/conf/zoo_sample.cfg /usr/local/zookeeper/conf/zoo.cfg
[root@linux-host2 src]# grep "^[a-Z]" /usr/local/zookeeper/conf/zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
clientPort=2181
dataDir=/usr/local/zookeeper/data
#设置id
server.1=192.168.15.211:2888:3888
server.2=192.168.15.212:2888:3888
server.3=192.168.15.213:2888:3888
# id号,必须与本机配置文件的id一样
[root@linux-host2 src]# echo "2" > /usr/local/zookeeper/data/myid
Server3 配置
[root@linux-host3 ~]# cd /usr/local/src/
[root@linux-host3 src]# yum install jdk-8u151-linux-x64.tar.gz -y
[root@linux-host3 src]# tar xvf zookeeper-3.4.11.tar.gz
[root@linux-host3 src]# ln -sv /usr/local/src/zookeeper-3.4.11 /usr/local/zookeeper
[root@linux-host3 src]# mkdir /usr/local/zookeeper/data
[root@linux-host3 src]# cp /usr/local/zookeeper/conf/zoo_sample.cfg /usr/local/zookeeper/conf/zoo.cfg
[root@linux-host3 src]# grep "^[a-Z]" /usr/local/zookeeper/conf/zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
clientPort=2181
dataDir=/usr/local/zookeeper/data
server.1=192.168.15.211:2888:3888
server.2=192.168.15.212:2888:3888
server.3=192.168.15.213:2888:3888
# id号,必须与本机配置文件的id一样
[root@linux-host3 src]# echo "3" > /usr/local/zookeeper/data/myid
启动,并测试
各服务器启动zookeeper
/usr/local/zookeeper/bin/zkServer.sh start
如果配置项后面有空格
就会出现
解决方法
正确结果----只要配置没问题可能需要等一会儿才会出现
查看状态
查看各zookeeper状态:
/usr/local/zookeeper/bin/zkServer.sh status
两个Mode: follower
一个Mode: leader
使用zoolnspector工具测试
zookeeper简单操作命令
连接到任意节点生成数据:
[root@linux-host3 data]# /usr/local/zookeeper/bin/zkCli.sh -server 192.168.15.211:2181
WatchedEvent state:SyncConnected type:None path:null
create /test "hello"
Created /test
[zk: 192.168.15.211:2181(CONNECTED) 1]
在其他zookeeper节点验证数据:
host2 src]# /usr/local/zookeeper/bin/zkCli.sh -server 192.168.15.212:2181
[zk: 192.168.15.212:2181(CONNECTED) 0] get /test
hello
二. 安装并测试kafka
kafka可以和zookeeper不在同一个服务器
1. 每台服务器安装kafka
Server1安装kafka:
[root@linux-host1 src]# tar xvf kafka_2.11-1.0.0.tgz
[root@linux-host1 src]# ln -sv /usr/local/src/kafka_2.11-1.0.0 /usr/local/kafka
[root@linux-host1 src]# vim /usr/local/kafka/config/server.properties
#设置每个代理全局唯一的整数ID,每一个都不一样
#这个值可以与zookeeper不一样
broker.id=1
#当前服务器地址,
listeners=PLAINTEXT://192.168.15.211:9092
#保留指定小时的日志内容,小时
log.retention.hours=24
log.dirs=日志文件
#所有的zookeeper地址
zookeeper.connect=192.168.15.211:2181,192.168.15.212:2181,192.168.15.213:2181
Server2安装kafka:
[root@linux-host2 src]# tar xvf kafka_2.11-1.0.0.tgz
[root@linux-host2 src]# ln -sv /usr/local/src/kafka_2.11-1.0.0 /usr/local/kafka
[root@linux-host2 src]# vim /usr/local/kafka/config/server.properties
broker.id=2
listeners=PLAINTEXT://192.168.15.212:9092
zookeeper.connect=192.168.15.211:2181,192.168.15.212:2181,192.168.15.213:2181
Server3安装kafka:
[root@linux-host3 src]# tar xvf kafka_2.11-1.0.0.tgz
[root@linux-host3 src]# ln -sv /usr/local/src/kafka_2.11-1.0.0 /usr/local/kafka
[root@linux-host3 src]# vim /usr/local/kafka/config/server.properties
broker.id=3
listeners=PLAINTEXT://192.168.15.213:9092
zookeeper.connect=192.168.15.211:2181,192.168.15.212:2181,192.168.15.213:2181
2. 分别启动kafka,并测试
每一个机器都要测试
#以守护进程的方式启动
host1 src]# /usr/local/kafka/bin/kafka-server-start.sh -daemon /usr/local/kafka/config/server.properties
测试kafka:每台都需要测试
验证进程:
[root@linux-host1 ~]# jps
10578 QuorumPeerMain
11572 Jps
11369 Kafka
2.1 使用zoolnspector工具测试
2.2 使用kafkatool工具测试
链接----进入到brokers/topics中找到具体的数据–data
测试创建topic
在任意kafaka服务器操作:
创建名为logstashtest
partitions(分区)为3
replication(复制)为3的topic(主题):
/usr/local/kafka/bin/kafka-topics.sh --create --zookeeper 192.168.66.102:2181,192.168.66.105:2181,192.168.66.106:2181 --partitions 3 --replication-factor 3 --topic logstashtest
测试获取topic
可以在任意一台kafka服务器进行测试:
/usr/local/kafka/bin/kafka-topics.sh --describe --zookeeper 192.168.66.102:2181,192.168.66.105:2181,192.168.66.106:2181 --topic logstashtest
logstashtest有三个分区分别为0、1、2,分区0的leader是3(broker.id),分区0有三个副本,并且状态都为lsr(ln-sync,表示可以参加选举成为leader)
删除topic:
/usr/local/kafka/bin/kafka-topics.sh --delete --zookeeper 192.168.66.102:2181,192.168.66.105:2181,192.168.66.106:2181 --topic logstashtest
获取所有topic
/usr/local/kafka/bin/kafka-topics.sh --list --zookeeper 192.168.66.102:2181,192.168.66.105:2181,192.168.66.106:2181
kafka命令测试消息发送
创建topic
/usr/local/kafka/bin/kafka-topics.sh --create --zookeeper 192.168.66.102:2181,192.168.66.105:2181,192.168.66.106:2181 --partitions 3 --replication-factor 3 --topic messagetest
Created topic "messagetest".
发送消息:
/usr/local/kafka/bin/kafka-console-producer.sh --broker-list 192.168.66.102:9092,192.168.66.105:9092,192.168.66.106:9092 --topic messagetest
数据会分散放在kafka的分区上
>hello
>kafka
>logstash
>ss
>oo
其他kafka服务器测试获取数据:
#Server1:
/usr/local/kafka/bin/kafka-console-consumer.sh --topic messagetest --bootstrap-server 192.168.66.102:9092 --from-beginning
三. logstash 收集日志并写入 kafka
往kafka写日志必须为json格式
配置zookeeper和kafka
1. 收集手动输入的日志(测试)
[root@linux-host3 ~]# vim /etc/logstash/conf.d/logstash-to-kafka.sh
input {
stdin {}
}
output {
kafka {
topic_id => "hello"
bootstrap_servers => "192.168.66.102:9092"
batch_size => 5
}
stdout {
codec => rubydebug
}
}
验证kafka收到logstash数据:
/usr/local/kafka/bin/kafka-console-consumer.sh --zookeeper 192.168.66.102:2181,192.168.66.105:2181,192.168.66.106:2181 --topic hello --from-beginning
/usr/local/kafka/bin/kafka-console-producer.sh --broker-list 192.168.15.211:9
092,192.168.15.212:9092,192.168.15.213:9092 --topic messagetest>hello
>kafka
>logstash
2. 收集 Nginx 日志
注意nginx日志权限644
[root@linux-host2 ~]# cat /etc/logstash/conf.d/nginx-kafka.conf
input {
file {
path => "/var/log/nginx/access.log"
start_position => "beginning"
type => "nginx-accesslog"
start_position => "beginning"
codec => "json" #声明 json 编码格式
} }
output {
if [type] == "nginx-accesslog" {
kafka {
bootstrap_servers => "192.168.15.11:9092" #kafka 服务器地址
topic_id => "nginx-accesslog"
#注意这里收集的日志必须为json格式
codec => "json"
}
file {
path => "/tmp/nginx-jsog-log.txt"
}
} }
重启 logstash:
/usr/share/logstash/bin/logstash -f /etc/logstash/conf.d/nginxkafka.conf -t
systemctl restart logstash
访问 Nginx Web 界面:
ab -n100 -c10 http://192.168.15.12/index.html
验证日志写入到/tmp 文件
#注意这里收集的日志必须为json格式
确认写入到kafka
#注意这里收集的日志必须为json格式
3. 从 kafka 读取日志
读取的是nginx日志
cat /etc/logstash/conf.d/kafka-es.conf
input {
kafka {
bootstrap_servers => "192.168.66.102:9092"
#这个名称为kafka中的类名
topics => "nginx-accesslog"
codec => "json"
consumer_threads => 1
#decorate_events => true
} }
output {
if [type] == "nginx-accesslog" {
elasticsearch {
hosts => ["192.168.66.101:9200"]
index => "nginx-accesslog-%{+YYYY.MM.dd}"
}}
}
测试语法并重启 logstash:
[root@linux-host1 ~]# /usr/share/logstash/bin/logstash -f /etc/logstash/conf.d/kafkaes.conf -t
systemctl restart logstash
kibana 添加 Nginx 访问日志索引
4. 收集日志并写入 kafka
将本机的日志写入kafka
配置 logstash 收集 message 日志:
chmod 644 /var/log/syslog
chmod +x /var/log/nginx/access.log
[root@linux-host2 conf.d]# cat nginx-kafka-in.conf
input {
file {
path => "/var/log/nginx/access.log"
start_position => "beginning"
type => "nginx-log"
codec => "json"
}
file {
path => "/var/log/syslog"
start_position => "beginning"
type => "syslog-log"
} }
output {
if [type] == "nginx-log" {
kafka {
bootstrap_servers => "192.168.66.105:9092"
topic_id => "nginx-log"
batch_size => 5
codec => "json"
} }
if [type] == "syslog-log" {
kafka {
bootstrap_servers => "192.168.66.106:9092"
topic_id => "syslog-log"
batch_size => 5
codec => "json" #写入的时候使用 json 编码,因为 logstash 收集后会转换
成 json 格式
}
file {
path => "/tmp/sysin-log.txt"
}
}
}
测试并重启 logstash:
/usr/share/logstash/bin/logstash -f /etc/logstash/conf.d/nginx-kafka.conf -t
systemctl restart logstash
5. 从 kafka 读取系统日志
此步骤如果没有从 kafka 正确收集日志或者将日志从 kafka 读取并写入到文件没有输出,可以使用测试
/usr/share/logstash/bin/logstash -f /etc/logstash/conf.d/kafka-es-out.conf
[root@linux-host1 ~]# cat /etc/logstash/conf.d/kafka-es-out.conf
input {
kafka {
bootstrap_servers => "192.168.66.102:9092"
topics => "nginx-log"
codec => "json"
consumer_threads => 1
decorate_events => true
}
kafka {
bootstrap_servers => "192.168.66.102:9092"
topics => "syslog-log"
consumer_threads => 1
decorate_events => true
codec => "json"
} }
output {
if [type] == "nginx-log" {
elasticsearch {
hosts => ["192.168.66.101:9200"]
index => "nginx-log-%{+YYYY.MM.dd}"
}}
if [type] == "syslog-log" {
elasticsearch {
hosts => ["192.168.66.101:9200"]
index => "syslog-log-%{+YYYY.MM.dd}"
}
file {
path => "/tmp/sysout-log.txt"
}
}
}
验证配置并启动 logstash:
/usr/share/logstash/bin/logstash -f /etc/logstash/conf.d/kafkaes.conf -t
systemctl start logstash
在 kibana 添加索引
kibana 验证数据