一:消息队列
1.1:什么是消息队列
消息(Message)是指在应用间传送的数据。消息队列(Message Queue)是一种应用间的通信方式解决方法,确保消息的可靠传递
1.2:消息队列的特征
( 1 ) 存储
与依赖于使用套接字的基本TCP 和UDP 协议的传统请求和响应系统不同, 消息队列通常将消息存储在某种类型的缓冲区中, 直到目标进程读取这些消息或将其从消息队列中显式移除为止。
( 2 ) 异步
与请求和响应系统不同, 消息队列通过缓冲消息可以在应用程序中公开一定程度的异步性, 允许源进程发送消息并在队列中累积消息,而目标进程则可以挑选消息进行处理。这样, 应用程序就可以在某些故障情况下运行, 例如连接断断续续或源进程或目标进程故障。
路由: 消息队列还可以提供路由功能,其中多个进程可以在同一队列中读取或写入消息, 从而实现广播或单播通信模式。
二:Kafka 基础与入门
2.1: kafka 基本概念
kaf ka 是Apache 组织下的一个开源系统, 它的最大的特性就是可以实时的处理大呈数据以满足各种需求场景: 比如基于hadoop 平台的数据分析、低时延的实时系统、st orm/ s park 流式处理引擎等。ka f ka 现在已被多家大型公司作为多种类型的数据管道和消息系统使用。
2.2:kafka 角色术语
kaf ka 的一些核心概念和角色
(1) Broker : Kafka 集群包含一个或多个服务器, 每个服务器被称为broker (经纪人) 。
(2) Topic: 每条发布到Kafka 集群的消息都有一个分类, 这个类别被称为Topic (主题) 。
(3) Producer: 指消息的生产者, 负责发布消息到kafka broker 。
(4) Consum er: 指消息的消费者, 从kafka broker 拉取数据,并消费这些已发布的消息。
(5) Partition: Partition 是物理上的概念, 每个Topic 包含一个或多个Partition , 每个partition 都是一个有序的队列。partiti on 中的每条消息都会被分配一个有序的id( offset ) 。
(6) Consumer Group: 消费者组, 可以给每个Consumer 指定消费组, 若不指定消费者组, 则属
于默认的group 。
(7) Message: 消息,通信的基本单位, 每个producer 可以向一个topic 发布---些消息。
2.3:kafka 拓扑架构
一个典型的Kafka 媒群包含若千Producer , 若干broker 、若千Con s umer Group , 以及一个Zoo keeper 集群。Kafka 通过Zookee per 管理集群配置, 选举leader , 以及在Consumer Group
发生变化时进行rebalance 。Producer 使用push 模式将消息发布到broker , Consumer 使用p ull
模式从broker 订阅并消费消息。典型架构如下图所示:
从图中可以看出, 典型的消息系统有生产者( Producer ) , 存储系统( broker ) 和消费者( Consumer ) 组成, Kafka 作为分布式的消息系统支持多个生产者和多个消费者, 生产者可以将消息分布到共群中不同节点的不同Partiti on 上, 消费者也可以消费集群中多个节点上的多个Partitiono 在写消息时允许多个生产者写到同一个Partition 中, 但是读消息时一个Partition只允许被一个消费组中的一个消费者所消费, 而一个消费者可以消费多个Partition 。也就是说同一个消费组下消费者对Partition 是互斥的, 而不同消费组之间是共享的
kafka 支持消息持久化存储, 持久化数据保存在kafka 的日志文件中, 在生产者生产消息后,kaf ka 不会直接把消息传递给消费者,而是先要在bro ker 中进行存储, 为了减少磁盘写入的次数,
broker 会将消息暂时缓存起来, 当消息的个数或尺寸、大小达到---定阀值时, 再统一写到磁盘上,这样不但提高了kaf ka 的执行效率, 也减少了磁盘IO 调用次数。
kaf ka 中每条消息写到partiti on 中, 是顺序写入磁盘的, 这个很重要, 因为在机械盘中如果是随机写入的话, 效率将是很低的,但是如果是顺序写入, 那么效率却是非常高, 这种顺序写入磁
盘机制是kafka 高吞吐率的一个很重要的保证。
2.4:Topic 和partition
Kafka 中的topic (主题)是以partition 的形式存放的,每一个topic 都可以设置它的partition 数星, Partition 的数呈决定了组成topi c 的log 的数星。推荐partition 的数呈一定要大于同时运行的consumer 的数呈。另外, 建议par tition 的数呈要小于等于媒群broker 的数显, 这样消息数据就可以均匀的分布在各个broker 中那么, Topi c 为什么要设置多个Partiti on 呢, 这是因为ka fk a 是基于文件存储的, 通过配置多个partiti on 可以将消息内容分散存储到多个broker 上, 这样可以避免文件尺寸达到单机磁盘的上限。同时, 将一个t o pi c 切分成任意多个partitions , 可以保证消息存储、消息消费的效率, 因为越多的partitions 可以容纳更多的consumer , 可有效提升Ka于ka 的吞吐率。因此,将Topi c 切分成多个partiti ons 的好处是可以将大星的消息分成多批数据同时写到不同节点上, 将写请求分担负载到各个栠群节点。
在存储结构上, 每个partiti on 在物理上对应一个文件夹, 该文件夹下存储这个partition的所有消息和索引文件。partit on 命名规则为t opi c 名称+序号, 第一个partit on 序号从0 开始,序号最大值为partitions 数量减1 。
在每个partition ( 文件夹) 中有多个大小相等的segment( 段) 数据文件, 每个segmen t 的大
小是相同的,但是每条消息的大小可能不相同,因此segment < br/>数据文件中消息数呈不一定相
等。segment 数据文件有两个部分组成, 分别为index file 和dat a fil e, 此两个文件是一一对应, 成对出现,后缀" . i ndex"和".lo g"分别表示为segment 索引文件和数据文件。
2.5:Consumer 消费机制
Kafka 发布消息通常有两种模式: 队列模式( queuing )和发布/ 订阅模式(publish-subscri be ) 。在队列模式下, 只有一个消费组, 而这个消费组有多个消费者, 一条消息只能被这个消费组中的一个消费者所消费; 而在发布/ 订阅模式下,可有多个消费组, 每个消费组只有一个消费者, 同一条消息可被多个消费组消费。
Kafka 中的Producer 和consumer 采用的是push 、pull 的模式, 即producer 向broker 进行push 消息, comsumer 从bork 进行pull 消息, push 和p ull 对于消息的生产和消费是异步进行的。pull 模式的一个好处是consumer 可自主控制消费消息的速率, 同时consumer 还可以自己控制消费消息的方式是批呈的从broker 拉取数据还是逐条消费数据。
三:zookeeper 概念介绍
ZooKeeper 是一种分布式协调技术, 所谓分布式协调技术主要是用来解决分布式环境当中多个进程之间的同步控制, 让他们有序的去访问某种共享资源, 防止造成资源竞争(脑裂)的后果。脑
裂是指在主备切换时, 由于切换不彻底或其他原因, 导致客户端和Slave 误以为出现两个activemaster , 最终使得整个集群处于混乱状态
目前, 在分布式协调技术方面做得比较好的有Google 的Chubby, 还有Apache 的ZooKeeper ,它们都是分布式锁的实现者。ZooKeeper 所提供锁服务在分布式领域久经考验, 它的可靠性、可用
性都是经过理论和实践验证的。ZooKeeper 是一种为分布式应用所设计的高可用、高性能的开源协调服务,它提供了一项基本服务: 分布式锁服务,同时,也提供了数据的维护和管理机制, 如: 统一命名服务、状态同步服务、集群管理、分布式消息队列、分布式应用配置项的管理等等
3.1:zookeeper 的工作原理
( 1 ) master 启动
在分布式系统中引入Zoo kee per 以后, 就可以配置多个主节点, 这里以配置两个主节点为例,假定它们是主节点A 和主节点B , 当两个主节点都启动后, 它们都会向ZooKeeper 中注册节点信息
我们假设主节点A 锁注册的节点信息是master00001 , 主节点B 注册的节点信息是master00002 , 注册完以后会进行选举, 选举有多种算法, 这里以编号最小作为选举算法为例,编号最小的节点将在选举中获胜并获得锁成为主节点, 也就是主节点A 将会获得锁成为主节点, 然后主节点B 将被阻塞成为一个备用节点。这样,通过这种方式Zoo kee per 就完成了对两个Master进程的调度。完成了主、备节点的分配和协作。
( 2 ) master 故障
如果主节点A 发生了故障, 这时候它在Zoo Kee per 所注册的节点信息会被自动删除,ZooKeeper 会自动感知节点的变化,发现主节点A 故障后,会再次发出选举, 这时候主节点B 将在选举中获胜, 替代主节点A 成为新的主节点,这样就完成了主、被节点的重新选举。
( 3 ) mast er 恢复
如果主节点恢复了,它会再次向Zoo Kee per 注册自身的节点信息, 只不过这时候它注册的节点信息将会变成mas ter00003, 而不是原来的信息。ZooKee per 会感知节点的变化再次发动选举,
这时候主节点B 在选举中会再次获胜继续担任主节点, 主节点A 会担任备用节点。zookeeper 就是通过这样的协调、调度机制如此反复的对梊群进行管理和状态同步的。
3.2:zookeeper 集群架构
zookeeper 一般是通过集群架构来提供服务的, 下图是zookeeper 的基本架构图。
zoo kee per 集群主要角色有server 和c li ent , 其中server 又分为leader 、follower 和observer 三个角色,每个角色的含义如下:
Leader: 领导者角色, 主要负责投票的发起和决议, 以及更新系统状态。
follower: 跟随着角色,用于接收客户端的请求并返回结果给客户端, 在选举过程中参与投票。
observer: 观察者角色, 用户接收客户端的请求, 并将写请求转发给leader , 同时同步leader状态, 但是不参与投票。Observer 目的是扩展系统, 提高伸缩性。
client: 客户端角色, 用于向zookeeper 发起请求。
3.3:zookeeper 的工作流程
Zookeeper 修改数据的流程: Zookeeper 集群中每个Server 在内存中存储了---份数据, 在Zookeeper 启动时, 将从实例中选举一个Server 作为leader , Leader 负责处理数据更新等橾作,
当且仅当大多数Server 在内存中成功修改数据, 才认为数据修改成功。
Zookeeper 写的流程为: 客户端Cl i ent 首先和一个Server 或者Observe 通信, 发起写请求,然后Server 将写请求转发给Leader , Leader 再将写请求转发给其它Server , 其它Server 在接收到写请求后写入数据并响应Leader , Leader 在接收到大多数写成功回应后, 认为数据写成功,最后响应Client, 完成一次写操作过程。
四:Zookeeper 在Kafka 中的作用
1: Broker 注册
Broker 是分布式部署并且相互之间相互独立, 但是需要有一个注册系统能够将整个集群中的Broker 管理起来, 此时就使用到了Zookeeper 。在Zookeeper 上会有一个专门用来进行Broker
服务器列表记录的节点:
/ brokers/ids
每个Broker 在启动时, 都会到Zookee per 上进行注册, 即到/ brokers / ids 下创建属于自己的节点, 如/ brokers / ids / [0... N] 。Kafka 使用了全局唯一的数字来指代每个Broker 服务器, 不同的Broker 必须使用不同的BrokerID 进行注册, 创建完节点后, 每个Broker 就会将自己的IP 地址和端口信息记录到该节点中去。其中, Broker 创建的节点类型是临时节点,一旦Broker 宥机,则对应的临时节点也会被自动删除。
2: Topic 注册
在Kafka 中,同一个To pic 的消息会被分成多个分区并将其分布在多个Broker 上, 这些分区信息及与Broker 的对应关系也都是由Zoo kee per 在维护, 由专门的节点来记录,如:
/ barkers/ t opics
Kaf ka 中每个Topic 都会以/ brokers / t o pi cs / [ t opi c] 的形式被记录, 如/ brokers /to pi cs /lo gin 和/ brokers / t o pi cs /s earch 等。Broker 服务器启动后,会到对应Topi c 节点( / brokers/to pi cs ) 上注册自己的Broker ID 并写入针对该Topi c 的分区总数,如/ brokers /to pi cs /lo gi n/3->2 , 这个节点表示Broker ID 为3 的一个Broker 服务器, 对于"lo gin" 这个Topi c 的消息,提供了2 个分区进行消息存储,同样,这个分区节点也是临时节点。
3: 生产者负载均衡
由于同一个Topic 消息会被分区并将其分布在多个Broker 上,因此,生产者需要将消息合理地发送到这些分布式的Broker 上,那么如何实现生产者的负载均衡, Kaf ka 支持传统的四层负载均衡,也支持Zookeeper 方式实现负载均衡。
(1) 四层负载均衡
根据生产者的IP 地址和端口来为其确定一个相关联的Broker 。通常, 一个生产者只会对应单个Broker , 然后该生产者产生的消息都发往该Broker 。这种方式逻辑简单, 每个生产者不需要同其他系统建立额外的TCP 连接,只需要和Broker 维护单个TCP 连接即可。但是, 其无法做到真正
的负载均衡, 因为实际系统中的每个生产者产生的消息显及每个Broker 的消息存储星都是不一样
的, 如果有些生产者产生的消息远多于其他生产者的话,那么会导致不同的Broker 接收到的消息
总数差异巨大, 同时, 生产者也无法实时感知到Broker 的新增和删除。
(2) 使用Zookeeper 进行负载均衡
由于每个Broker 启动时, 都会完成Broker 注册过程, 生产者会通过该节点的变化来动态地感知到Broker 服务器列表的变更,这样就可以实现动态的负载均衡机制。
4: 消费者负载均衡
与生产者类似, Ka f ka 中的消费者同样需要进行负载均衡来实现多个消费者合理地从对应的Broker 服务器上接收消息,每个消费者分组包含若干消费者,每条消息都只会发送给分组中的一个消费者, 不同的消费者分组消费自己特定的Topic 下面的消息, 互不干扰。
5: 记录消息分区与消费者的关系
消费组(Consumer Grou p) 下有多个Consumer (消费者)。对于每个消费者组(Consumer Group) , Kafka 都会为其分配一个全局唯---的Grou p ID, Grou p 内部的所有消费者共享该ID 。订阅的topic 下的每个分区只能分配给某个group 下的一个consumer ( 当然该分区还可以被分配给其他group )
同时, Kafka 为每个消费者分配一个Consumer ID , 通常采用"Hostname : UUID" 形式表示。在Kafka 中, 规定了每个消息分区只能被同组的一个消费者进行消费, 因此, 需要在Zookeeper 上记录消息分区与Consumer 之间的关系, 每个消费者一旦确定了对一个消息分区的消费权力, 需要将其Consumer ID 写入到Zoo kee per 对应消息分区的临时节点上, 例如:/ consumers/ [group_id] / owners/ [ t opic] / [broker_i d-partition_i d]其中, [ broker_i d- partiti on_id] 就是一个消息分区的标识, 节点内容就是该消息分区上消费者的Consumer ID 。
6: 消息消费进度Offset记录
在消费者对指定消息分区进行消息消费的过程中, 需要定时地将分区消息的消费进度Off set
记录到Zoo kee per 上, 以便在该消费者进行重启或者其他消费者重新接管该消息分区的消息消费后,能够从之前的进度开始继续进行消息消费。Offset 在Zoo kee per 中由一个专门节点进行记录, 其节点路径为:/ consumers/ [ g rou p_id ] / o 于f set s / [ topic ] / [broker_id- partiti on_id]节点内容就是Offset 的值。
7: 消费者注册
消费者服务器在初始化启动时加入消费者分组的步骤如下:
(1 )注册到消费者分组
每个消费者服务器启动时,都会到Zoo kee pe r 的指定节点下创建一个属千自己的消费者节点,例如/ con s umers / [ g rou p_i d] / i ds / [consumer_id] , 完成节点创建后, 消费者就会将自己订阅的Topi c 信息写入该临时节点。
( 2 ) 对消费者分组中的消费者的变化注册监听
每个消费者都需要关注所属消费者分组中其他消费者服务器的变化情况,即对/con s umer s/ [ g rou p_id ] / i d s 节点注册子节点变化的Wat cher 监听,一旦发现消费者新增或减少,就触发消费者的负载均衡。
( 3 ) 对B rok er 服务器变化注册监听
消费者需要对/ broker/ ids / [0- N ] 中的节点进行监听,如果发现Bro ker 服务器列表发生变化,那么就根据具体情况来决定是否需要进行消费者负载均衡。
( 4 ) 进行消费者负载均衡
为了让同一个Topi c 下不同分区的消息尽呈均衡地被多个消费者消费而进行消费者与消息分区分配的过程, 通常, 对于一个消费者分组, 如果组内的消费者服务器发生变更或Broker 服务器发生变更, 会发出消费者负载均衡。