实战解析耳听八方的Redis拓展应用——Stream

127.0.0.1:6379> xgroup create codehole cg1 0-0

OK

$ 表示从尾部开始消费,只接受新消息,当前 Stream 消息会全部忽略

127.0.0.1:6379> xgroup create codehole cg2 $

OK

获取 Stream 信息

127.0.0.1:6379> xinfo stream codehole

  1. length

  2. (integer) 3 # 共 3 个消息

  3. radix-tree-keys

  4. (integer) 1

  5. radix-tree-nodes

  6. (integer) 2

  7. groups

  8. (integer) 2 # 两个消费组

  9. first-entry # 第一个消息

    1. 1527851486781-0
    1. “name”
  10. “laoqian”

  11. “age”

  12. “30”

  13. last-entry # 最后一个消息

    1. 1527851498956-0
    1. “name”
  14. “xiaoqian”

  15. “age”

  16. “1”

获取 Stream 的消费组信息

127.0.0.1:6379> xinfo groups codehole

    1. name
  1. “cg1”

  2. consumers

  3. (integer) 0 # 该消费组还没有消费者

  4. pending

  5. (integer) 0 # 该消费组没有正在处理的消息

    1. name
  6. “cg2”

  7. consumers # 该消费组还没有消费者

  8. (integer) 0

  9. pending

  10. (integer) 0 # 该消费组没有正在处理的消息

消费

==

Stream 提供了 xreadgroup 指令可以进行消费组的组内消费,需要提供消费组名称、消费者名称和起始消息 ID。它同 xread 一样,也可以阻塞等待新消息。读到新消息后,对应的消息 ID 就会进入消费者的 PEL(正在处理的消息) 结构里,客户端处理完毕后使用 xack 指令通知服务器,本条消息已经处理完毕,该消息 ID 就会从 PEL 中移除。

> 号表示从当前消费组的 last_delivered_id 后面开始读

每当消费者读取一条消息,last_delivered_id 变量就会前进

127.0.0.1:6379> xreadgroup GROUP cg1 c1 count 1 streams codehole >

    1. “codehole”
      1. 1527851486781-0
    1. “name”
  1. “laoqian”

  2. “age”

  3. “30”

127.0.0.1:6379> xreadgroup GROUP cg1 c1 count 1 streams codehole >

    1. “codehole”
      1. 1527851493405-0
    1. “name”
  1. “yurui”

  2. “age”

  3. “29”

127.0.0.1:6379> xreadgroup GROUP cg1 c1 count 2 streams codehole >

    1. “codehole”
      1. 1527851498956-0
    1. “name”
  1. “xiaoqian”

  2. “age”

  3. “1”

    1. 1527852774092-0
    1. “name”
  4. “youming”

  5. “age”

  6. “60”

再继续读取,就没有新消息了

127.0.0.1:6379> xreadgroup GROUP cg1 c1 count 1 streams codehole >

(nil)

那就阻塞等待吧

127.0.0.1:6379> xreadgroup GROUP cg1 c1 block 0 count 1 streams codehole >

开启另一个窗口,往里塞消息

127.0.0.1:6379> xadd codehole * name lanying age 61

1527854062442-0

回到前一个窗口,发现阻塞解除,收到新消息了

127.0.0.1:6379> xreadgroup GROUP cg1 c1 block 0 count 1 streams codehole >

    1. “codehole”
      1. 1527854062442-0
    1. “name”
  1. “lanying”

  2. “age”

  3. “61”

(36.54s)

观察消费组信息

127.0.0.1:6379> xinfo groups codehole

    1. name
  1. “cg1”

  2. consumers

  3. (integer) 1 # 一个消费者

  4. pending

  5. (integer) 5 # 共 5 条正在处理的信息还有没有 ack

    1. name
  6. “cg2”

  7. consumers

  8. (integer) 0 # 消费组 cg2 没有任何变化,因为前面我们一直在操纵 cg1

  9. pending

  10. (integer) 0

如果同一个消费组有多个消费者,我们可以通过 xinfo consumers 指令观察每个消费者的状态

127.0.0.1:6379> xinfo consumers codehole cg1 # 目前还有 1 个消费者

    1. name
  1. “c1”

  2. pending

  3. (integer) 5 # 共 5 条待处理消息

  4. idle

  5. (integer) 418715 # 空闲了多长时间 ms 没有读取消息了

接下来我们 ack 一条消息

127.0.0.1:6379> xack codehole cg1 1527851486781-0

(integer) 1

127.0.0.1:6379> xinfo consumers codehole cg1

    1. name
  1. “c1”

  2. pending

  3. (integer) 4 # 变成了 5 条

  4. idle

  5. (integer) 668504

下面 ack 所有消息

127.0.0.1:6379> xack codehole cg1 1527851493405-0 1527851498956-0 1527852774092-0

1527854062442-0

(integer) 4

127.0.0.1:6379> xinfo consumers codehole cg1

    1. name
  1. “c1”

  2. pending

  3. (integer) 0 # pel 空了

  4. idle

  5. (integer) 745505

Stream 消息太多怎么办?

===============

读者很容易想到,要是消息积累太多,Stream 的链表岂不是很长,内容会不会爆掉?xdel指令又不会删除消息,它只是给消息做了个标志位。

Redis 自然考虑到了这一点,所以它提供了一个定长 Stream 功能。在 xadd 的指令提供一个定长长度 maxlen,就可以将老的消息干掉,确保最多不超过指定长度。

127.0.0.1:6379> xlen codehole

(integer) 5

127.0.0.1:6379> xadd codehole maxlen 3 * name xiaorui age 1

1527855160273-0

127.0.0.1:6379> xlen codehole

(integer) 3

我们看到 Stream 的长度被砍掉了。如果 Stream 在未来可以提供按时间戳清理消息的规则那就更加完美了,但是目前还没有。

消息如果忘记 ACK 会怎样?

===============

Stream 在每个消费者结构中保存了正在处理中的消息 ID 列表 PEL,如果消费者收到 了消息处理完了但是没有回复 ack,就会导致 PEL 列表不断增长,如果有很多消费组的话,那么这个 PEL 占用的内存就会放大。

PEL 如何避免消息丢失?

=============

在客户端消费者读取 Stream 消息时,Redis 服务器将消息回复给客户端的过程中,客户端突然断开了连接,消息就丢失了。但是 PEL 里已经保存了发出去的消息 ID。待客户端重新连上之后,可以再次收到 PEL 中的消息 ID 列表。不过此时 xreadgroup 的起始消息 ID 不能为参数>,而必须是任意有效的消息 ID,一般将参数设为 0-0,表示读取所有的 PEL 消息以及自 last_delivered_id 之后的新消息。

Stream 的高可用

===========

Stream 的高可用是建立主从复制基础上的,它和其它数据结构的复制机制没有区别,也就是说在 Sentinel 和 Cluster 集群环境下 Stream 是可以支持高可用的。不过鉴于 Redis 的 指令复制是异步的,在 failover 发生时,Redis 可能会丢失极小部分数据,这点 Redis 的其 它数据结构也是一样的。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

针对最近很多人都在面试,我这边也整理了相当多的面试专题资料,也有其他大厂的面经。希望可以帮助到大家。

image

上述的面试题答案都整理成文档笔记。 也还整理了一些面试资料&最新2021收集的一些大厂的面试真题(都整理成文档,小部分截图)

image

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
最后

针对最近很多人都在面试,我这边也整理了相当多的面试专题资料,也有其他大厂的面经。希望可以帮助到大家。

[外链图片转存中…(img-23qWZ6zx-1712912185635)]

上述的面试题答案都整理成文档笔记。 也还整理了一些面试资料&最新2021收集的一些大厂的面试真题(都整理成文档,小部分截图)

[外链图片转存中…(img-WaWenRy6-1712912185636)]

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值