看手机的网站叫什么网站设计 分辨率
前言
平时做后端开发时,如果需要用到消息队列功能,但公司的IT环境又没有提供专业的队列软件(RabitMQ/Kafka…),那么在简单且要求不高的场景下,可以使用 Redis 的List数据类型来做消息队列。
但List类型有一个挺致命的缺点,就是消息可靠性。当消费者使用 RPOP 命令从队列中取出一条消息后,如果消费者在消费完成前崩溃了,那么这条消息就永远丢失找不回来了。
注:为了方便理解,下文统一以“左进右出”的 List 作为例子
解决方案
下面介绍两种解决方案,其中推荐方案2
方案1:RPOPLPUSH
使用 RPOPLPUSH 命令从 List 里取出一条消息的同时,又将这条消息写入另一个List,例如:
RPOPLPUSH myqueue myqueue:backup
 
从 myqueue里取出一条消息,同时写入到 myqueue:backup备份。
消息有了备份之后,如果消费者程序中途崩溃了,那么重启后,只要首先检查备份队列有没有消息,有的话优先消费备份队列的消息,消费完后再消费主队列的消息就可以了。
但这样的设计只能防止一次程序崩溃,如果在消费备份队列时,消费者又崩溃了呢?岂不是消息又丢失了?难道又用同样的方法建一个myqueue:backup:2队列吗?显然这样的方法很不优雅。
注:RPOPLPUSH 命令自从 Redis 6.2.0 版本开始已经被标记为“过时”,新的替代命令是 LMOVE
方案2:LRANGE + LTRIM
方案2是使用 LRANGE 和 LTRIM 命令,LRANGE 命令可以一次性获取 N 条消息,相比 RPOP命令一条条的取效率上要更高。等消息全部消费完毕后,再使用 LTRIM 命令删除消息。这样在调用LTRIM命令前,这批消息会一直都存在于队列中,即使消费者崩溃也不会丢失。
示例 - 从队列右边取出100条数据,然后删除:
LRANGE myqueue -100 -1
LTRIM myqueue 0 -101
 
myqueue是key名字,后面两个数字是范围 start 和 stop,0代表第一个元素,-1代表最后一个元素,-100代表倒数第100个元素,如此类推。
需要注意的一点是,对于“左进右出”的队列,使用LRANGE获取的一批消息,顺序是跟消费顺序相反的,在消费前应先反转顺序。例如 ["one", "two", "three", "four"] 四个元素,使用
 LRANGE myqueue -2 -1获取到的结果是 ["three", "four"],但正确的消费顺序应该是 four -> three
Stream数据类型
如果你使用的是 Redis 5.0 以上版本,那么应该优先考虑使用 Stream 数据类型来做消息队列,Stream相比List在功能上要强大得多,提供了“消费者组”、“ACK确认”等消息队列场景专业功能,有兴趣可以自行网上搜索学习。
