Redis的List数据类型作为消息队列,已经比较合适了,但存在一些不足,比如只能独立消费,订阅发布又无法支持数据的持久化,相对前两者,Redis Stream作为消息队列的使用更为有优势。
 
相信球迷小伙伴们对文字直播这个东西都不陌生,时常在想,这个功能是怎么实现的?
具体说就是用什么技术实现最为合适?如何面对数以百万计的读压力?广告消息是如何插播进来的?最后的历史消息如何归档,如何持久化存储?
文字直播其实就是解说员作为生产者,生产消息(文字信息),各种客户端作为消费者,消费信息(刷新文字内容)。
典型的消息队列实现,可以用队列或者类似队列的功能实现,这里只是简单想象一下,结合redis中的stream数据类型,来学习stream作为消息队列的功能实现。
 
 
1,生成者:生产者队列的创建,与消息的增删改
1.1 创建并写入消息
  语法:xadd queue_name Id filed value(filed value)
     1,每一组消息需要一个唯一的Id,*号表示服务器自动生成ID,后面顺序跟着一组或者多组消息(filed value)
     2,消息ID的形式是timestampInMillis-sequence,例如1527846880572-5,它表示当前的消息在毫米时间戳1527846880572时产生,并且是该毫秒内产生的第5条消息。
           消息ID可以由服务器自动生成,也可以由客户端自己指定,但是形式必须是整数-整数,而且必须是后面加入的消息的ID要大于前面的消息ID。
     3,消息元素的的结构为key-value,必须成对出现,如果key或者value元素中有空格,必须用"abc  def"或者'abc  def'括起来
 
1.2 生产者写入消息
  语法:xadd queue_name *|Id filed value    
 
1.3 xlen 当前stream的长度:xlen stream_name
  xlen "NBA_Match_001" ,也就是上面写入的10条消息
    
1.4 限制某一个stream的最大长度,maxlen 
  依据先进先出的原则,自动删除超出最长长度的消息
  xadd "NBA_Match_001" maxlen 50000 * "2019-07-13 08:26:39" "反击哈腾,一条龙上篮得分"
  
1.5 查询消息(查询是生产者查询自己生产的消息,跟消费者的消费是两码事)

正向查询
xrange "NBA_Match_001"              # 查询所有消息
xrange "NBA_Match_001" - +              # -表示最小值, +表示最大值
xrange "NBA_Match_001" 1562980142175-0 +    # 指定最小消息ID的列表
xrange "NBA_Match_001"- 1562980142175-0      # 指定最大消息ID的列表
反向查询
xrevrange "NBA_Match_001"
xrevrange "NBA_Match_001" + -
xrevrange "NBA_Match_001" + 1562980142175-0
xrevrange "NBA_Match_001" 1562980142175-0 -

1.6 删除消息
  xdel stream_name id,删除消息并不是真正的物理删除,队列的长度不变,指示标记当前消息被删除

1.7 查看stream属性xinfo stream stream_name 
1.8 del stream_name
删除 stream :del NBA_Match_001
删除本质上本Redis中的其他数据类型一致,stream本身就是一个key值,del key值就删除了整个消息的全部信息。
 
 
2 xread:独立消费
类似于List,生产者往list中写数据,消费者从list中读数据,只能有一个消费者
 
2. 1,从头部读取消息,从某个streams中读取n条消息,0-0只从头开始,或者指定从streams的Id开始
  xread count 1 streams "NBA_Match_001" 0-0
  xread count 1 streams "NBA_Match_001" 1562980142175-0
  
2.2,从尾部读取最新的一条消息
xread count 1 streams "NBA_Match_001" $
此时默认不返回任何消息
xread  block 0 count 1 streams "NBA_Match_001" $
以阻塞的方式读取尾部最新的一条消息,直到新的消息的到来

  

 
3 多消费者xgroup :消费组,每个组中的消费者独立消费stream中的消息
典型的比如文字直播的安卓App客户端,苹果App客户端,网页客户端等等。多个终端,都可以独立地消费队列里面的

3.1 创建消费组

对消息队列"NBA_Match_001"创建了两个消费组,一个是cg1,一个是cg2,比如网页客户端与App客户端

1,xgroup create "NBA_Match_001" cg1 0-0  #  表示从头开始消费

创建消费组cg1,消费组必须绑定一个steam(NBA_Match_001),从头(0-0 )开始消费"NBA_Match_001"中的消息
2,xgroup create "NBA_Match_001" cg2 0-0  #  表示从头开始消费
3,2 从消费组中创建消费者
xreadgroup指令可以进行消费组的组内消费
xreadgroup GROUP cg1 c1 count 1 streams "NBA_Match_001" >
>号表示从当前消费组的last_delivered_id后面开始读 , 每当消费者读取一条消息,last_delivered_id变量就会前进 
当一个组的消费则消费完全部消息之后,就没有新的消息了
 

每个消费组(Consumer Group)的状态都是独立的,相互不受影响。也就是说同一份Stream内部的消息会被每个消费组都消费到。
同一个消费组(Consumer Group)可以挂接多个消费者(Consumer),这些消费者之间是竞争关系,任意一个消费者读取了消息都会使游标last_delivered_id往前移动。
每个消费者者有一个组内唯一名称。

关于消费组,可能不太好理解,举个例子就比较清楚
假设有2个消费组cg1,cg2,对于cg1,其组内共有3个消费者c1,、c2、c3。一个消息队列中共有5条消息a,b,c,d,e,那么一种可能的消费方式如下
a -> c1
b -> c2
c -> c3
d -> c1
e -> c2
也就是说3个消费者,对于消息的消费是互斥的,消费的消息是没有交集的
而对于cg2,同样可以消费a,b,c,d,e这5条消息,不依赖于cg1消费组以及消费情况,同理,具体怎么消费,取决于其组内的消费者数量
就好比体育直播的客户端,正常情况下,网页客户端可以收到所有的直播消息,手机App客户端也可以收到所有的直播消息一样,不同消费组间对消息的消费互不干扰。

4 多个生产者和多个消费者

  这种情况类似以上,不用的是增加了多个消费者,在上面的基础上做了扩展。
  其实不难想象,文字直播插播的广告消息,可能是类似如下结构,是另外一个独立的生产者,与文字直播员一样生成写入消息到队列,然后客户端看到的就是夹杂了广告的直播。

目前就个人认识而言,stream数据类型实现消息队列并不完美,最大的问题就是单点压力问题:这里是说单点压力,而不是单点故障,stream类型数据,其实从逻辑上看,是一个key值(stream_name),跟着一系列value(消息),这些消息只能存储在一个Redis实例中,如何缓解多个消费者对单个Key值中的消息消费压力?说来说去,不就是想说kafka的partition么……

参考:

http://database.51cto.com/art/201812/588189.htm

https://www.zhihu.com/question/279540635

Redis中的Stream数据类型作为消息队列的尝试的更多相关文章

  1. 手把手教你用redis实现一个简单的mq消息队列(java)

    众所周知,消息队列是应用系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构.目前使用较多的消息队列有 ActiveMQ,RabbitMQ,Zero ...

  2. 面试官:Redis中哈希数据类型的内部实现方式是什么?

    面试官:Redis中基本的数据类型有哪些? 我:Redis的基本数据类型有:字符串(string).哈希(hash).列表(list).集合(set).有序集合(zset). 面试官:哈希数据类型的内 ...

  3. 使用Redis Stream来做消息队列和在Asp.Net Core中的实现

    写在前面 我一直以来使用redis的时候,很多低烈度需求(并发要求不是很高)需要用到消息队列的时候,在项目本身已经使用了Redis的情况下都想直接用Redis来做消息队列,而不想引入新的服务,kafk ...

  4. redis k-v数据库、高速缓存、消息队列代理

    Redis 简介   Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库. Redis 与其他 key - value 缓存产品有以下三个特点: Redis支持数据的 ...

  5. Redis 中的高级数据类型

    5个基础数据类型 高级功能 ① HyperLogLog (参考) 供不精确的去重计数功能,比较适合用来做大规模数据的去重统计,例如统计 UV > PFADD visitors alice bob ...

  6. Redis系列(五):消息队列

    消息队列已经成为现在互联网服务端的标配组件,现在比较常用的消息中间件有RabbitMQ.Kafka.RocketMQ.ActiveMQ.说出来你可能不信,Redis作为一个缓存中间件,居然也提供了消息 ...

  7. Redis 竟然能用 List 实现消息队列

    分布式系统中必备的一个中间件就是消息队列,通过消息队列我们能对服务间进行异步解耦.流量消峰.实现最终一致性. 目前市面上已经有 RabbitMQ.RochetMQ.ActiveMQ.Kafka等,有人 ...

  8. Redis中的简单事物以及消息订阅发布

    Redis支持简单的事物,但是没有mysql的Innodb支持的那么的完善 我们接下来看一下Redis和Mysql的事物的一个对比:   MySQL Redis 开启 start transactio ...

  9. php中对共享内存,消息队列的操作

    http://www.cnblogs.com/fengwei/archive/2012/09/12/2682646.html php作为脚本程序,通常生命周期都很短,如在web应用中,一次请求就是ph ...

随机推荐

  1. nodejs dateformat date-utils

    https://www.npmjs.org/package/dateformat https://www.npmjs.org/package/date-utils 来自为知笔记(Wiz)

  2. 微信小程序把玩(十六)form组件

    原文:微信小程序把玩(十六)form组件 form表单组件 是提交form内的所有选中属性的值,注意每个form表单内的组件都必须有name属性指定否则提交不上去,button中的type两个subm ...

  3. Excel的Range对象(C#)

    原文:Excel的Range对象(C#) Range 对象是 Excel 应用程序中最经常使用的对象:在操作 Excel 内的任何区域之前,都需要将其表示为一个 Range 对象,然后使用该 Rang ...

  4. centos 7 安装 git 2.22.0

    1.安装所需软件包 yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel yum install gcc ...

  5. 利用docker在window7下安装TensorFlow

    安装过程下碰了不少坑,记录一下安装过程,方便以后有需要时复用. 1.安装docker 下载最新版本的docker并且默认安装即可,安装后打开Docker Quickstart Terminal,初次进 ...

  6. UILabel实现自适应宽高需要注意的地方(三)

        一.需求图如下所示    UILabel 的高度自适应 UILabel中的段落间距可设置   图片效果如下:   调整段落适应长宽高方式:         需求:   保证"游戏玩法 ...

  7. 利用Rsync同步工具上传、删除目标文件

    Rsync是文件备份工具,当然也可以当做传输工具,管理远程服务器的文件 上传 rsync -avzP --progress --port 9106 /path/.../指定文件 root@192.16 ...

  8. SYN1610型B码时统设备

       SYN1610型B码时统设备 产品概述 SYN1610型B码时统设备是由西安同步电子科技有限公司精心设计.自行研发生产的一款模块化配置的通用性时统终端,可接收北斗/ GPS信号/ IRIG-B码 ...

  9. 优秀的Restful API应该是什么样的

    1 你一直在错误的使用http协议 现在微服务真是火的一塌糊涂!大街小巷,逢人必谈微服务,各路大神纷纷忙着把自家的单体服务拆解成多个Web微小服务!而作为微服务之间通信的桥梁,Web API的设计就显 ...

  10. 【webAssembly系列】webAssembly初探究竟

    一.前言 自从JavaScript诞生开始,到现在开始变成流行的编程语言,背后的是web发展所推动的.web应用的变得更多更复杂,但是渐渐暴露出JavaScript的问题: (1)语法太灵活导致开发大 ...