Redis 怎么做消息队列?
模式:可靠的队列(reliable queue)
Redis的列表(list)经常被用作队列(queue),用于在不同程序之间有序地交换消息(message).一个客户端通过LPUSH命令将消息放入队列中,而另一个客户端通过RPOP或者BRPOP命令取出队列中等待时间最长的消息.不幸的是,上面的队列方法是不可靠的.因为在这个过程中,一个客户端可能在取出一个消息之后崩溃,而未处理完的消息也就因此丢失.
使用RPOPLPUSH命令(或者它的阻塞版本BRPOPLPUSH)可以解决这个问题:
因为它不仅返回一个消息,同时还将这个消息添加到另一个备份列表当中.如果一切正常的话,当一个客户端完成某个消息的处理之后,可以用LREM命令将这个消息从备份列表删除.最后,添加一个客户端专门用于监视备份列表,它自动地将超过一定处理时限的消息RPOPLPUSH重新放入队列中去.因为负责处理该消息的客户端可能已经崩溃,这样就不会丢失任何消息了.
上述做法需要注意的问题:
RPOPLPUSH重新入队,即把备份列表右侧元素(表尾)重新入队,可能会出现消息被重复消费的情况.
因此消费操作要实现幂等性,即保证重复消费结果一致.
举例说明:
数据列表(source): c,b,a
2个客户端先后RPOPLPUSH消费并备份了2个元素:a和b
客户端1: RPOPLPUSH source backup (返回a并备份到backup)
客户端2: RPOPLPUSH source backup (返回b并备份到backup)
备份列表(backup): b,a
客户端消费逻辑完成后,删除备份列表的元素.
客户端1: LREM backup -1 a (移除备份列表backup中,从表尾到表头,第一个a,其中-1表示从表尾开始)
客户端2: LREM backup -1 b (移除备份列表backup中,从表尾到表头,第一个b,其中-1表示从表尾开始)
最后,Redis AOF持久化有几个配置:
appendfsync always 表示每当Redis执行写命令,就立即调用fsync把数据写入aof文件,最安全,但速度最慢.
appendfsync everysec 表示每秒钟fsync写一次,也就是有丢失前1秒数据的风险,但性能要比实时写入好得多,是默认配置.
appendfsync no 表示不调用fsync刷写,让操作系统自动刷新数据到磁盘(周期大概为30秒),快速但不够安全,不推荐.注意,Kafka的默认配置就类似这个级别.
性能与安全,自行权衡.