💧 Posted on 

[转] kafka 如何体现消息的顺序性

顺序消息包括以下两方面:

  • 全局顺序
  • 局部顺序

全局顺序

全局顺序,这种要求比较严格。例如Mysql数据库中的binlog日志传输:mysql binlog日志传输要求全局的顺序,不能有任何的乱序。

这种的解决办法通常是最为保守的方式:

  • 全局使用一个生产者
  • 全局使用一个消费者(并严格到一个消费线程)
  • 全局使用一个分区(当然不同的表可以使用不同的分区或者topic实现隔离与扩展)

局部顺序

在大部分业务场景下,只需要保证消息局部有序即可,什么是局部有序?

局部有序是指在某个业务功能场景下保证消息的发送和接收顺序是一致的。如:订单场景,要求订单的创建、付款、发货、收货、完成消息在同一订单下是有序发生的,即消费者在接收消息时需要保证在接收到订单发货前一定收到了订单创建和付款消息。

kafka 中消息顺序性的保障

Kafka只能保证单分区内消息顺序有序,无法保证全局有序(同一topic的消息有序)

Apache Kafka官方保证了partition内部的数据有效性(追加写、offset读);为了提高Topic的并发吞吐能力,可以提高Topic的partition数,并通过设置partition的replica来保证数据高可靠,但是在多个Partition时,不能保证Topic级别的数据有序性。

  • 生产者:通过分区的leader副本负责数据顺序写入,来保证消息顺序性
  • 消费者:同一个分区内的消息只能被一个group里的一个消费者消费,保证分区内消费有序

针对这种场景的处理思路是:

  1. topic设置一个分区,发送端和消费端开启多线程生产和消费

优缺点:

  • 实现简单
  • 容易遇到瓶颈,服务端压力大
  1. topic设置多个分区,自定义发送端的分区策略,数据发送到同一个分区中,消费端开启多线程消费

优缺点:

  • 扩展多个分区分摊了非同类数据写入同个分区的压力
  • 相同业务的数据在同一个分区依然有热点瓶颈的问题
  1. topic设置多个分区,自定义发送端的分区策略,数据发送不同分区,消费时按发送分区的顺序消费,发送和消费端都启动多线程来提高并发度

  2. 自义分区器,使得消息按分区号大小顺序依次发送相同数量大小的数据

  3. 发送端和消费端启动多个消费线程进行生产和消费

  4. 线程之间按分区号大小顺序消费数据

优缺点:

  • 消费性能极大下降,无法真正并发

消息重试对顺序消息的影响

对于一个有着先后顺序的消息A、B,正常情况下应该是A先发送完成后再发送B,但是在异常情况下,在A发送失败的情况下,B发送成功,而A由于重试机制在B发送完成之后重试发送成功了。这时对于本身顺序为AB的消息顺序变成了BA
消息producer在发送消息的时候,对于同一个broker连接是存在多个未确认的消息在同时发送的,也就是存在上面场景说到的情况,虽然A和B消息是顺序的,但是由于存在未知的确认关系,有可能存在A发送失败,B发送成功,A需要重试的时候顺序关系就变成了BA。简之一句就是在发送B时A的发送状态是未知的。针对以上的问题,严格的顺序消费还需要以下参数支持:max.in.flight.requests.per.connection