华为云 PB 级数据库 GaussDB(for Redis) 解析第二期:Redis 消息队列 Stream 的应用探讨
摘要:本文将对 Stream 的常用命令和应用场景进行介绍,并探讨原生 Redis Stream 消息队列的缺陷以及 GaussDB(for Redis)提供的解决方案,供大家学习和选用。
华为云高斯 Redis 团队欢迎各路英才加入,联系邮箱:yuwenlong4@huawei.com
引言:Redis Stream 是 Redis 5.0 引入的一种新的数据类型,其本质是一个消息队列,类似于 kafka 等消息中间件。它提供了消息的落地存储功能,并实现了类似 kafka 消费组和消费者的功能。与 kafka 相比,Redis Stream 同样拥有强大的功能,但因原生 Redis 无法有效支持大规模数据存储,成本昂贵,并存在数据丢失/不一致风险等原因,导致其未能流行起来。本文将对 Stream 的常用命令和应用场景进行介绍,并探讨原生 Redis Stream 消息队列的缺陷以及 GaussDB(for Redis)提供的解决方案,供大家学习和选用。
一、Redis Stream 简介
与 Pub/Sub 相比,Redis Stream 具有消息的落地存储功能,每一个客户端能访问任意时刻的消息,并且能记录每一个客户端的访问位置,还能保证消息不会丢失。Redis Stream 的结构如下所示,它有一个消息链表,将所有加入的消息都链接起来,每个消息都有唯一的 ID 和对应的内容。
如图所示,每一个 Stream 队列包含多条消息,每条消息由唯一的 ID 进行标识,由时间戳和序列号组成,例如 1627849609889-0。每条消息以追加的方式添加到 Stream 队列中。同一个 Stream 队列可以包含多个消费组(Consumer Group),每个消费组的状态都是独立的,同一个 Stream 队列的消息可以被多个消费组重复消费。
同一个消费组又包含多个消费者(Consumer),这些消费者之间是竞争关系,不同消费者不会重复消费同一条消息,任意一个消费者读取了队列中的一条消息都会使消费组中的游标 last_delivered_id 往前移动。该方式提高了并发效率,例如,多个进程并发处理 Stream 队列中的消息。每个消费者中维持一个状态变量 pending_ids,简称为 PEL(Pending Entries List),记录了当前已经被客户端读取的但尚未被 ACK 的消息,确保消息被客户端成功消费。
Redis Stream 命令可以分为消息队列命令和消费者命令两类,如下所示:
以即时通讯中的聊天室场景为例,使用 Redis Stream 作为中间件,实现聊天室的发言以及信息查看。
1) 使用 XADD 命令进行发言。
2) 使用 XLEN 命令获取聊天室发言的数量。
3)使用 XRANGE 获取消息队列的消息。
4)使用 XREAD 命令读取消息。可以在不设置消费组和消费者的情况下,使用 XREAD 的命令进行消息读取,此时 Stream 队列类似于一个普通的列表(list)。
更多的 Redis Stream 命令使用请参考官方文档(https://redis.io/commands/xread)。
二、应用场景
由于 Redis Stream 天然有序,特别适合存储时序数据,应用场景包括即时通讯、智慧医疗、流量削峰、智慧城市等领域。
(1)即时通讯:微信、QQ 等是我们日常生活中常用的通讯软件,常用的聊天方式包含点对点通讯和群聊两种方式。下图是一个群聊的模型图,当采用 Redis Stream 作为通讯的中间件,创建一个群聊时,在 Redis 中对应地为该群聊创建一个 Stream 队列。在发送消息时,将每个用户的消息按照时间顺序添加到 Stream 队列中,保证了消息的有序性。由于 Stream 是一个持久化的队列,无论是在线还是离线状态,每个用户可以多次查看历史消息,保证了通讯的完整性。
(2)智慧医疗:医疗行业的信息化,可以更好地服务于每一个人。为每一个人从出生起建立一份健康档案,记录相应的健康信息,如体检报告、诊断报告、用药信息、以及智能终端实时上传的健康指标。这些信息都是一些时序数据,同样可以采用 Redis Stream 来实现智慧医疗系统。建立起智慧医疗系统后,使用终端可以查看所有的医疗信息,并会提示患者按时吃药,在终端上传身体指标异常时,会自动报警并预约挂号。现阶段每个医院都有自己的信息系统,不同的医院很难查到同一个患者的医疗信息,在未来,医疗上云将有利于解决医疗信息孤岛,更好的帮助每一位患者。
(3)流量削峰:在常见的秒杀活动或团购中,如春运抢票、商城促销等,通常短时间内有大量的流量,导致系统崩溃。由于每一个用户在请求时对应唯一的时间戳,所有的请求都有一个先后顺序,同样可以采用 Redis Stream 作为中间件,将请求加入到 Redis Stream 消息队列。将消息转存到消息队列间接提供给应用,而非直接发送给应用,可以防止大流量冲击导致的系统崩溃。当消息队列中的请求数量达到规定的最大值时,直接回复客户端抢购失败。
三、原生 Redis 是否真的适用于以上场景?
如上应用场景具有数据规模大、数据持续增长的特点,虽然原生 Redis 有良好的设计初衷,但是并不能解决实际问题。具体体现在:
无法有效应对大规模数据:原生 Redis 是一个基于内存的数据库,单个节点存储容量有限,当扩展至 TB 级别的集群,将会出现管理困难,运维成本高等问题。
集群扩容影响业务性能:原生 Redis 在进行集群扩容时,需要重新划分 hash 槽并进行数据迁移,必定会影响业务性能。
数据可能会丢失:原生 Redis 虽然可以采用 RDB 和 AOF 的方式对数据进行持久化,但是并不会实时地将每一条命令写入到硬盘中,当出现掉电或集群崩溃的情况,必定会丢失一部分数据,对于类似智慧医疗场景,是难以忍受的。
除此以外,必须考虑数据库系统的可用性、数据一致性、成本和备份恢复能力等情况:
可用性: 原生 Redis 若采用一主一备的集群模式,当一对主备节点下线,集群部分数据将不可用。
数据一致性:当主节点宕机,主备节点切换,数据存在没有完全同步的情况。
成本:原生 Redis 是一种内存型数据库,当内存容量扩展至 TB 级别,成本将非常昂贵。
备份恢复:需要人工连接数据库执行 SAVE 或 BGSAVE 命令,不能支持定期自动备份,在恢复到新实例时需要手动拷贝备份数据。
四、是否有更好的解决方案?
在以上场景中,亟需一种能够存储和处理大规模 Stream 数据、鲁棒性强、且成本低廉的数据库系统。而 GaussDB(for Redis)(下文简称高斯 Redis)正是以上场景中一种很好的应用解决方案。高斯 Redis 是华为云数据库团队自主研发的兼容 Redis 协议的云原生数据库,该数据库突破原生 Redis 的内存限制,可轻松扩展至 PB 级存储,具有秒扩容、超可用、强一致和低成本等特点。
五、总结
Redis Stream 可以广泛应用在即时通讯、智慧医疗、流量削峰等领域。在面对大规模的 Stream 数据时,原生 Redis 存在成本过高、容量太小、可用性差、数据不一致等问题,无法适用于海量消息队列的场景。与原生 Redis 相比,高斯 Redis 具有海量存储,低成本,可持久化等优点,可做为比原生 Redis 更理想的 Stream 队列承载方案。
附:参考资料
《华为云 GaussDB(for Redis)与自建开源 Redis 的成本对比》
《一场由 fork 引发的超时,让我们重新探讨了 Redis 的抖动问题》
bbs.huaweicloud.com/blogs/22752…
《当 Redis 遇见计算存储分离》
developer.huaweicloud.com/hero/forum/…
《GaussDB(for Redis)与原生 Redis 的性能对比》
bbs.huaweicloud.com/blogs/23694…
《华为云 PB 级数据库 GaussDB(for Redis)揭秘第一期:Redis 与存算分离》
bbs.huaweicloud.com/blogs/23858…
版权声明: 本文为 InfoQ 作者【华为云开发者社区】的原创文章。
原文链接:【http://xie.infoq.cn/article/98b59971c2052ff8f8d4d8951】。文章转载请联系作者。
评论