面试官:使用Kafka,如何保证消息的顺序性?
我:设置partition为1,同一个partition肯定是能保证顺序的,多个partition就保证不了了。
面试官: .........
我察言观色后,觉得,这肯定不是他想要的答案。线上谁会把partiton设置为1啊。
我:可以让需要排序的消息保证的数据,用同一个key,然后消费的时候,让同一个key的数据都走同一个partition,partition的数量=consumer的数量,让一个consumer消费一个partition。
面试官:你的回答说明你知道kafka的一些原理,但是这不是我想要的答案。我说一个实际的场景,你结合这个场景来回答。比如直播场景,用户给主播点赞,连点的话,屏幕会依次出现,1,2,3,4........显示用户最高连点赞的数。服务端接受手机客户端(android或者ios)发来的消息,有可能因为网络原因,5比4先到。我们每收到一个消息,就扔到kafka里,在consumer里调用第三方的api,让客户在屏幕上看到动效。如果手机屏幕显示完5以后,再显示4就是bug。你想想看,你的partition的方案,能解决我这个问题吗?
我想:好像真的不能,如果5先到,然后先发给消费者了,即使是同一个partiton,kafka按照offset先后排序,还是5先显示,4后显示,显然解决不了。
我:那就需要consumer消费的时候,key能让consumer感知到需要排序,消费到一个就往共享内存如redis里放,利用redis的有序集合,放的时候就排好序。然后启动一个线程,该线程的逻辑就是不断的从该有序集合里取,并调用第三方api让用户看到动效。
面试官:但是consumer有多个啊?
我:可以在启动线程之前,上一个分布式锁,如果每抢到锁,就不启动线程,只是往共享内存里放。
面试官:这个方案,可以解决我的问题,但过于复杂,还要用到redis,还要上分布式锁,能否设计的再简单点?
我:......
我:让同一个key都走同一个partition,正如我最开始说的那样,然后利用PriorityQueue,放进去再取就是有序的。再启动一个线程,一个个取出来,调用第三方api,直到取完。
网友评论