DDIA读书笔记 第十一章-1.消息队列
消息队列
一个主题多个消费者
2种模式
-
load balance
-
一个消息只被其中的一个消费者使用
-
-
fan-out
-
一个消息被所有的消费者使用
-
2种模式可以配合使用,比如kafka 的消费组间和组内消费者间。
对待数据的2种思维:
消息传递:消息的存活应该是短暂的,在送达消费者之后,就应该立即删除
数据库与文件系统: 数据的存活应该是持久的,在被显式删除之前,都应该是永久记录的
2种思维的结合,产生了 基于日志的消息代理(log-baseed message)
日志: 磁盘上简单的追加记录序列
基于日志的消息代理:
基本原理:
-
生产者:通过将消息追加到日志末尾来发送消息
-
消费者:通过依次读取日志来接收消息;遇到文件末尾则等待新消息追加的通知 (类比 tailf )
优化:
-
提高吞吐量:
-
对日志进行分区,将不同的分区托管在不通的日志,且每个分区都拆分出能独立读写的日志
-
一个主题可以定义为一组携带相同类型的分区
-
每个分区内,为每个消息分配一个递增的序列号或偏移量:
-
保证了分区内的有序性
-
代理不需要跟踪确认每条消息,只需要记录每个消费者的偏移即可
-
减少了簿记开销,而且在批处理和流处理中采用这种方法有助于提高基于日志的系统的吞吐量
-
这种方式,与单领导者数据库复制种的日志序列号非常相似
-
在数据库复制中,日志序列号允许跟随者断开连接后,重新连接到领导者,并在不跳过任何写入的情况下恢复复制
-
这里原理完全相同:消息代理的表现得像一个主库,而消费者就像一个从库。
-
Raft 的复制状态机机制,也是同样的原理
-
-
-
-
磁盘空间使用
-
将日志分割成段,并不时地将旧段删除或者移动到归档存储
-
Ring Buffer日志实现了一个有限大小(在磁盘中,可以很大)的缓冲区,当缓冲区满时会丢弃旧数据
-
当消费者跟不上生产者时
三种选择:丢弃信息,进行缓冲或施加背压
日志型消息队列的做法:
软性的背压:监控消费者落后日志头部的距离,超过阈值就报警
重播旧消息
消费行为的副作用:
传统的消息队列:处理和确认消息之后,消息会被销毁
日志型消息队列:从文件中顺序读取数据,只读操作,不会更改日志
所以日志型消息队列,可以方便的对旧数据进行重复利用,是集成数据流的更可靠的工具
-
允许进行更多的实验,更容易
-
更容易从故障中恢复
其他
webhook
如果消费者在网络上公开了服务,生产者可以直接发送HTTP或RPC请求将消息推送给使用者。这就是webhooks背后的想法,一种服务的回调URL被注册到另一个服务中,并且每当事件发生时都会向该URL发出请求