Redis(8)——公布/订阅与Stream

Redis(8)——公布/订阅与Stream

一、Redis 中的公布/订阅功效

公布/ 订阅系统 是 Web 系统中对照常用的一个功效。简朴点说就是 公布者公布新闻,订阅者接受新闻,这有点类似于我们的报纸/ 杂志社之类的: (借用前边的一张图)

Redis(8)——公布/订阅与Stream

从我们 前面(下方相关阅读) 学习的知识来看,我们虽然可以使用一个 list 列表结构连系 lpushrpop 来实现新闻行列的功效,然则似乎很难实现实现 新闻多播 的功效:

Redis(8)——公布/订阅与Stream

为了支持新闻多播,Redis 不能再依赖于那 5 种基础的数据结构了,它单独使用了一个模块来支持新闻多播,这个模块就是 PubSub,也就是 PublisherSubscriber (公布者/ 订阅者模式)

PubSub 简介

我们从 上面的图 中可以看到,基于 list 结构的新闻行列,是一种 PublisherConsumer 点对点的强关联关系,Redis 为了消除这样的强关联,引入了另一种观点:频道 (channel)

Redis(8)——公布/订阅与Stream

Publisherchannel 中公布新闻时,关注了指定 channelConsumer 就能够同时受到新闻。但这里的 问题 是,消费者订阅一个频道是必须 明确指定频道名称 的,这意味着,若是我们想要 订阅多个 频道,那么就必须 显式地关注多个 名称。

为了简化订阅的繁琐操作,Redis 提供了 模式订阅 的功效 Pattern Subscribe,这样就可以 一次性关注多个频道 了,纵然生产者新增了同模式的频道,消费者也可以立刻受到新闻:

Redis(8)——公布/订阅与Stream

例如上图中,所有 位于图片下方的 Consumer 都能够受到新闻

Publisherwmyskxz.chat 这个 channel 中发送了一条新闻,不仅仅关注了这个频道的 Consumer 1Consumer 2 能够受到新闻,图片中的两个 channel 都和模式 wmyskxz.* 匹配,以是 Redis 此时会同样发送新闻给订阅了 wmyskxz.* 这个模式的 Consumer 3 和关注了在这个模式下的另一个频道 wmyskxz.log 下的 Consumer 4Consumer 5

另一方面,若是吸收新闻的频道是 wmyskxz.chat,那么 Consumer 3 也会受到新闻。

快速体验

Redis 中,PubSub 模块的使用异常简朴,常用的下令也就下面这么几条:

# 订阅频道:
SUBSCRIBE channel [channel ....]   # 订阅给定的一个或多个频道的信息
PSUBSCRIBE pattern [pattern ....]  # 订阅一个或多个相符给定模式的频道
# 公布频道:
PUBLISH channel message  # 将新闻发送到指定的频道
# 退订频道:
UNSUBSCRIBE [channel [channel ....]]   # 退订指定的频道
PUNSUBSCRIBE [pattern [pattern ....]]  #退订所有给定模式的频道

我们可以在内陆快速地来体验一下 PubSub

Redis(8)——公布/订阅与Stream

详细步骤如下:

  1. 开启内陆 Redis 服务,新建两个控制台窗口;
  2. 在其中一个窗口输入 SUBSCRIBE wmyskxz.chat 关注 wmyskxz.chat 频道,让这个窗口成为 消费者
  3. 在另一个窗口输入 PUBLISH wmyskxz.chat 'message' 往这个频道发送新闻,这个时刻就会看到 另一个窗口实时地泛起 了发送的测试新闻。

实现原理

可以看到,我们通过很简朴的两条下令,险些就可以简朴使用这样的一个 公布/ 订阅系统 了,然则详细是怎么样实现的呢?

每个 Redis 服务器历程维持着一个标识服务器状态redis.h/redisServer 结构,其中就 保留着有订阅的频道 以及 订阅模式 的信息:

struct redisServer {
    // ...
    dict *pubsub_channels;  // 订阅频道
    list *pubsub_patterns;  // 订阅模式
    // ...
};

订阅频道原理

当客户端订阅某一个频道之后,Redis 就会往 pubsub_channels 这个字典中新添加一条数据,现实上这个 dict 字典维护的是一张链表,好比,下图展示的 pubsub_channels 示例中,client 1client 2 就订阅了 channel 1,而其他频道也分别被其他客户端订阅:

Redis(8)——公布/订阅与Stream

SUBSCRIBE 下令

SUBSCRIBE 下令的行为可以用下列的伪代码示意:

def SUBSCRIBE(client, channels):
    # 遍历所有输入频道
    for channel in channels:
        # 将客户端添加到链表的末尾
        redisServer.pubsub_channels[channel].append(client)

通过 pubsub_channels 字典,程序只要检查某个频道是否为字典的键,就可以知道该频道是否正在被客户端订阅;只要取出某个键的值,就可以获得所有订阅该频道的客户端的信息。

PUBLISH 下令

领会 SUBSCRIBE,那么 PUBLISH 下令的实现也变得十分简朴了,只需要通过上述字典定位到详细的客户端,再把新闻发送给它们就好了:(伪代码实现如下)

def PUBLISH(channel, message):
    # 遍历所有订阅频道 channel 的客户端
    for client in server.pubsub_channels[channel]:
        # 将信息发送给它们
        send_message(client, message)

UNSUBSCRIBE 下令

使用 UNSUBSCRIBE 下令可以退订指定的频道,这个下令执行的是订阅的反操作:它从 pubsub_channels 字典的给定频道(键)中,删除关于当前客户端的信息,这样被退订频道的信息就不会再发送给这个客户端。

订阅模式原理

Redis(8)——公布/订阅与Stream

正如我们上面说到了,当发送一条新闻到 wmyskxz.chat 这个频道时,Redis 不仅仅会发送到当前的频道,还会发送到匹配于当前模式的所有频道,现实上,pubsub_patterns 背后还维护了一个 redis.h/pubsubPattern 结构:

typedef struct pubsubPattern {
    redisClient *client;  // 订阅模式的客户端
    robj *pattern;        // 订阅的模式
} pubsubPattern;

每当挪用 PSUBSCRIBE 下令订阅一个模式时,程序就建立一个包罗客户端信息和被订阅模式的 pubsubPattern 结构,并将该结构添加到 redisServer.pubsub_patterns 链表中。

我们来看一个 pusub_patterns 链表的示例:

Redis(8)——公布/订阅与Stream

这个时刻客户端 client 3 执行 PSUBSCRIBE wmyskxz.java.*,那么 pubsub_patterns 链表就会被更新成这样:

【python系统学习10】布尔值

Redis(8)——公布/订阅与Stream

通过遍历整个 pubsub_patterns 链表,程序可以检查所有正在被订阅的模式,以及订阅这些模式的客户端。

PUBLISH 下令

上面给出的伪代码并没有 完整形貌 PUBLISH 下令的行为,由于 PUBLISH 除了将 message 发送到 所有订阅 channel 的客户端 之外,它还会将 channelpubsub_patterns 中的 模式 举行对比,若是 channel 和某个模式匹配的话,那么也将 message 发送到 订阅谁人模式的客户端

完整形貌 PUBLISH 功效的伪代码定于如下:

def PUBLISH(channel, message):
    # 遍历所有订阅频道 channel 的客户端
    for client in server.pubsub_channels[channel]:
        # 将信息发送给它们
        send_message(client, message)
    # 取出所有模式,以及订阅模式的客户端
    for pattern, client in server.pubsub_patterns:
        # 若是 channel 和模式匹配
        if match(channel, pattern):
            # 那么也将信息发给订阅这个模式的客户端
            send_message(client, message)

PUNSUBSCRIBE 下令

使用 PUNSUBSCRIBE 下令可以退订指定的模式,这个下令执行的是订阅模式的反操作:序会删除 redisServer.pubsub_patterns 链表中,所有和被退订模式相关联的 pubsubPattern 结构,这样客户端就不会再收到和模式相匹配的频道发来的信息。

PubSub 的瑕玷

只管 Redis 实现了 PubSub 模式来到达了 多播新闻行列 的目的,但在现实的新闻行列的领域,险些 找不到稀奇合适的场景,由于它的瑕玷十分显著:

  • 没有 Ack 机制,也不保证数据的延续: PubSub 的生产者通报过来一个新闻,Redis 会直接找到响应的消费者通报已往。若是没有一个消费者,那么新闻会被直接抛弃。若是最先有三个消费者,其中一个突然挂掉了,过了一会儿等它再重连时,那么重连时代的新闻对于这个消费者来说就彻底丢失了。
  • 不持久化新闻: 若是 Redis 停机重启,PubSub 的新闻是不会持久化的,究竟 Redis 宕机就相当于一个消费者都没有,所有的新闻都会被直接抛弃。

基于上述瑕玷,Redis 的作者甚至单独开启了一个 Disque 的项目来专门用来做多播新闻行列,不外该项目现在似乎都没有成熟。不外厥后在 2018 年 6 月,Redis 5.0 新增了 Stream 数据结构,这个功效给 Redis 带来了 持久化新闻行列,今后 PubSub 作为新闻行列的功效可以说是就消逝了..

Redis(8)——公布/订阅与Stream

二、更为壮大的 Stream | 持久化的公布/订阅系统

Redis Stream 从观点上来说,就像是一个 仅追加内容新闻链表,把所有加入的新闻都一个一个串起来,每个新闻都有一个唯一的 ID 和内容,这很简朴,让它庞大的是从 Kafka 借鉴的另一种观点:消费者组(Consumer Group) (思绪一致,实现差别)

Redis(8)——公布/订阅与Stream

上图就展示了一个典型的 Stream 结构。每个 Stream 都有唯一的名称,它就是 Redis 的 key,在我们首次使用 xadd 指令追加新闻时自动建立。我们对图中的一些观点做一下注释:

  • Consumer Group:消费者组,可以简朴看成纪录流状态的一种数据结构。消费者既可以选择使用 XREAD 下令举行 自力消费,也可以多个消费者同时加入一个消费者组举行 组内消费。统一个消费者组内的消费者共享所有的 Stream 信息,统一条新闻只会有一个消费者消费到,这样就可以应用在分布式的应用场景中来保证新闻的唯一性。
  • last_delivered_id:用来示意消费者组消费在 Stream 上 消费位置 的游标信息。每个消费者组都有一个 Stream 内 唯一的名称,消费者组不会自动建立,需要使用 XGROUP CREATE 指令来显式建立,而且需要指定从哪一个新闻 ID 最先消费,用来初始化 last_delivered_id 这个变量。
  • pending_ids:每个消费者内部都有的一个状态变量,用来示意 已经 被客户端 获取,然则 还没有 ack 的新闻。纪录的目的是为了 保证客户端至少消费了新闻一次,而不会在网络传输的中途丢失而没有对新闻举行处置。若是客户端没有 ack,那么这个变量内里的新闻 ID 就会越来越多,一旦某个新闻被 ack,它就会对应最先削减。这个变量也被 Redis 官方称为 PEL (Pending Entries List)

新闻 ID 和新闻内容

新闻 ID

新闻 ID 若是是由 XADD 下令返回自动建立的话,那么它的花样会像这样:timestampInMillis-sequence (毫秒时间戳-序列号),例如 1527846880585-5,它示意当前的新闻是在毫秒时间戳 1527846880585 时发生的,而且是该毫秒内发生的第 5 条新闻。

这些 ID 的花样看起来有一些新鲜,为什么要使用时间来当做 ID 的一部分呢? 一方面,我们要 知足 ID 自增 的属性,另一方面,也是为了 支持局限查找 的功效。由于 ID 和天生新闻的时间有关,这样就使得在凭据时间局限内查找时基本上是没有分外消耗的。

固然新闻 ID 也可以由客户端自界说,然则形式必须是 “整数-整数”,而且后面加入的新闻的 ID 必须要大于前面的新闻 ID。

新闻内容

新闻内容就是通俗的键值对,形如 hash 结构的键值对。

增删改查示例

增删改查下令很简朴,详情如下:

  1. xadd:追加新闻
  2. xdel:删除新闻,这里的删除仅仅是设置了标志位,不影响新闻总长度
  3. xrange:获取新闻列表,会自动过滤已经删除的新闻
  4. xlen:新闻长度
  5. del:删除Stream

使用示例:

# *号示意服务器自动天生ID,后面顺序随着一堆key/value
127.0.0.1:6379> xadd codehole * name laoqian age 30  #  名字叫laoqian,岁数30岁
1527849609889-0  # 天生的新闻ID
127.0.0.1:6379> xadd codehole * name xiaoyu age 29
1527849629172-0
127.0.0.1:6379> xadd codehole * name xiaoqian age 1
1527849637634-0
127.0.0.1:6379> xlen codehole
(integer) 3
127.0.0.1:6379> xrange codehole - +  # -示意最小值, +示意最大值
1) 1) 1527849609889-0
   2) 1) "name"
      2) "laoqian"
      3) "age"
      4) "30"
2) 1) 1527849629172-0
   2) 1) "name"
      2) "xiaoyu"
      3) "age"
      4) "29"
3) 1) 1527849637634-0
   2) 1) "name"
      2) "xiaoqian"
      3) "age"
      4) "1"
127.0.0.1:6379> xrange codehole 1527849629172-0 +  # 指定最小新闻ID的列表
1) 1) 1527849629172-0
   2) 1) "name"
      2) "xiaoyu"
      3) "age"
      4) "29"
2) 1) 1527849637634-0
   2) 1) "name"
      2) "xiaoqian"
      3) "age"
      4) "1"
127.0.0.1:6379> xrange codehole - 1527849629172-0  # 指定最大新闻ID的列表
1) 1) 1527849609889-0
   2) 1) "name"
      2) "laoqian"
      3) "age"
      4) "30"
2) 1) 1527849629172-0
   2) 1) "name"
      2) "xiaoyu"
      3) "age"
      4) "29"
127.0.0.1:6379> xdel codehole 1527849609889-0
(integer) 1
127.0.0.1:6379> xlen codehole  # 长度不受影响
(integer) 3
127.0.0.1:6379> xrange codehole - +  # 被删除的新闻没了
1) 1) 1527849629172-0
   2) 1) "name"
      2) "xiaoyu"
      3) "age"
      4) "29"
2) 1) 1527849637634-0
   2) 1) "name"
      2) "xiaoqian"
      3) "age"
      4) "1"
127.0.0.1:6379> del codehole  # 删除整个Stream
(integer) 1

自力消费示例

我们可以在不界说消费组的情况下举行 Stream 新闻的 自力消费,当 Stream 没有新新闻时,甚至可以壅闭守候。Redis 设计了一个单独的消费指令 xread,可以将 Stream 当成通俗的新闻行列(list)来使用。使用 xread 时,我们可以完全忽略 消费组(Consumer Group) 的存在,就好比 Stream 就是一个通俗的列表(list):

# 从Stream头部读取两条新闻
127.0.0.1:6379> xread count 2 streams codehole 0-0
1) 1) "codehole"
   2) 1) 1) 1527851486781-0
         2) 1) "name"
            2) "laoqian"
            3) "age"
            4) "30"
      2) 1) 1527851493405-0
         2) 1) "name"
            2) "yurui"
            3) "age"
            4) "29"
# 从Stream尾部读取一条新闻,毫无疑问,这里不会返回任何新闻
127.0.0.1:6379> xread count 1 streams codehole $
(nil)
# 从尾部壅闭守候新新闻到来,下面的指令会堵住,直到新新闻到来
127.0.0.1:6379> xread block 0 count 1 streams codehole $
# 我们重新打开一个窗口,在这个窗口往Stream里塞新闻
127.0.0.1:6379> xadd codehole * name youming age 60
1527852774092-0
# 再切换到前面的窗口,我们可以看到壅闭排除了,返回了新的新闻内容
# 而且还显示了一个守候时间,这里我们守候了93s
127.0.0.1:6379> xread block 0 count 1 streams codehole $
1) 1) "codehole"
   2) 1) 1) 1527852774092-0
         2) 1) "name"
            2) "youming"
            3) "age"
            4) "60"
(93.11s)

客户端若是想要使用 xread 举行 顺序消费,一定要 记着当前消费 到哪里了,也就是返回的新闻 ID。下次继续挪用 xread 时,将上次返回的最后一个新闻 ID 作为参数通报进去,就可以继续消费后续的新闻。

block 0 示意永远壅闭,直到新闻到来,block 1000 示意壅闭 1s,若是 1s 内没有任何新闻到来,就返回 nil

127.0.0.1:6379> xread block 1000 count 1 streams codehole $
(nil)
(1.07s)

建立消费者示例

Stream 通过 xgroup create 指令建立消费组(Consumer Group),需要通报起始新闻 ID 参数用来初始化 last_delivered_id 变量:

127.0.0.1:6379> xgroup create codehole cg1 0-0  #  示意从头最先消费
OK
# $示意从尾部最先消费,只接受新新闻,当前Stream新闻会所有忽略
127.0.0.1:6379> xgroup create codehole cg2 $
OK
127.0.0.1:6379> xinfo codehole  # 获取Stream信息
 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  # 第一个新闻
10) 1) 1527851486781-0
    2) 1) "name"
       2) "laoqian"
       3) "age"
       4) "30"
11) last-entry  # 最后一个新闻
12) 1) 1527851498956-0
    2) 1) "name"
       2) "xiaoqian"
       3) "age"
       4) "1"
127.0.0.1:6379> xinfo groups codehole  # 获取Stream的消费组信息
1) 1) name
   2) "cg1"
   3) consumers
   4) (integer) 0  # 该消费组还没有消费者
   5) pending
   6) (integer) 0  # 该消费组没有正在处置的新闻
2) 1) name
   2) "cg2"
   3) consumers  # 该消费组还没有消费者
   4) (integer) 0
   5) pending
   6) (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) 1) "codehole"
   2) 1) 1) 1527851486781-0
         2) 1) "name"
            2) "laoqian"
            3) "age"
            4) "30"
127.0.0.1:6379> xreadgroup GROUP cg1 c1 count 1 streams codehole >
1) 1) "codehole"
   2) 1) 1) 1527851493405-0
         2) 1) "name"
            2) "yurui"
            3) "age"
            4) "29"
127.0.0.1:6379> xreadgroup GROUP cg1 c1 count 2 streams codehole >
1) 1) "codehole"
   2) 1) 1) 1527851498956-0
         2) 1) "name"
            2) "xiaoqian"
            3) "age"
            4) "1"
      2) 1) 1527852774092-0
         2) 1) "name"
            2) "youming"
            3) "age"
            4) "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) 1) "codehole"
   2) 1) 1) 1527854062442-0
         2) 1) "name"
            2) "lanying"
            3) "age"
            4) "61"
(36.54s)
127.0.0.1:6379> xinfo groups codehole  # 考察消费组信息
1) 1) name
   2) "cg1"
   3) consumers
   4) (integer) 1  # 一个消费者
   5) pending
   6) (integer) 5  # 共5条正在处置的信息另有没有ack
2) 1) name
   2) "cg2"
   3) consumers
   4) (integer) 0  # 消费组cg2没有任何转变,由于前面我们一直在操作cg1
   5) pending
   6) (integer) 0
# 若是统一个消费组有多个消费者,我们可以通过xinfo consumers指令考察每个消费者的状态
127.0.0.1:6379> xinfo consumers codehole cg1  # 现在另有1个消费者
1) 1) name
   2) "c1"
   3) pending
   4) (integer) 5  # 共5条待处置新闻
   5) idle
   6) (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) 1) name
   2) "c1"
   3) pending
   4) (integer) 4  # 变成了5条
   5) idle
   6) (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) 1) name
   2) "c1"
   3) pending
   4) (integer) 0  # pel空了
   5) idle
   6) (integer) 745505

QA 1:Stream 新闻太多怎么办? | Stream 的上限

很容易想到,要是新闻积累太多,Stream 的链表岂不是很长,内容会不会爆掉就是个问题了。xdel 指令又不会删除新闻,它只是给新闻做了个标志位。

Redis 自然思量到了这一点,以是它提供了一个定长 Stream 功效。在 xadd 的指令提供一个定长长度 maxlen,就可以将老的新闻干掉,确保最多不跨越指定长度,使用起来也很简朴:

> XADD mystream MAXLEN 2 * value 1
1526654998691-0
> XADD mystream MAXLEN 2 * value 2
1526654999635-0
> XADD mystream MAXLEN 2 * value 3
1526655000369-0
> XLEN mystream
(integer) 2
> XRANGE mystream - +
1) 1) 1526654999635-0
   2) 1) "value"
      2) "2"
2) 1) 1526655000369-0
   2) 1) "value"
      2) "3"

若是使用 MAXLEN 选项,当 Stream 的到达指定长度后,老的新闻会自动被镌汰掉,因此 Stream 的巨细是恒定的。现在还没有选项让 Stream 只保留给定数目的条目,由于为了一致地运行,这样的下令必须在很长一段时间内壅闭以镌汰新闻。(例如在添加数据的岑岭时代,你不得不长暂停来镌汰旧新闻和添加新的新闻)

另外使用 MAXLEN 选项的花销是很大的,Stream 为了节约内存空间,采用了一种特殊的结构示意,而这种结构的调整是需要分外的花销的。以是我们可以使用一种带有 ~ 的特殊下令:

XADD mystream MAXLEN ~ 1000 * ... entry fields here ...

它会基于当前的结构合理地对节点执行裁剪,来保证至少会有 1000 条数据,可能是 1010 也可能是 1030

QA 2:PEL 是若何制止新闻丢失的?

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

Redis Stream Vs Kafka

Redis 基于内存存储,这意味着它会比基于磁盘的 Kafka 快上一些,也意味着使用 Redis 我们 不能长时间存储大量数据。不外若是您想以 最小延迟 实时处置新闻的话,您可以思量 Redis,然则若是 新闻很大而且应该重用数据 的话,则应该首先思量使用 Kafka。

另外从某些角度来说,Redis Stream 也更适用于小型、廉价的应用程序,由于 Kafka 相对来说更难设置一些。

相关阅读

  1. Redis(1)——5种基本数据结构 – https://www.wmyskxz.com/2020/02/28/redis-1-5-chong-ji-ben-shu-ju-jie-gou/
  2. Redis(2)——跳跃表 – https://www.wmyskxz.com/2020/02/29/redis-2-tiao-yue-biao/
  3. Redis(3)——分布式锁深入探讨 – https://www.wmyskxz.com/2020/03/01/redis-3/
  4. Reids(4)——神奇的HyperLoglog解决统计问题 – https://www.wmyskxz.com/2020/03/02/reids-4-shen-qi-de-hyperloglog-jie-jue-tong-ji-wen-ti/
  5. Redis(5)——亿级数据过滤和布隆过滤器 – https://www.wmyskxz.com/2020/03/11/redis-5-yi-ji-shu-ju-guo-lu-he-bu-long-guo-lu-qi/
  6. Redis(6)——GeoHash查找四周的人https://www.wmyskxz.com/2020/03/12/redis-6-geohash-cha-zhao-fu-jin-de-ren/
  7. Redis(7)——持久化【一文领会】 – https://www.wmyskxz.com/2020/03/13/redis-7-chi-jiu-hua-yi-wen-liao-jie/

参考资料

  1. 订阅与公布——Redis 设计与实现 – https://redisbook.readthedocs.io/en/latest/feature/pubsub.html
  2. 《Redis 深度历险》 – 钱文品/ 著 – https://book.douban.com/subject/30386804/
  3. Introduction to Redis Streams【官方文档】 – https://redis.io/topics/streams-intro
  4. Kafka vs. Redis: Log Aggregation Capabilities and Performance – https://logz.io/blog/kafka-vs-redis/
  • 本文已收录至我的 Github 程序员发展系列 【More Than Java】,学习,不止 Code,迎接 star:https://github.com/wmyskxz/MoreThanJava
  • 小我私家民众号 :wmyskxz,小我私家自力域名博客:wmyskxz.com,坚持原创输出,下方扫码关注,2020,与您配合发展!

Redis(8)——公布/订阅与Stream

异常感谢列位人才气 看到这里,若是以为本篇文章写得不错,以为 「我没有三颗心脏」有点器械 的话,求点赞,求关注,求分享,求留言!

创作不易,列位的支持和认可,就是我创作的最大动力,我们下篇文章见!

原创文章,作者:28qn新闻网,如若转载,请注明出处:http://www.28qn.com/archives/1077.html