首先来看什么是消息系统?简单来讲就是生产者发送包含事件的消息给消息系统,然后将消息推送给消费者。消息系统有很多种,最简单的就是TCP连接这种的直接信道,之后出现的消息系统大多都是在这个模型上构建的,只不过TCP是生产者和消费者一对一,更完善的消息系统是多对多的形式。
如果让你来设计消息系统
带着这些问题继续下去
这个算是最简单粗暴的处理方式,消息不经过中间节点。但是这个需要生产者和消费者考虑消息丢失的可能性,在消息处理的过程种需要生产者和消费者长期保持在线,一旦有一方不在线,消息便会丢失无法找回。所以这个时候需要消息代理使得消费者和生产者解耦。
代表系统:UDP,ZeroMQ
消息代理实质上是一种针对处理消息流而优化的数据库。 它作为服务器运行,生产者和消费者作为客户端连接到服务器。生产者将消息写入代理,消费者通过从代理那里读取来接收消息,使得生产者和消费者可以顺利解耦。消息的持久性以及消费消息速度过缓的问题也交给了消息代理去解决。这样的后果就是生产者和消费者不再是同步处理数据,而是异步,生产者产生完消息后可以不用再管消费者是否消费。
两者的区别在于load balance当一个客户端消费完一条消息后,这条消息不会再被其它客户端消费,但是fan-out则是一个消息可以让多个客户端同时消费到。
为了防止消费者消费过程种出现问题,一般的消费代理都会有确认机制,只有当消费者发回确认消息后,消息才会被删除,否则就有可能等待另一个消费消费。这里会出现一个问题,当使用load balanc时,会出现消息乱序的情况。
代表系统:RabbitMQ
前面的文章提过日志是只增不减的有序序列,在消息系统里,日志也可以成为消息的存储媒介,最新的消息永远是日志的最后,消费者只要记住自己的读取的位移,不断往后移就可以读到最新的消息,而日志也带给了消息系统真正的消息持久化,消费者可以持续的从某个时间段抽取数据。为了提高吞吐量,日志也可以做分区,每一个主题包含一定数量的分区,分区也可以分布在各个不同的机器上。
因为日志的读取方式,所以天然支持fan-out的发送方式,为了支持load balance,可以将整个分区丢给消费者组。但是这要求消费者必须以单线程消费数据,从而降低了性能。
代表系统:Kafka
因此在消息处理代价高昂,希望逐条并行处理,以及消息的顺序并没有那么重要的情况下, 可以使用JMS/AMQP风格的消息代理。另一方面,在消息吞吐量很高,需要处理迅速,顺序很重要的情况下,基于日志的方法值得选择。