前言
kafka可以保证同一个partition的消息的有序性,不能保证不同partition消息的有序性。
为什么kafka不设计成不同partition消息的有序性?
如果要保证多个partition有序,那么既要保证broker保存消息的顺序,又要保证消费消息时的顺序。如果partition1堵了,为了保证消费的有序性,其它partition都只能等待了,这样kafka的多partition还有什么意义呢。
kafka producer 发送消息时,是如何确保单一partition的有序性的?
加锁

结合我们自己的业务场景,可以在发送消息时,想保证顺序的同一批数据指定相同的message key,因为kafka可以保证相同的key进入同一partition。
比如,用kafka发送GPS数据时,有三个参数(partition key message),其中partition和key是可选的,我们可以通过指定partition或者指定key为gps设备的imei号,这两者都可以保证同一台gps设备的数据进入同一个partition。
并且kafka也保证了消费端同一个partition的消息只被一个Consumer消费。
牺牲性能的做法
当然,我们也可以在创建topic时,只指定一个partition,这样也能保证消息的有序性,不过这样就浪费了kafka的分布式高吞吐的特性,所以不推荐这样做。
消息发送失败,重试机制启动的情况下,如何保证消息的有序性?
正常的理想状态下,上面的配置的确没问题,可是有时,我们还需要考虑消息发送失败的情况。
一般我们会设置重试机制来解决消息发送的问题,如果是非临时性错误导致的消息发送失败(如消息体过大),那么再怎么重试也是没有意义的。如果是临时性错误导致消息发送失败(如网络抖动或分区找不到首领),那么可以设置producer的retries,该值默认是0,比如设置3,重试3次。但是这样可能就会造成乱序的问题,比如消息A先发送,但是发送失败了,等消息B发完后,消息A又重试成功了,这就造成了message A 和 B 的乱序。
如何解决呢?
可以借助 max.in.flight.requests.per.connection 配置项来解决,该参数指定了生产者在收到服务器响应前可以发送几个消息。该值默认是5。它的值越高,吞吐量就越高,但是也越占内存。我们可以把它设为1,这样就保证了即使发生重试,消息也会严格的有序。
但是,还是老问题,高可靠性和高性能,择其一必然会舍其一,这样的配置可以保证消息的可靠性,但是性能也会下降。
0.11版本后,kafka引入事务机制可保证producer挂掉重启后依然保证有序。