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
-
length
-
(integer) 3 # 共 3 个消息
-
radix-tree-keys
-
(integer) 1
-
radix-tree-nodes
-
(integer) 2
-
groups
-
(integer) 2 # 两个消费组
-
first-entry # 第一个消息
-
- 1527851486781-0
-
- “name”
-
“laoqian”
-
“age”
-
“30”
-
last-entry # 最后一个消息
-
- 1527851498956-0
-
- “name”
-
“xiaoqian”
-
“age”
-
“1”
获取 Stream 的消费组信息
127.0.0.1:6379> xinfo groups codehole
-
- name
-
“cg1”
-
consumers
-
(integer) 0 # 该消费组还没有消费者
-
pending
-
(integer) 0 # 该消费组没有正在处理的消息
-
- name
-
“cg2”
-
consumers # 该消费组还没有消费者
-
(integer) 0
-
pending
-
(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 >
-
- “codehole”
-
-
- 1527851486781-0
-
-
- “name”
-
“laoqian”
-
“age”
-
“30”
127.0.0.1:6379> xreadgroup GROUP cg1 c1 count 1 streams codehole >
-
- “codehole”
-
-
- 1527851493405-0
-
-
- “name”
-
“yurui”
-
“age”
-
“29”
127.0.0.1:6379> xreadgroup GROUP cg1 c1 count 2 streams codehole >
-
- “codehole”
-
-
- 1527851498956-0
-
-
- “name”
-
“xiaoqian”
-
“age”
-
“1”
-
- 1527852774092-0
-
- “name”
-
“youming”
-
“age”
-
“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 >
-
- “codehole”
-
-
- 1527854062442-0
-
-
- “name”
-
“lanying”
-
“age”
-
“61”
(36.54s)
观察消费组信息
127.0.0.1:6379> xinfo groups codehole
-
- name
-
“cg1”
-
consumers
-
(integer) 1 # 一个消费者
-
pending
-
(integer) 5 # 共 5 条正在处理的信息还有没有 ack
-
- name
-
“cg2”
-
consumers
-
(integer) 0 # 消费组 cg2 没有任何变化,因为前面我们一直在操纵 cg1
-
pending
-
(integer) 0
如果同一个消费组有多个消费者,我们可以通过 xinfo consumers 指令观察每个消费者的状态
127.0.0.1:6379> xinfo consumers codehole cg1 # 目前还有 1 个消费者
-
- name
-
“c1”
-
pending
-
(integer) 5 # 共 5 条待处理消息
-
idle
-
(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
-
- name
-
“c1”
-
pending
-
(integer) 4 # 变成了 5 条
-
idle
-
(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
-
- name
-
“c1”
-
pending
-
(integer) 0 # pel 空了
-
idle
-
(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开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
最后
针对最近很多人都在面试,我这边也整理了相当多的面试专题资料,也有其他大厂的面经。希望可以帮助到大家。
上述的面试题答案都整理成文档笔记。 也还整理了一些面试资料&最新2021收集的一些大厂的面试真题(都整理成文档,小部分截图)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
最后
针对最近很多人都在面试,我这边也整理了相当多的面试专题资料,也有其他大厂的面经。希望可以帮助到大家。
[外链图片转存中…(img-23qWZ6zx-1712912185635)]
上述的面试题答案都整理成文档笔记。 也还整理了一些面试资料&最新2021收集的一些大厂的面试真题(都整理成文档,小部分截图)
[外链图片转存中…(img-WaWenRy6-1712912185636)]
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!