华为云企业级redis揭秘第二期:redis消息队列stream应用探讨-星辰平台

发表于 2021/02/25 11:57:55 2021/02/25
【摘要】 云数据库gaussdb(for redis)作为华为云旗下企业级redis,致力于为客户提供稳定可靠、超高并发,且能够极速弹性扩容的kv存储服务。


引言:redis stream是redis 5.0引入的一种新的数据类型,其本质是一个消息队列,类似于 kafka等消息中间件。它提供了消息的落地存储功能,并实现了类似kafka消费组和消费者的功能。与kafka相比,redis stream同样拥有强大的功能,但因原生redis无法有效支持大规模数据存储,成本昂贵,并存在数据丢失/不一致风险等原因,导致其未能流行起来。本文将对stream的常用命令和应用场景进行介绍,并探讨原生redis stream消息队列的缺陷以及gaussdb(for redis)提供的星辰平台的解决方案,供大家学习和选用。

与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作为中间件,实现聊天室的发言以及信息查看。

  • 使用xadd命令进行发言
  • 使用xlen命令获取聊天室发言的数量
  • 使用xrange获取消息队列的消息

  • 使用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是一个基于内存的数据库,单个节点存储容量有限,当扩展至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)团队

杭州/西安/深圳简历投递:[email protected]

gaussdb(for redis)产品星辰平台主页:

更多技术文章,关注gaussdb(for redis)官方博客:

【星辰平台的版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区),文章链接,文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。