替代全局订阅?)
Dragonfly 集群模式如何启用 Sharded Pub/SubSPUBLISH/SSUBSCRIBE替代全局订阅【免费下载链接】dragonflyA modern replacement for Redis and Memcached项目地址: https://gitcode.com/GitHub_Trending/dr/dragonfly在 Dragonfly 中开启集群模式--cluster_modeyes后PUBLISH、SUBSCRIBE、PSUBSCRIBE这类全局发布订阅命令会被服务端直接拒绝集群下唯一可用的发布订阅路径是 Sharded Pub/SubSPUBLISH/SSUBSCRIBE/SUNSUBSCRIBE。本文在一个本地两节点集群上完成完整的操作路径启动节点、推送 slot 配置、确认频道归属、完成一次订阅—发布—退订往返、检查订阅状态并说明 slot 迁移时对已有订阅的处理。文中的命令和预期响应都可以对照仓库里的集群 pub/sub 集成测试复核。集群模式下为什么只有 Sharded Pub/Sub 可用pub-sub 文档把 Dragonfly 的 pub/sub 分成三种形态并明确列出它们在集群模式下的行为形态命令作用域集群模式StandardPUBLISH、SUBSCRIBE、UNSUBSCRIBE全局所有频道Blocked — 返回错误PatternPSUBSCRIBE、PUNSUBSCRIBE全局glob 匹配Blocked — 返回错误ShardedSPUBLISH、SSUBSCRIBE、SUNSUBSCRIBE按 slot频道名决定 slot支持在集群节点上执行全局命令会返回(error) PUBLISH is not supported in cluster mode yet。原因在于全局频道没有 slot 归属而集群按 slot 做路由cluster-mode.md §5.1。Sharded Pub/Sub 把频道名当作 key 参与 slot 计算slot(channel) crc16(tag(channel)) 0x3FFFhash tag 规则与普通 key 相同取第一段配平的{...}内容否则取整个频道名见 cluster-mode.md §3.1–3.2。这样同一个频道的SPUBLISH和SSUBSCRIBE总是路由到同一个 slot、同一个属主节点集群的 slot 归属检查可以直接套用。命令的元信息来自 pub-sub.md 的命令注册表SPUBLISHarity 3参数为频道名 消息体SSUBSCRIBEarity -2订阅 1 个或多个频道SUNSUBSCRIBEarity -1不带参数时退订当前连接的全部 sharded 频道。准备获取二进制与集群启动参数二进制可以按 Build From Source 从源码构建安装构建依赖Debian/Ubuntu 为ninja-build、libunwind-dev、libboost-context-dev、libssl-dev等git clone --recursive后执行./helio/blaze.sh -release再在build-opt目录ninja dragonfly也可以参考 Quick Start 使用 Docker 镜像。集群模式下的启动参数cluster-mode.md §2.2 与 §8参数说明--cluster_modeyes进入完整集群模式。在收到第一份DFLYCLUSTER CONFIG之前节点不持有任何 slot数据面命令一律返回-ERR Cluster is not yet configured--admin_portp真实集群模式必需。DFLYCLUSTER、DFLYMIGRATE只在这个 admin listener 上接受连接--cluster_node_idid可选。节点身份必须与配置 JSON 中master.id一致--cluster_announce_ipip可选。返回给客户端的 IP用于CLUSTER SLOTS/SHARDS/NODES和 MOVED 回复第一步启动本地两节点集群按仓库测试的端口约定30001 起顺序递增启动两个节点# 节点 A ./build-opt/dragonfly --port 30001 --admin_port 30002 --cluster_modeyes # 节点 B ./build-opt/dragonfly --port 30003 --admin_port 30004 --cluster_modeyes端口可换成任意不冲突的值。启动后在任意 listener不限 admin 端口上获取各节点身份redis-cli -p 30001 CLUSTER MYID redis-cli -p 30003 CLUSTER MYID第二步构造并推送 slot 配置集群拓扑由外部 cluster manager 编写并推送到每个节点。按 §4.1 的 JSON wire format 构造拓扑每个 shard 包含slot_ranges闭区间互不重叠全部 shard 合起来必须覆盖 0..16383、masterid为上一步CLUSTER MYID的输出、replicas可为空数组。下面这份示例把 16384 个 slot 对半分给节点 A 和节点 BJSON 里两处 id 是占位符请替换为各自CLUSTER MYID的实际输出[ { slot_ranges: [ { start: 0, end: 8191 } ], master: { id: 节点 A 的 CLUSTER MYID 输出, ip: 127.0.0.1, port: 30001, health: online }, replicas: [] }, { slot_ranges: [ { start: 8192, end: 16383 } ], master: { id: 节点 B 的 CLUSTER MYID 输出, ip: 127.0.0.1, port: 30003 }, replicas: [] } ]同一份 JSON 必须推送到每个节点集群内部没有 gossip。通过 admin 端口下发redis-cli -p 30002 DFLYCLUSTER CONFIG 上面的 JSON redis-cli -p 30004 DFLYCLUSTER CONFIG 上面的 JSON两个节点都返回OK表示配置生效。校验失败时slot 有缺口或重叠、节点 id 重复等返回-ERR Invalid cluster configuration.且节点保留原配置不变修正后重新推送即可。仓库的集成测试还有一个变体不设置--admin_port时直接在主端口下发DFLYCLUSTER CONFIG两种做法二选一即可。验证方式redis-cli -p 30001 CLUSTER SLOTS返回的 slot 拓扑应体现 A 拥有 0..8191、B 拥有 8192..16383。此后向不拥有某频道 slot 的节点发命令会得到-MOVED slot ip:port端点是本地配置中该 slot 的属主。第三步确认频道的 slot 归属订阅前先确认目标频道落在哪个节点上redis-cli -p 30001 CLUSTER KEYSLOT kostasKEYSLOT key是任意 listener 可用的只读查询命令。返回的 slot 号在[0, 8191]归节点 A在[8192, 16383]归节点 B。本文示例沿用仓库测试使用的频道kostas如果想控制频道落在哪个节点可以借助 hash tag只有{...}内的内容参与散列。用 MOVED 行为直接验证路由向不拥有该频道 slot 的节点执行订阅例如频道归 A 所有时redis-cli -p 30003 SSUBSCRIBE kostas -MOVED slot 127.0.0.1:30001其中slot即CLUSTER KEYSLOT返回的 slot 号。这说明SSUBSCRIBE和SPUBLISH一样先过 slot 路由检查必须连到属主节点执行。第四步SSUBSCRIBE → SPUBLISH → SUNSUBSCRIBE 完整往返连接到频道属主节点本例为节点 A并订阅redis-cli -p 30001 SSUBSCRIBE kostasSSUBSCRIBE是阻塞式订阅命令连接建立后会先收到一条订阅确认推送类型为ssubscribe末尾的数字是本次操作后剩余的订阅数。另开一个终端在同一节点发布redis-cli -p 30001 SPUBLISH kostas hello订阅端连接随后收到一条类型为smessage的推送内容为频道名 消息体。仓库测试用 redis-py 集群客户端RedisClusterpubsub().ssubscribe(...)验证的就是这两条推送文档示例输出{type: ssubscribe, pattern: None, channel: bkostas, data: 1} {type: smessage, pattern: None, channel: bkostas, data: bhello}消息的投递路径见下图来自 docs/pub-sub.mdSPUBLISH在全局ChannelStore中查找该频道的订阅者再异步分发到各订阅者所在的 I/O 线程写出。最后执行退订不带参数则退订全部 sharded 频道redis-cli -p 30001 SUNSUBSCRIBE kostas连接收到一条sunsubscribe推送测试中此时计数为 0。两个执行细节投递是异步的内部走DispatchBrief跨线程分发仓库测试在SPUBLISH后sleep(2)再取消息用脚本验证时不要假设发布与接收严格同时发生smessage类型只用于 sharded 频道与标准频道的message推送类型区分。第五步用 PUBSUB SHARDCHANNELS / SHARDNUMSUB 检查订阅状态PUBSUB SHARDCHANNELS [pattern]列出当前活跃的 sharded 频道PUBSUB SHARDNUMSUB channel...返回各频道的订阅数。仓库测试在订阅了pubsub-shard-channel和shard-channel两个频道后的验证输出文档示例redis-cli -p 30001 PUBSUB SHARDCHANNELS 1) pubsub-shard-channel 2) shard-channel redis-cli -p 30001 PUBSUB SHARDCHANNELS pubsub* 1) pubsub-shard-channel redis-cli -p 30001 PUBSUB SHARDNUMSUB pubsub-shard-channel shard-channel 1) pubsub-shard-channel 2) (integer) 1 3) shard-channel 4) (integer) 1这两个子命令只在集群模式下支持非集群节点执行会返回PUBSUB SHARDCHANNELS is not supported in non cluster mode见 src/server/main_service.cc。slot 迁移时受影响频道的强制退订当 cluster manager 推送新配置把 slot 迁走迁移协议见 cluster-mode.md §6原节点会调用UnsubscribeAfterClusterSlotMigrationsrc/server/channel_store.cc收集受影响 slot 内所有频道的订阅者整体移除并向每个受影响的连接推送sunsubscribe计数为 0。迁移集成测试验证了这条链路频道的 slot 迁到另一节点后旧节点上的订阅者收到sunsubscribe此时再到旧节点SSUBSCRIBE会被 MOVED 重定向到新属主。同样的清理也会发生在DFLYCLUSTER FLUSHSLOTS以及配置使 slot 离开属主时——节点在完成 slot 数据清扫后丢弃这些 slot 的 sharded 订阅。也就是说发生 slot 重平衡后客户端需要自行向新属主节点重新订阅受影响频道服务端不会代客迁移订阅关系。边界条件与限制全局发布订阅在集群模式不可用PUBLISH、SUBSCRIBE、PSUBSCRIBE、PUNSUBSCRIBE均被拒绝PUBLISH的确切报错为PUBLISH is not supported in cluster mode yet。从全局订阅迁移过来的应用需要把所有调用路径改成 sharded 形态且频道命名会开始参与 slot 路由。SSUBSCRIBE一次订阅多个频道时所有频道必须落在同一 slot否则触发集群的单 slot 约束被拒绝-CROSSSLOT见 cluster-mode.md §5.1。节点重启后不持有 slotcluster manager 必须重新推送当前配置节点才能恢复服务。集群模式下存储为单 DBSELECT到其他 DB 索引会被拒绝。发布端背压单个 I/O 线程上订阅者排队字节数达到硬上限publish_buffer_limit的 4 倍才会暂停发布者细节见 docs/pub-sub.md 的 Backpressure 一节。延伸阅读docs/cluster-mode.md — 集群命令面、配置 JSON 校验规则、迁移协议与失败模式docs/pub-sub.md — ChannelStore、消息分发与背压的内部实现tests/dragonfly/cluster_pubsub_test.py — 本文整条路径可运行的集成测试包括 slot 迁移场景docs/cluster-node-health.md — 配置中health字段对客户端拓扑过滤的影响。【免费下载链接】dragonflyA modern replacement for Redis and Memcached项目地址: https://gitcode.com/GitHub_Trending/dr/dragonfly创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考