01 . 消息队列之(Kafka+ZooKeeper)

消息队列简介

什么是消息队列?

首先,我们来看看什么是消息队列,维基百科里的解释翻译过来如下:

队列提供了一种异步通信协议,这意味着消息的发送者和接受者不需要同时与消息保持联系,发送者发送的消息会存储在队列中,直到接受者拿到他.

一般我们把消息的发送者称为生产者,消息的接收者称为消费者;注意定义中的哪两个字'异步'

通常生产者的生产速度和消费者的消费速度是不相等的; 如果两个程序始终保持同步沟通,那势必有一方存在空等时间;

如果两个程序持续运行的话,消费者的平均速一定要大于生产者,不然队列堆积越来越多;
当然,如果消费者没有时效性需求的话,也可以吧消息堆积在队列中,集中消费;

为何使用消息队列?

1.解耦

在项目启动之初来预测将来项目会碰到什么需求,是极其困难的。消息系统在处理过程中间插入了一个隐含的,基于数据的接口层,两边的处理过程都要事先这一接口.这允许你独立的扩展或修改两边的处理过程,只要确保他们遵守相同的接口约束.

2.冗余

有些情况下,处理数据的过程会失败。除非数据被持久化,否则将造成丢失。消息队列把数据进行持久化直到他们已经被完全处理,通过这一方式规避了数据丢失风险,许多消息队列所采用的的'插入 - 获取 - 删除'范式中,在把一个消息从队列中删除之前,需要你的处理系统明确的指出该消息已经被处理完毕,从而确保你的数据被安全的保存直到你使用完毕.

3.扩展性

因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的,只要另外增加处理过程即可。不需要改变代码,不需要调节参数,扩展就像调大电力按钮一样简单.

4.灵活性 & 峰值处理能力

在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量并不常见;
如果为以处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费,使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷请求完全崩溃.

5.可恢复性

系统的一部分组件时效时,不会影响到整个系统,消息队列降低了进程间的耦合度,所以即使一个消息处理的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理.

6.顺序保证

在大多数使用场景下,数据处理的顺序都很重要,大部分消息队列本来就是排序的,并且保证数据会按按照特定的顺序来处理,kafka保证了一个Partition内的消息的有序性.

7缓冲

在任何重要的系统中,都会需要不同处理时间的元素。例如,加载一张图片比应用过滤器花费更少的时间。消息队列通过一个缓冲层来帮助任务最高效率的执行—— 写入队列的处理会尽可能的快速。该缓冲有助于控制和优化数据流经过系统的速度.

8.异步通信

很多时候,用户不想也不需要立即处理消息,消息队列提供了异步处理机制,允许用户把一个消息放入队列,但不立即处理他,想向队列放入多少消息就放多少,然后在需要的时候再去处理他们.

9.削峰

通过在应用前端以消息队列接收请求来达到削峰的目的。请求超过队列长度直接不处理重定向至错误页面
流量削峰是消息队列中常用场景,一般在秒杀或团抢活动中使用广泛
应用场景: 秒杀活动,一般会因为流量过大,导致流量剧增,应用挂掉,为解决这个问题,一般需要在应用前端加入消息队列

消息队列在秒杀活动中的应用?
1. 可以控制活动的人数
2. 可以缓解短时间内高流量压垮应用
3. 用户的请求,服务器接收后,首先写入消息队列,假如消息队列长度超过最大数量,则直接抛弃用户请求或跳转到错误页面
4. 秒杀业务根据消息队列中的请求信息,再做后续处理

# 提速: 消息队列应用下,消息生产应用只管生产,不需要等待消费完就能处理其他事情,实际上起到了提速的作用.

Kafka概念

Kafka简介

Kafka是一个开源的分布式消息引擎/消息中间件,同时Kafka也是一个流处理平台。Kakfa支持以发布/订阅的方式在应用间传递消息,同时并基于消息功能添加了Kafka Connect、Kafka Streams以支持连接其他系统的数据(Elasticsearch、Hadoop等)

Kafka最核心的最成熟的还是他的消息引擎,所以Kafka大部分应用场景还是用来作为消息队列削峰平谷。另外,Kafka也是目前性能最好的消息中间件。

在Kafka集群(Cluster)中,一个Kafka节点就是一个Broker,消息由Topic来负载,可以存储在1个或多个Partition中,发布消息的应用为Producer、消费消息的应用为Consumer,多个Consumer可以促成Consumer Group共同消费一个Topic中的消息。

# Broker:	Kafka节点
# Topic: 主题,用来承载消息
# Partition: 分区,用于主题分片存储
# Producer: 生产者,向主题发布消息的应用
# Consumer: 消费者,从主题订阅消息的应用
# Consumer Group: 消费者组,由多个消费者组成.
Kafka.原点

Kafka设计的初衷是处理不同类型的数据,实现一个简单的、结构化的高性能系统,以实时分析用户行为和监控系统状态.

Kafka的诞生

由Jay Kreps主导的开发团队希望构建一个能同时满足监控系统和追踪系统的消息系统,最初的目标是

# 通过push-pull 模型对生产者和消费者解耦
# 提供消息持久性支持多消费者
# 优化消息的高吞吐率
# 允许系统水平扩展

最终,开发出来的Kafka在接口上和典型的消息系统的发布/订阅一致,但在存储层上,更像一个日志聚合系统。借助Apache Avro进行消息序列化,Kafka能够做到大规模的消息处理。

发布-订阅模型

通过发布-订阅模型,各个子模块之间做到解耦,各个子模块只需要知道自己需要往中间件-kafka取值还是存值即可。简单的抽象模型如下图所示

Kafka的出现,做到了子系统之间的解耦合,因此,它也被称为[分布式日志提交系统]或者[分布式流处理系统]。下面是kafka的一些基本概念:

消息和批处理
Kafka处理的数据单元叫做[消息],一种类似于数据库中[行]或者[记录]的概念.

这些数据单元,对于Kafka而言,并没有特殊意义,都是字节数组,但是每个消息可以拥有描述性的元数据---key,这些key通常用来表示消息应该存放的分区。为了效率,Kafka里的消息都是批处理的,同一批(Batch)的消息主题和分区相同,这样的设计有助于减少单消息在网络传输带来的开销,当然,这种处理方式,也是一种在吞吐量和网络延时的折中的方案.

模式

为了让消息具备更加的可读性,Kafka使用模式(Schema)来管理数据类型,如JSON,XML等等。为了向后兼容,或者做到可扩展性,选择合适的Schema非常重要.

主题和分区

Kafka里的消息按主题分类,鉴于Kafka里的消息是按追加,从头到尾读取的方式,使用分区可以大大提高Kafka的读取效率,也提供了系统的可扩展性,消息写入分区的方式如下图所示:
一个主题的消息,在类似于Kafka这样系统中,称之为[流]

生产者和消费者

Kafka有两个重要的概念: 生产者和消费者: 两个高级的客户端(Kafka使用者)接口: 集成Kafka的Kafka Connect API和操作Kafka的Kafka Stream接口.

生产者: 创建消息的主题。可以通过不同的Key把消息发往不同的主题中去,还可以根据用户自定义的行为发送日志.

消费者: 读取消息的主体,消费者追踪每个分区的offset的值,决定从哪里去取消息,Zookeeper或者Kafka可以存储offset的值,共同消费一个主题的消费者,被称为[消费者],消费者中的消费者和主题中的分区的队列关系被称为[消费者所得权],.使用下图所示的消费组,可以使Kafka更便于水平扩展.

中间人和集群

中间人: 单个的Kafka服务器叫做中间人,一个Kafka中间人,接收生产者发来的消费,分配偏移量,并存储入物理空间中去: 同时中间人还接受消费者的请求,把物理空间的消息响应回去.

集群: 一组协同工作的中间人叫做集群,在一个集群中,会有一个中间人充当集群控制器的角色,该控制器负责监控中间人的状态.在集群中,独占分区的中间人叫做该分区的头头(Leader).多个中间人共享分区,可以使消息进行[主从复制],当一个中间人挂掉,其他的中间人可接管头头的角色,当然前提是,接管头头角色的中间人之前可以和前头头联通。下图是一个集群里,不同中间人复制消息的图示:

Kafka还有一个重要的概念: 保质期(Retention),表示消息在Kafka服务器里保留的时长。Kafka根据不同的策略,配置服务器里消息的保质期,如: 根据消息的大小(达到特定大小后失效),根据时间(指定时间后过期)配置。

多集群
# 随着业务的扩展,如下需求通常会被指出:

    # 数据类型分离
    # 安全因素的数据隔离
    # 多数据中心(灾备)

举个例子,不同集群间可以通过MirrorMaker工具进行数据复制,简而言之,就是通过该工具,从一个集群消费消息,然后向另外一个集群生产消息,下面是一个通过MirrorMaker进行集群中消息复制的图例

Kafka生态系统

基于Kafka的生产/消费模型,有一系列的生产和消费的技术,各种处理消息的技术,以统一的接口方式,构成了kafka的生态系统,Kafka生态系统如下图所示:

Kafka应用

活动跟踪

Kafka可以记录用户访问前端应用的活动日志,这也是Linkedin开发Kafka的初衷.

Kafka搜集的用户点击鼠标事件、浏览页面的事件、更改个人主页的事件,均可以用作后端程序处理,使其变成有价值的产物.

系统监控和日志记录

可以向Kafka中发送系统的运行日志,通过分析这些日志,可以对系统的各个指标进行评估,同时,Kafka记录的日志可供其他日志分析系统消费.

发消息

Kafka可以向其他应用发送中间件的消息,如: 数据库有改动,可以将有改动的信息发往应用程序

流式处理

Kafka提供的对数据的流式操作,如Hadoop的Map/Reduce模型类似,可以做到数据的实时处理

为什么选择Kafka

虽然很多发布/订阅式的系统,但是选择Kafka是出于以下原因:

多生产者

Kafka可以无缝接入多个生产者,多个消费者可以消费同一个主题内的消息,而无需知道该主题的消息来自哪个生产者,一个简单的例子就是: 多个微服务往同一个注意中投放消息,然后该主题的消息[聚合]了多个应用

多消费者

Kafka多消费者模型,表现为多个消费者互不干扰地消费同一主题内的消息,这也是Kafka和其他消息队列不同的地方.

基于磁盘的有效期

Kafka中的消息会被写入磁盘,得益于Kafka灵活的消息过期策略,磁盘中的消息有效期是可配置的。鉴于此,Kafka不会有丢消息的危险,即便应用重启,他仍能够借助Kafka从结束的地方重新开始.

扩展性

Kafka拥有灵活的扩展性配置,这意味着: 用户可以根据需求扩展Kafka的Broker的数量来接收和处理任意数量的数据: 多Broker可以接管单Broker中的错误.

高性能

上述 多生产者/消费者、可扩展性、灵活的有效期配置造就了Kafka的高性能.

ZooKeeper简介

ZooKeeper是一个开源的分布式应用程序协调服务,是Google的Chubby一个开源的实现。ZooKeeper为分布式应用提供一致性服务、提供的功能包括:

分布式同步(Distributed Synchronization),命名服务(Naming Service)、集群维护(GroupMaintenance)、分布式锁(Distributed Lock)等,简化分布式应用协调及其管理的难度,提供高性能的分布式服务.

它包含一个简单的原语集,分布式应用程序可以基于它实现同步服务,配置维护和命名服务等。Zookeeper是hadoop的一个子项目,其发展历程无需赘述。在分布式应用中,由于工程师不能很好地使用锁机制,以及基于消息的协调机制不适合在某些应用中使用,因此需要有一种可靠的、可扩展的、分布式的、可配置的协调机制来统一系统的状态。Zookeeper的目的就在于此。

ZooKeeper本身可以以单机模式安装运行,不过他的长处在于通过分布式ZooKeeper集群(一个Leader,多个Follower),基于一定的策略来保证ZooKeeper集群的稳定性和可用性,从而实现分布式应用的可靠性.

ZooKeeper集群角色说明

ZooKeeper主要有领导者(Leader), 跟随者(Follower)和观察者(Observer)三种角色.

# 1. 领导者(Leader):  为客户端提供读和写的服务,负责投票的发起和决议,更新系统状态.
# 2. 跟随者(Follower): 为客户端提供读服务,如果是写服务则转发给Leader,在选举过程中参与投票.
# 3. 观察者(Observer): 为客户端提供读服务器,如果是写服务则转发给Leader,不参与选举过程中的投票,
#    也不参与“g过半写成功”的策略,在不影响写性能的情况下提供集群的读性能,此角色于ZooKeeper3.3的角色.

1 . 最终一致性:client不论连接到哪个Server,展示给它都是同一个视图,这是zookeeper最重要的性能。

2 . 可靠性:具有简单、健壮、良好的性能,如果消息m被到一台服务器接受,那么它将被所有的服务器接受。

3 . 实时性:Zookeeper保证客户端将在一个时间间隔范围内获得服务器的更新信息,或者服务器失效的信息。但由于网络延时等原因,Zookeeper不能保证两个客户端能同时得到刚更新的数据,如果需要最新数据,应该在读数据之前调用sync()接口。

4 . 等待无关(wait-free):慢的或者失效的client不得干预快速的client的请求,使得每个client都能有效的等待。
原子性:更新只能成功或者失败,没有中间状态。

5 . 顺序性:包括全局有序和偏序两种:全局有序是指如果在一台服务器上消息a在消息b前发布,则在所有Server上消息a都将在消息b前被发布;偏序是指如果一个消息b在消息a后被同一个发送者发布,a必将排在b前面。

为什么zookeeper节点是奇数

我们知道,在每台机器数据保持一致的情况下,zookeeper集群可以保证,客户端发起的每次查询操作,集群节点都能返回同样的结果。

但是对于客户端发起的修改,删除等能改变数据的操作呢?集群中那么多台机器,你修改你的,我修改我的,最后犯规集群中那台机器的数据呢?

这就是一盘散沙,需要一个领导,于是在zookeeper集群中,leader的作用就体现出来了,只有leader节点才有权利发起修改数据的操作,而follower节点即使接收到了客户端发起的修改操作,也要将其转交给leader来处理,leader接收到修改数据的请求后,会向所有follower广播一条消息,让他们执行某项操作,follower 执行完后,便会向 leader 回复执行完毕。当 leader 收到半数以上的 follower 的确认消息,便会判定该操作执行完毕,然后向所有 follower 广播该操作已经生效。

所以zookeeper集群中leader是不可缺少的,但是 leader 节点是怎么产生的呢?其实就是由所有follower 节点选举产生的,讲究民主嘛,而且leader节点只能有一个,毕竟一个国家不能有多个总统。

这个时候回到我们的小标题,为什么 zookeeper 节点数是奇数,我们下面来一一来说明:

1 . 容错率

首先从容错率来说明:(需要保证集群能够有半数进行投票)

2台服器,至少2台正常运行才行(2的半数为1,半数以上最少为2),正常运行1台服务器都不允许挂掉,但是相对于 单节点服务器,2台服务器还有两个单点故障,所以直接排除了。
3台服务器,至少2台正常运行才行(3的半数为1.5,半数以上最少为2),正常运行可以允许1台服务器挂掉
4台服务器,至少3台正常运行才行(4的半数为2,半数以上最少为3),正常运行可以允许1台服务器挂掉
5台服务器,至少3台正常运行才行(5的半数为2.5,半数以上最少为3),正常运行可以允许2台服务器挂掉

2 . 防脑裂

脑裂集群的脑裂通常是发生在节点之间通信不可达的情况下,集群会分裂成不同的小集群,小集群各自选出自己的leader节点,导致原有的集群出现多个leader节点的情况,这就是脑裂。

3台服务器,投票选举半数为1.5,一台服务裂开,和另外两台服务器无法通行,这时候2台服务器的集群(2票大于半数1.5票),所以可以选举出leader,而 1 台服务器的集群无法选举。

4台服务器,投票选举半数为2,可以分成 1,3两个集群或者2,2两个集群,对于 1,3集群,3集群可以选举;对于2,2集群,则不能选择,造成没有leader节点。

5台服务器,投票选举半数为2.5,可以分成1,4两个集群,或者2,3两集群,这两个集群分别都只能选举一个集群,满足zookeeper集群搭建数目。
以上分析,我们从容错率以及防止脑裂两方面说明了3台服务器是搭建集群的最少数目,4台发生脑裂时会造成没有leader节点的错误。

Kafka集群部署

集群环境

List

# CentOS7.3
# zookeeper-3.4.14.tar.gz
# kafka_2.12-2.3.0.tgz
# jdk-8u121-linux-x64.rpm
节点名 IP 软件版本 说明
zk01 192.168.171.143 ZooKeeper3.4.14 / JDK1.8u121 / Kafka_2.12 Nat,内网
zk02 192.168.171.144 ZooKeeper3.4.14 / JDK1.8u121 / Kafka_2.12 Nat,内网
zk03 192.168.171.128 ZooKeeper3.4.14 / JDK1.8u121 / Kafka2.12 Nat,内网

注意事项:

# 1. zoo.cfg文件配置出错:dataLogDir指定的目录未被创建;主机名可能不对;
# 2. myid文件中的整数格式不对,或者与zoo.cfg中的server整数不对应;
# 3. 防火墙未关闭;
# 4. 端口占用;
# 5. 还有一个特别坑的地方就是jdk,不要相信java -version,这里看见的可能跟/etc/profile中配置的不一样;
ZooKeeper集群模式

单机模式

# 在zoo.cfg中只配置一个server.id就是单机模式了
# 这种模式下,如果当前主机宕机,那么所有依赖于当前zookeeper服务工作的其他服务都不能正常工作,
# 这种事情称为单节点故障,所以这种模式一般用在测试环境

伪分布式

# 在zoo.cfg中配置多个server.id,其中ip都是当前机器,而端口各不相同,启动时就是伪集群模式了.
# 这种模式和单机模式产生的问题是一样的,这种模式也是用在测试环境中

完全分布式

# 多台机器各自配置zoo.cfg文件,将各自互相加入服务器列表,上面搭建的集群就是这种完全分布式.
# 这种模式是真实生产环境中使用的zookeeper集群模式

部署ZooKeeper

集群节点规划

ZooKeeper在提供分布式锁等服务的时候需要过半数的节点可用,另外高可用的诉求来说,节点的个数必须>1,所以ZooKeeper集群需要>1的奇数节点,例如3,5,7等等,本次我们规划三个节点,操作系统选用CentOS7。

注意事项:

# 1. zoo.cfg文件配置出错:dataLogDir指定的目录未被创建;主机名可能不对;
# 2. myid文件中的整数格式不对,或者与zoo.cfg中的server整数不对应;
# 3. 防火墙未关闭;
# 4. 端口占用;
# 5. 还有一个特别坑的地方就是jdk,不要相信java -version,这里看见的可能跟/etc/profile中配置的不一样;
初始化系统环境
init_security() {
systemctl stop firewalld
systemctl disable firewalld &>/dev/null
setenforce 0
sed -i '/^SELINUX=/ s/enforcing/disabled/'  /etc/selinux/config
sed -i '/^GSSAPIAu/ s/yes/no/' /etc/ssh/sshd_config
sed -i '/^#UseDNS/ {s/^#//;s/yes/no/}' /etc/ssh/sshd_config
systemctl enable sshd crond &> /dev/null
rpm -e postfix --nodeps
echo -e "\033[32m [安全配置] ==> OK \033[0m"
}
init_security

init_yumsource() {
if [ ! -d /etc/yum.repos.d/backup ];then
    mkdir /etc/yum.repos.d/backup
fi
mv /etc/yum.repos.d/* /etc/yum.repos.d/backup 2>/dev/null
if ! ping -c2 www.baidu.com &>/dev/null    
then
    echo "您无法上外网,不能配置yum源"
    exit    
fi
    curl -o /etc/yum.repos.d/163.repo http://mirrors.163.com/.help/CentOS7-Base-163.repo &>/dev/null
    curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo &>/dev/null
    yum clean all
    timedatectl set-timezone Asia/Shanghai
    echo "nameserver 114.114.114.114" > /etc/resolv.conf
    echo "nameserver 8.8.8.8" >> /etc/resolv.conf
    chattr +i /etc/resolv.conf
    yum -y install ntpdate
    ntpdate -b  ntp1.aliyun.com        # 对时很重要,避免zookeeper因为时间不准找不到主机
    echo -e "\033[32m [YUM Source] ==> OK \033[0m"
}
init_yumsource

main() {
    init_security
    init_yumsource
}
main

# 配置主机名解析
tail -3 /etc/hosts
192.168.171.143 zk01
192.168.171.144 zk02
192.168.171.128 zk03
准备Java环境并安装ZooKeeper
# 准备Java环境
tar xvf jdk-8u151-linux-x64.tar.gz  -C /usr/local/
tail -3 /etc/profile
export JAVA_HOME=/usr/local/jdk1.8.0_151
export PATH=$PATH:$JAVA_HOME/bin
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
source /etc/profile

# 下载ZooKeeper包,并解压到相应目录
wget https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3.4.14/zookeeper-3.4.14.tar.gz
tar xvf zookeeper-3.4.14.tar.gz -C /usr/zookeeper/
cd /usr/local
mv zookeeper-3.4.14/ zookeeper
cd zookeeper/conf/
cp zoo_sample.cfg zoo.cfg
mkdir -p /usr/local/zookeeper/data
mkdir -p /usr/local/zookeeper/logs
cd ..
echo 0 > data/myid

# 配置节点标识
# zk01机器:  echo "1" > /zookeeper/data/myid        
# zk02机器:  echo "2" > /zookeeper/data/myid  
# zk03机器:  echo "3" > /zookeeper/data/myid

# 配置环境变量
tail -2 /etc/profile    # profile最后增加如下内容
export ZOOKEEPER_HOME=/usr/local/zookeeper
export PATH=$PATH:$ZOOKEEPER_HOME/bin

# 使环境变量生效
source  /etc/profile
配置ZooKeeper
# 修改配置文件
cat conf/zoo.cfg 
tickTime=2000  # 服务器之间或客户端与服务器之间的单次心跳检测时间间隔,单位为毫秒.
initLimit=10   # 集群中leader服务器与follower服务器第一次连接最多次数
syncLimit=5    # leader 与 follower之间发送和应答时间,如果follower在设置的时间不能与leader进行通信,那么follower将视为不可用.
dataDir=/usr/local/zookeeper/data  # 自定义的zookeeper保存数据的目录
dataLogDir=/usr/local/zookeeper/logs
clientPortAddress=192.168.43.47
clientPort=2181
server.0=192.168.43.47:2888:3888 
server.1=192.168.43.151:2888:3888 
server.2=192.168.re.43:2888:3888
启动ZooKeeper
# sh $Z启动
sh zkServer.sh start

# 或者直接
zkServer.sh start
zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /opt/zookeeper-3.4.14/bin/../conf/zoo.cfg
Mode: follower

# 如果启动报错,通过以下命令查看日志
zkServer.sh start-foreground
测试ZooKeeper连接有不有问题
zkCli.sh -server zk1:2181
WATCHER::
WatchedEvent state:SyncConnected type:None path:null
# 输入命令测试,查看ZooKeeper根
[zk: zk1:2181(CONNECTED) 0] ls /
[zookeeper]

ZooKeeper常用配置项说明

配置项 名称 ken.io的说明
tickTime CS通信心跳间隔 服务器之间维持心跳的时间间隔,也就是tickTime时间会发送一个心跳,TickTime以秒为单位
initLimit LF初始通信时限 集群中的follower服务器(F)与Leader服务器之间初始连接时能容忍的最多心跳数
syncLimit LF同步通信时限 集群的follower服务器(F)与Leader服务器之间初始连接时能容忍的最多心跳数
dataDir 数据文件目录 Zookeeper保存数据的目录,默认情况下,Zookeeper将写数据的日志文件也保存在这个目录里
dataLogDir 日志文件目录 Zookeeper保存日志文件的目录
clientPort 客户端连接端口 客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求
server.N 服务器名称与地址 从N开始依次为:服务编号、服务地址、LF通信端口、选举端口;例如:server.1=192.168.88.11:2888:3888

注意事项

# 下面这个环境是接着ZooKeeper环境做的,所以先做完ZooKeeper
下载Kafka的tar.gz包并准备数据目录
# 创建应用目录
mkdir /usr/kafka
#创建kafka数据目录
mkdir /kafka/logs -p
mkdir -p /kafka/logs
chmod 777  /kafka -R
# 下载安装包到/opt
cd /opt
wget http://mirrors.tuna.tsinghua.edu.cn/apache/kafka/2.3.1/kafka_2.12-2.3.1.tgz
tar xvf kafka_2.12-2.3.1.tgz -C /usr/kafka
Kafka节点配置
Kafka01(zk1)
cd /usr/kafka/kafka_2.12-2.3.1/
vim config/server.properties
21 broker.id=0
31 listeners=PLAINTEXT://zk1:9092
123 zookeeper.connect=zk1:2181,zk2:2181,zk3:2181

Kafka02(zk2)
cd /usr/kafka/kafka_2.12-2.3.1/
vim config/server.properties
21 broker.id=1
31 listeners=PLAINTEXT://zk2:9092

Kafka02(zk3)
cd /usr/kafka/kafka_2.12-2.3.1/
vim config/server.properties
21 broker.id=2
31 listeners=PLAINTEXT://zk3:9092
启动Kafka
# 进入kafka根目录
cd /usr/kafka/kafka_2.12-2.3.0/
# 启动
nohup ./bin/kafka-server-start.sh config/server.properties &

Kafka测试

创建Topic
./bin/kafka-console-producer.sh --broker-list 192.168.43.47:9092,192.168.43.151:9092,192.168.43.43:9092 --topic kafka1
#Topic在Kafka01上创建后也会同步到集群中另外两个Broker:  Kafka02, Kafka03
查看Topic

我们可以通过命令列出指定的Broker

 ./bin/kafka-topics.sh --list --bootstrap-server 192.168.43.47:9092,192.168.43.151:9092,192.168.43.43:9092 
__consumer_offsets
kafka1
test-you-io
删除Topic
./bin/kafka-topics.sh --delete --zookeeper 192.168.43.47:2181,192.168.43.151:2181,192.168.43.43:2181 --topic kafkatest
发送消息
 ./bin/kafka-console-producer.sh --broker-list 192.168.43.47:9092,192.168.43.151:9092,192.168.43.43:9092 --topic kafka1
>1234

# 到另外两台机器消费消息,我们可以看到都能收到ZK2消息,这是因为两个消费的命令是建立了两个不同的Consumer,
# 如果我们启动Consumer指定Consumer Group ID就可以作为一个消费组协同工,1个消息同时只会被一个Consumer消费到.
接受消息
./bin/kafka-console-consumer.sh --bootstrap-server 192.168.43.47:9092,192.168.43.151:9092,192.168.43.43:9092 --topic kafka1 --from-beginning
1234

Kafka常用配置项说明

配置项 默认值/示例值 说明
broker.id 0 Broker唯一标识
listeners PLAINTEXE://192.168.122.23:9092 监听信息,PLAINTEXT表示明文传输
log.dirs kafka/logs kafka数据库存放地址,可以填写多个,用","间隔
message.max.bytes message.max.bytes 单个消息长度限制,单位是字节
num.partitions 1 默认分区数
log.flush.interval.messages long.maxvalue 在数据被写入硬盘和消费者可用最大的累计消息数量
log.flush.interval.ms Long.MaxValue 在数据被写入到硬盘前的最大时间
log.flus.scheduler.interval.ms Long.MaxValue 检查数据是否写入到硬盘的时间间隔
log.retention.hours 24 控制一个log保留时间,单位: 小时

常用Message Queue对比?

RabbitMQ

RabbitMQ是使用Erlang编写的一个开源的消息队列,本身支持很多的协议: AMQP,XMPP,SMTP,STOMP,正因为如此,他非常轻量级,她更适合于企业级的开发,同时实现了Broker构架,这意味着在发送客户端时先在中心队列排队。对路由,负载均衡或者数据持久化都有很好的支持.

Redis

Redis是一个基于Key-Value对的NoSQL数据库,开发维护很活跃,虽然他是一个Key-Value数据库存储系统,但他本身支持MQ功能,所以完全可以做一个轻量级的队列服务来使用。对于RabbitMQ和Redis的入队和出队操作,各执行100万次,每10万次记录一次执行时间。测试数据分为128Bytes,512Bytes,1k和10k四个不同大小的数据。实验证明:

入队时,当数据比较小时Redis的性能高于RabbitMQ,如果数据超过了10k,Redis慢的让人无法忍受;
出队时,无论数据大小,Redis都表现非常好的性能,而RabbitMQ的出队性能则远远低于Reids.

ZeroMQ

ZeroMQ号称最快的消息队列系统,尤其针对大吞吐量的需求场景。ZeroMQ能够实现RabbitMQ不擅长的高级/复杂的队列,但是开发人员需要自己组合多种技术框架,技术上复杂度是对这MQ能够应用成功的挑战。 ZeroMQ具有一个独特的非中间件的模式,你不需要安装和运行一个消息服务器或中间件,因为你的应用程序将扮演这个角色。你只需要简单的引用ZeroMQ程序库,可以使用NuGet安装,然后你就可以愉快的在应用程序之间发送消息了。

但是ZeroMQ仅提供非持久性的队列,也就是说如果宕机,数据将会丢失,其中,Twitter的Storm 0.9.0以前的版本中默认使用ZeroMQ作为数据流的传输(Storm从0.9版本开始同时支持ZeroMQ和Netty作为传输模块).

ActiveMQ

ActiveMQ是Apache下的一个子项目,类似于ZeroMQ,它能够以代理人和点对点的技术实现队列。同时类似于RabbitMQ,他少量代码就可以高效实现高级应用场景

Kafka/Jafka

Kafka是Apache下的一个子项目,是一个高性能跨语言分布式/订阅消息队列系统,而Jafka是在Kafka之上孵化而来的,是一个Kafka的一个升级版,具有以下特性:

  1. 快速持久化,可以再O(1)的系统的开销下进行消息持久化;
  2. 高吞吐,完全的分布式系统,Broker,Producer,Consumer都原生自动支持分布式,自动实现负载均衡.
  3. 支持Hadoop数据并行加载,对于像Hadoop的一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决
  4. 方案,Kafka通过Hadoop的并行加载机制统一了在线和离线的消息处理.Apache Kafka相对于ActiveMQ是一个非常轻量级的消息系统,除了性能非常好之外,还是一个工作良好的分布式系统.

Kafka、RabbitMQ、Redis消息中间件对比

在分布式系统中、消息中间件常用于系统间的数据交换,
按照实际业务需求场景以及运维成本,可以选择适合自己的产品.

Kafka

# 1.基于Pull的模式来处理消息消费
# 2.追求高吞吐量
# 3.一开始的目的就是日志收集和传输
# 4.0.8版本开始支持复制,不支持事务,对消息的重复、丢失、错误没有严格要求、适合产生大量数据的互联网服务的数据收集业务.

RabbitMQ

RabbitMQ是使用Erlang语言开发的开源消息队列系统,基于AMQP协议来实现.
AMQP的主要特征
1.面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。
2.AMQP协议更多用在企业系统内,对数据一致性、稳定性和可靠性要求很高的场景,对性能和吞吐量的要求还在其次。
主要应用于如: dubbo框架(zookeeper用于注册中心)、spring cloud等

Redis

Redis是一个基于Key-Value对的NoSQL数据库,开发维护很活跃.
虽然他是一个Key-value数据库存储系统,但它本身支持MQ功能,所以完全可以当做一个轻量级的队列服务来使用

在应用场景方面

RabbitMQ,遵从AMQP协议,由内在高并发的erlang语言开发,用在实时的对可靠性要求比较高的消息传递上.

Kafka是Linkedin于2010年12月份开源的消息订阅系统,它主要用于处理活式的流式数据,大数据量的数据处理上.

在架构模型上

RabbitMQ遵循AMQP协议,RabbitMQ的broker由Exchange,Binding,queue组成,其中exchange和binding组成了消息的路由键;客户端Producer通过连接channel和server进行通信,Consumer从queue获取消息进行消费(长连接,queue有消息会推送到consumer端,consumer循环从输入流读取数据)。rabbitMQ以broker为中心;有消息的确认机制。

kafka遵从一般的MQ结构,producer,broker,consumer,以consumer为中心,消息的消费信息保存的客户端consumer上,consumer根据消费的点,从broker上批量pull数据;无消息确认机制。

在吞吐量方面

kafka具有高的吞吐量,内部采用消息的批量处理,zero-copy机制,数据的存储和获取是本地磁盘顺序批量操作,具有O(1)的复杂度,消息处理的效率很高。
rabbitMQ在吞吐量方面稍逊于kafka,他们的出发点不一样,rabbitMQ支持对消息的可靠的传递,支持事务,不支持批量的操作;基于存储的可靠性的要求存储可以采用内存或者硬盘。

在可用性方面

RabbitMQ支持miror的queue,主queue失效,miror queue接管
kafka的broker支持主备模式

在集群负载均衡方面

kafka采用zookeeper对集群中的broker、consumer进行管理,可以注册topic到zookeeper上;通过zookeeper的协调机制,producer保存对应topic的broker信息,可以随机或者轮询发送到broker上;并且producer可以基于语义指定分片,消息发送到broker的某分片上。
RabbitMQ的负载均衡需要单独的loadbalancer进行支持.

应用场景

rabbitmq比kafka可靠,kafka更适合IO高吞吐的处理,比如ELK日志收集
Kafka和RabbitMq一样是通用意图消息代理,他们都是以分布式部署为目的。但是他们对消息语义模型的定义的假设是非常不同的。

  • 以下场景你比较适合使用Kafka。你有大量的事件(10万以上/秒)、你需要以分区的,顺序的,至少传递成功一次到混杂了在线和打包消费的消费者、你希望能重读消息、你能接受目前是有限的节点级别高可用或则说你并不介意通过论坛/IRC工具得到还在幼儿阶段的软件的支持。

  • 以下场景你比较适合使用RabbitMQ。你有较少的事件(2万以上/秒)并且需要通过复杂的路由逻辑去找到消费者、你希望消息传递是可靠的、你并不关心消息传递的顺序、你需要现在就支持集群-节点级别的高可用或则说你需要7*24小时的付费支持(当然也可以通过论坛/IRC工具)

  • redis 消息推送(基于分布式 pub/sub)多用于实时性较高的消息推送,并不保证可靠

  • redis 消息推送(基于分布式 pub/sub)多用于实时性较高的消息推送,并不保证可靠。其他的mq和kafka保证可靠但有一些延迟(非实时系统没有保证延迟)。redis-pub/sub断电就清空,而使用redis-list作为消息推送虽然有持久化,也并非完全可靠不会丢。

  • redis是内存数据库!redis他爹做了disque,你要不要试试。mq一般都采用订阅~发布模型,如果你考虑性能,主要关注点就放在消费模型是pull还是push。影响最大的,应该是存储结构。kafka的性能要在topic数量小于64的时候,才能发挥威力。partition决定的。极限情况下丢消息,例如:主写入消息后,主机器宕机,并硬盘损坏

posted @ 2020-05-13 20:42  常见-youmen  阅读(1599)  评论(0编辑  收藏  举报