Kafka分布式的消息顺序

Kafka分布式的单位是partition,同一个partition用一个write ahead log组织,因此能够保证FIFO的顺序。不一样partition之间不能保证顺序。mysql

可是绝大多数用户均可以经过message key来定义,由于同一个key的message能够保证只发送到同一个partition,好比说key是user id,table row id等等,因此同一个user或者同一个record的消息永远只会发送到同一个partition上,保证了同一个user或record的顺序。固然,若是你有key skewness 就有些麻烦,须要特殊处理sql


Apache Kafka官方保证了partition内部的数据有效性(追加写、offset读);为了提升Topic的并发吞吐能力,能够提升Topic的partition数,并经过设置partition的replica来保证数据高可靠;并发

可是在多个Partition时,不能保证Topic级别的数据有序性。分布式

所以,若是大家就像死磕kafka,可是对数据有序性有严格要求,那我建议:大数据

  1. 建立Topic只指定1个partition,这样的坏处就是磨灭了kafka最优秀的特性。

因此能够思考下是否是技术选型有问题, kafka自己适合与流式大数据量,要求高吞吐,对数据有序性要求不严格的场景。优化



原文连接:http://www.lpnote.com/2017/01/17/sequence-message-in-kafka/this

顺序消息包括如下两方面:线程

  • 全局顺序
  • 局部顺序

全局顺序

全局顺序就目前的应用范围来说,能够列举出来的也就限于binlog日志传输,如mysql binlog日志传输要求全局的顺序,不能有任何的乱序。这种的解决办法一般是最为保守的方式:日志

  1. 全局使用一个生产者
  2. 全局使用一个消费者(并严格到一个消费线程)
  3. 全局使用一个分区(固然不一样的表可使用不一样的分区或者topic实现隔离与扩展)

局部顺序

其实在大部分业务场景下,只须要保证消息局部有序便可,什么是局部有序?局部有序是指在某个业务功能场景下保证消息的发送和接收顺序是一致的。如:订单场景,要求订单的建立、付款、发货、收货、完成消息在同一订单下是有序发生的,即消费者在接收消息时须要保证在接收到订单发货前必定收到了订单建立和付款消息。文档

针对这种场景的处理思路是:针对部分消息有序(message.key相同的message要保证消费顺序)场景,能够在producer往kafka插入数据时控制,同一key分发到同一partition上面。由于每一个partition是固定分配给某个消费者线程进行消费的,因此对于在同一个分区的消息来讲,是严格有序的(在kafka 0.10.x之前的版本中,kafka因消费者重启或者宕机可能会致使分区的从新分配消费,可能会致使乱序的发生,0.10.x版本进行了优化,减小从新分配的可能性)。

注意事项

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

对于一个有着前后顺序的消息A、B,正常状况下应该是A先发送完成后再发送B,可是在异常状况下,在A发送失败的状况下,B发送成功,而A因为重试机制在B发送完成以后重试发送成功了。
这时对于自己顺序为AB的消息顺序变成了BA

消息producer发送逻辑的控制

消息producer在发送消息的时候,对于同一个broker链接是存在多个未确认的消息在同时发送的,也就是存在上面场景说到的状况,虽然A和B消息是顺序的,可是因为存在未知的确认关系,有可能存在A发送失败,B发送成功,A须要重试的时候顺序关系就变成了BA。简之一句就是在发送B时A的发送状态是未知的。
针对以上的问题,严格的顺序消费还须要如下参数支持:max.in.flight.requests.per.connection
这个参数官方文档的解释是:

The maximum number of unacknowledged requests the client will send on a single connection before blocking. Note that if this setting is set to be greater than 1 and there are failed sends, there is a risk of message re-ordering due to retries (i.e., if retries are enabled).

大致意思是:

在发送阻塞前对于每一个链接,正在发送可是发送状态未知的最大消息数量。若是设置大于1,那么就有可能存在有发送失败的状况下,由于重试发送致使的消息乱序问题。因此咱们应该将其设置为1,保证在后一条消息发送前,前一条的消息状态已是可知的。

相关文章
相关标签/搜索