一个经典的redis队列简单解决方案
需求场景:
一些异步的作业,比如订单信息同步,消息通知等,我们一般都是通过事件触发,然后先保存在队列里面,异步消费的方式去执行。
这个同步的技术需要保障两个点:
1、事件触发稳定性
2、事件消费的稳定性
我们先来聊第一个点:
要保证事件触发稳定,需要满足2个点,触发数据丢失可补偿,事件及时性,那么我们的方案可以是用canal监听mysql的方式,把事件数据触发写入到redis队列里面,这样的好处是canal可以方便的根据位点,恢复redis队列的数据(假设redis的数据是可以丢失的定位)。
那第二点,消费的稳定性,就要去对redis列队的数据进行消费,是稳定的。因为涉及到消费的性能要求,我们一般采取redis队列的pop方式,保障并发问题。但是pop有个致命的问题就是pop后,业务消费处理失败的处理能力有效,容易造成redis的pop后业务逻辑处理失败,队列数据丢失。解决方案就是数据和pop分开,触发数据放到一个hashmap里面,pop的消费数据放到list里面;每次从hashmap取hgetall到list,然后当我们pop的list时,消费成功,才将hashmap里面的数据删除。然后,消费失败的数据,放到另外一组hashmap和list里面,重复这个逻辑,与正常的队列区分开来。
暗夜之中,才见繁星;危机之下,暗藏转机;事在人为,为者常成。