如何确保 Redis 驱动消息队列的高可用


让内存使用可控

Redis 性能好,但是需要很多内存空间,而内存又比磁盘贵。为了在性能和价格之间做一个平衡,需要让内存的使用可控:

  • 队列任务尺寸尽可能小;
  • 确保有足够多的进程尽可能快地消费队列,避免任务堆积。

为了让队列任务尺寸尽可能小,可以通过保持任务属性的简单来实现,比如尽可能使用数字、字符串、值对象,避免使用复杂对象。

如果不得不设置 Eloquent 模型属性,可以只传递模型 ID 而不是整个模型,或者,使用Illuminate\Queue\SerializesModels Trait,这样,在序列化模型时,只会保留模型 ID。

另一个方面,就是要保证队列任务消费的速度尽可能快,如果你的内存使用率在 80%,推送大量任务可能会导致服务器内存耗尽,所以一定要避免任务堆积,始终有空间预留给新推送的任务。

持久化任务到磁盘

内存数据不会持久化存储,如果服务器重启将意味着所有队列任务被清空。

我们可以配置 Redis 将数据持久化到磁盘,或每隔一段时间将全量数据进行备份(RDB),或仅以追加方式记录所有传入的命令(AOF)。这样一来,当服务器重启后,就可以读写磁盘中的持久化数据恢复 Redis 内存数据(重放)。

和 MySQL 一样,为了性能考虑,Redis 的持久化也有一定延时,在队列这种场景中,如果有足够多的消费进程,其实也没有必要进行持久化,因为即便服务器重启,也不会丢失太多数据。不进行持久化操作也能提高 Redis 性能,让用户觉得更快。

Redis 主从复制

Redis 内置了主从复制功能。你可以配置多个只读的 Redis 从库复制主库的数据。

你可以通过这种模式从主库读取任务或者向其推送任务,还可以在主库崩溃时将从库变成主库(主从切换)。

这将会最小化因为 Redis 实例崩溃造成的队列任务丢失,不过和我们前面提到的一样,我们应该专注于如何尽可能快地消费队列中的任务,而不是如何持久化或者实现主从复制。

共享同一个 Redis 实例

除了队列之外,还可以将 Redis 用作其他功能,比如缓存、Session、分布式锁、广播等,还可以使用单个 Redis 实例存储多个应用的队列数据。

如果你不得不这么做的话,建议为每个应用设置单独的数据库,比如存储应用 A 队列任务的数据库是 0,存储应用 A 缓存数据的数据库是 1,存储应用 B 队列任务的数据库是 2。。。

这样一来,当你运行 FLUSHDB 指令的时候就只会清空当前数据库的数据,而不会影响其他功能和应用的数据。

不过,Redis 是一个单进程服务,所以单个数据库的吞吐量很大,会影响其他数据库。

使用不同数据库的替代方案是运行不同的 Redis 实例,这样的话,所有的连接就都是独立的,不相互影响的了。


点赞 取消点赞 收藏 取消收藏

<< 上一篇: 如何选择正确的消息队列驱动

>> 下一篇: 在生产环境管理队列任务的重试