新闻资讯

身为一名程序员,如何在双十一避免数据重复消费之坑吗?
北大青鸟总部

摘要:身为一名程序员,如何在双十一避免数据重复消费之坑吗?

在业务系统的开发当中,为了保障系统的高性能、高可用,基本都会使用分布式架构,采用消息队列将生产者(响应调用的服务)与消费者(发起调用的服务)进行解耦,让生产者服务和消费者服务可以并行处理更多的程序调用、用户请求。当消息队列遇上分布式,就变成了分布式消息队列,也就是说请求在消费队列发给了多个服务器节点,所有服务器节点的消息队列之和就是请求数。在分布式中最高频的问题便是数据一致性问题,多个服务器节点因为时间空间的不一致从而接收到的数据、传出去的数据都不一样,在消息队列中最高频的问题便是生产消费不一致,从而导致数据丢失等。分布式遇上消息队列,我们一起来看看存在哪些坑,又如何避免这些坑

TIM截图20200813095819.png

01数据重复消费之坑

在Kafka消息队列的设计中,系统通过偏移量offset来标记消息的顺序。生产者服务将消息写进队列,消费者从队列里拿消息进行消费,消费成功后将偏移量提交,下次再消费时就从最新的偏移量开始消费数据。在分布式消息队列中,有可能会出现这样的情况,生产者往队列中写进去了2条数据,比如数据1偏移量为1,数据2偏移量为2,消费者从队列里先消费了偏移量1,偏移量1提交成功,正要去消费数据2时,出现了断电或进程中断等问题导致系统重启后,再去消费了数据2,这样就导致数据被重复消费了。我们可通过一个简单的例子来看看:

双十一大促的时候,iPhone12在淘宝售卖,Alice提交了订单1进行支付购买,Bob也提交了订单2进行支付购买,并且他们都购买成功了,订单系统会把所有成功的订单信息都放在消息队列,用以购买成功后系统会给用户推送消息,推送消息的服务从队列里拿消息进行消费,它先拿了消息1,给Alice推送了成功购买的信息,并且标记已成功处理消息,正当它继续去拿消息2推送时,已经推送成功了,但是在标记推送成功时断电了,等系统重启后,消息推送系统又再次从消息2开始处理,重新推送消息。对于Bob来说,他就收到了两条重复消息,如果系统程序老出问题,他就会一直收到重复消息,这样的用户体验非常不好。

避坑指南来了,那就是通过程序算法解决。当用户下订单支付成功后,订单的状态会由开始变为支付成功或待配送,消息推送系统再进行消息推送时从消息队列和订单系统中同时获取信息,doublecheck二者是否一致,再进行消息的推送,从而避免了数据的重复消费问题。

02消息丢失之坑

我们知道完整的消息队列系统是由三部分组成的,生产者、消息队列、消费者。在生产者生产消息给到消费队列、消息队列存放消息、消费者消费消息这三个过程中,如果哪个过程出了问题,都会导致消息丢失。如果是在购买成功发送推送消息的场景,那么消息丢失都还好,不会产生什么损失。但如果是在下订单的场景、减库存的场景,消息丢失那就严重了。在下订单场景中,多个用户在平台购买商品,创建了订单,但是因为订单消息丢失了,支付系统尚未获取到订单从而没有去发起支付程序,新冠肺炎疫苗也救不了你了。在减库存场景中,多个用户参加秒杀活动,成功发起了创建订单请求,这时候库存系统进行库存的减少,然而订单系统尚未收到,不断的创建订单,最后系统库存都没有了,前方还在不断的创建订单,iPhone12本来只有10个参加秒杀,现在变为1000个,剩下的990个,都需要商家全额购买给到消费者,不好意思,新冠肺炎疫苗也救不了你。

避坑指南来了,针对生产者存放消息进队列丢失的问题,可以采用确认机制,生产者生产的消息都带上唯一ID,写入消息队列后,消息队列返回一个ack确认消息,标明成功接收,如果没有接收到消息,则在超时时间范围内返回nack消息,标明消息未接收成功。针对消息队列丢消息的问题,可以采用持久化方案,将消息队列的消息放入在磁盘中,并且将创建的队列持久化;针对消费者丢消息的问题,可以采用确认机制,消费者处理完消息之后,主动返回ack消息告诉队列,已处理完毕,超过时间范围后则重新处理。

03消息乱序之坑

消息乱序是指生产者生产的消息顺序和消费者消费的消息顺序不一样。在双十一大促时,Alice本来没有什么要买的,但是看到大家都在买啊,那也就参加随便买一点,就当是过节了,看到iPhone12价格4999还不错,就下单买了一个,吃了个饭回来后发现自己好像没有什么需求,于是又把订单取消了。这时候订单系统有两条消息,第一条订单成功创建,第二条订单取消。当消息队列系统中有多个消费者时,消费者1拿到了第一条消息,去发货了,消费者2拿到了第二条消息,取消了订单。对于Alice来说,他觉得既惊讶又开心,不花一分钱就拥有了iPhone12,但对于商家来说,总收入和总库存对不上,产生了损失,很难受。

避坑指南来了,那就是通过程序算法解决,第一针对同一个ID发起的消息,放入同一个队列,第二创建多个消费者,每个消费者只消费一个队列。

04消息积压之坑

消息积压是指消息队列的数据没有被及时处理,场景1是消费者出现了问题不能来消费,从而导致消息全在队列里,场景2是消费者消费速度太慢生产者生产太快,从而导致消息全在队列里。典型的业务场景就是,双十一大促时,用户发起了大量的订单清单,但是库存系统和支付系统都出现了问题,导致订单不能被处理,从而损失多笔订单。

避坑指南是创建更多的队列、更多的消费者、加快消费者消费速度。

微服务是好东西,分布式也是好东西,消息队列也是好东西,三者结合产生了更大的洪荒之力。但正如一枚硬币有正也有反,它们带来了更好的技术解决方案同时也带来很多问题,新技术的问题破解还有待攻克


相关阅读
微服务挺好,但你真的适合吗?
微服务前端之微前端
微服务应用故障定位系统实现原理剖析
看微服务核心技术如何演变
什么?你还不知道微服务是啥!
热门推荐