为什么需要消息系统
- 解耦
- 业务逻辑更简单 中间件替换成本低
- 冗余
- 扩展性
- 不需要考虑 扩展性问题 例如后端处理负载高的问题
- 灵活性 & 峰值处理能力
- 可恢复性 可以备份恢复消息
- 顺序保证
- 缓冲
- 异步处理
- 消息通信
不同的订阅端 消费不同的主题
针对不同的业务 进行适配
- 离线业务 离线处理
- 在线数据流
消息系统
现在比较流行的MQ有:ActiveMQ、Kafka、RabbitMQ、Redis、Jafka、ZeroMQ
Kafka 兼具消息队列 和日志聚合的场景
RabbitMQ
- RabbitMQ是使用Erlang编写的一个开源的消息队列,本身支持很多的协议:
- AMQP、XMPP、SMTP、STOMP,也正因如此,它非常重量级,更适合于企业级的开发。
- 同时实现了Broker构架,这意味着消息在发送给客户端时先在中心队列排队。
- 对路由、负载均衡或者数据持久化都有很好的支持
ZeroMQ
• ZeroMQ号称最快的消息队列系统,尤其针对大吞吐量的需求场景。
• ZeroMQ能够实现RabbitMQ不擅长的高级/复杂的队列,但是开发人员需要自己组合多种技术框架。
• 但是ZeroMQ仅提供非持久性的队列,也就是说如果宕机,数据将会丢失。
ActiveMQ
• ActiveMQ是Apache下的一个子项目。 类似于ZeroMQ,它能够以代理人和点对点的技术实现队列。
• 同时类似于RabbitMQ,它少量代码就可以高效地实现高级应用场景
生产者/消费者模型
在生产者/消费者模型中,生产者Producer负责生产数据,而消费者Consumer负责
使用数据。多个生产者会在同一时间生产数据,并放到内存中一个共享的区域
Kafka系统架构和原理
Topics 、Append Log
- Kafka提供的一个抽象的 主题概念:topic
- 一个topic是对一组消息的归纳 其实对应一个业务流
- 每个topic将被分成多个partition 分区
- 每个partition会生成一个append log文件
- 每条消息在文件中的位置称为offset(偏移量),唯一标记一条消息
Producer和Consumer
两个API 录入数据 消费数据
-
Producer即生产者,向Kafka集群发送消息,消息会安装Topic进行分类
-
Consumer即消费者,消费者通过与Kafka集群建立长连接的方式,不断地从集群中拉取消息,然后可以对这些消息进行处理
- 它需要保存消费消息的offset:当consumer正常消费消息时,offset将会“线性”的增加,即消息将依次顺序被消费
- 通过设置offset consumer可以从任意位置消费消息
-
Consumer可以在本地保存最后消息的offset,并向ZooKeeper注册offset
Consumer Group
这是Kafka用来实现一个topic消息广播的手段。即多个不同的group来同时消费同一个topic下的消息。他们消费的offset各不相同,各不干扰。 实现了隔离性
一个group中,Consumer的数量不应该多于Partition的数量,即一个消费者可以消费多个分区,但一个分区只能给一个消费者消费。
注意 若一个group中的消费者数量大于Partition数量的话,多余的消费者将不会收到任何消息
- 例如partition只有3个 但是consumer有4个 所以至少有一个是拿不到数据的
约束
同一个Consumer Group 一个Partition只能对应一个Consumer 但是一个Consumer 可以对应多个Partition
Broker
消息保存在一组服务器中,它们被称为代理(Broker)或Kafka集群
- 每个Broker有一个Broker id
- 每个Broker存储Topic的部分数据
Kafka的存储文件
按照offset.kafka来命名,用offset做名字的好处是方便查找。
例如 你想找位于2049的位置,只要找到2048.kafka的文件即可。第一个个存储文件是00000000000.kafka
整体架构图
一个topic可以划分 多个 partition切片
- 每个partition切片 可以 复制多个 replica副本
- 每个replica副本 分布在不同的节点
- replica副本 之间有主从之分 leader和follower(主从关系)
ZK的作用
- 当Consumer Group 挂掉时, 需要保存已经消费的offset 不然恢复后怎么办?
commit offset操作 将offset记录到ZK中
- ZK 还要记录集群状态信息 leader和follower(主从关系)
replica副本
0.8版本后 加入了 replica副本
类似主动复制 写的时候 只写 leader 然后会把数据同步到follower 读的时候 leader和follower
Kafka将每个partition数据复制到多个server上,任何一个partition有一个leader和零个或多个follower(ISR),称为partition的副本(replica)。
Leader处理所有的读写请求,follower需要和leader保持同步。Follower和consumer一样,消费消息并保存在本地日志中
当所有的follower都将一条消息保存成功,此消息才被认为是“committed”。只有committed的消息,consumer才能消费它。
问题 当leader失效时,需在followers中选取出新的leader。可能此时follower落后于leader,因此需要选择一个尽可能“新”的follower
消费传输机制
生产者发送消息到 kafka时 会有2阶段提交问题
先保存offset 还是 先处理消息, 任何一个地方出现问题 都会导致丢数据 或者 数据重复消费的问题
at most once
消息最多发生一次,无论消费者是否接受到,都不会重发。
消费者fetch消息,先保存消息的offset,然后处理消息。
问题 当消费者保 存offset之后,但是在消息处理过程中出现了异常,导致部分消息未能继续处理。
那么此后“未处理”的消息将不能被fetch到,这就是“at most once”。
at least once
消息至少发送一次,如果消息未能接受成功,会重发直到接收成功。
消费者fetch消息,先处理消息,然后保存offset。
问题 如果消息处理成功之后,但是在保存offset阶段,ZooKeeper异常导致保存操作未能执行成功,这就导致接下来再次fetch时可能获得上次已经处理过的消息,这就是“at least once”。
exactly once
消息只会发送一次。
容灾
多副本机制可以保证数据 可用
如果宕机节点上的replica是leader 那么就会重新选举 尽可能新的leader