这种上层的包装,虽然极大地方便了集群的关注点和线性扩展,在目前落地方案里 Redis也已经尽力扩展完善,但依然还是处于半自动状态。集群是分布的 N个 node,如需要伸展为 N+2个node,那么可以手动或者结合其他辅助框架给每个 node进行划分和调整,一般均衡数约为 16384 /(N+2) slot。同样的,Cluster 的Sharding 在实际落地之前,也需要注意到其不适合的场景,并根据实际数据体量和 QPS瓶颈来合理扩展node,同时处理事务型的应用、统计查询等,对比单机自然是效率较低,这时候可能需要权衡规避过多的扩展,越多从来都不代表越稳定或者说性能越高。
二、谈谈缓存的集群实践与相关细节
2.1 提下集群的流程
我在之前一篇文章里,主要围绕主从和高可用进行了一些讨论(主从和主备高可用篇:https://www.cnblogs.com/bsfz/p/9769503.html),要提出的是 Master-Slave 结构上来说同样算是一种集群的表现形式,而在 Redis Cluster 方案里,则更侧重分布式数据分片集群,性能上能规避一些冗余数据的内存浪费以及木桶效应,并同时具备类似 Sentinel机制的 HA和 Failover等特性(但要注意并非完全替换)。
这里同样涉及到运维、架构 、开发等相关,但个人依然侧重于针对架构和开发来做一些讨论。 当然,涉及架构中对网络I/O、CPU的负载,以及某些场景下的磁盘I/O的代价等问题的权衡,其实大体都是相通的,部分可参见之前文章中的具体阐述。
简单说在集群模式 Redis Cluster 下, node 的角色分为 Master node 和 Slave node,明面上不存在第三角色。 Master node 将被分配一定范围的 slots 作为数据 Sharding 的承载,而 Slave node 则主要负责数据的复制(相关交互细节可参照上一篇) 并进行出现故障时半自动完成故障转移(HA的实现)。node之间的通信依赖一个相对完善的去中心化的高容错协议Gossip, 当扩展node、node不可达、node升级、 slots修改等时, 内部需要经过一段较短时间的反复ping/pong消息通信, 并最终达到集群状态同步一致。
以 Redis 3.x 举例,假定一共 10 个 node,Master / Slave = 5 / 5,执行基础握手指令 " cluster meet [ip port] "后,就能很快在 cluster nodes里看到相应会话日志信息,在这个基础上,再给每个node 添加指定 Range 的 lots( addslots指令),就基本完成了 Redis Cluster的基础构建。(当然,如果是侧重运维,一般你可以手动自定义配置,也可以使用 redis-trib.rb来辅助操作,这里不讨论)。
2.2 Redis Cluster的部分限制
Redis node的拓扑结构设计,目前只能采用单层拓扑,即不可直接进行树状延伸扩展node,注意这里是不同于 Redis Mater-Slave 基本模式的,然后记得在上一篇也提到了本人迄今为止也并未有机会在项目中使用,也是作为备用。
对于原有 DB空间的划分基本等同取消,这个有在第一篇设计细节话题中提到过,并且 Redis Cluster 模式下只能默认使用第一个DB, 即索引为0 标识的库。
假如存在大数据表 “Table”,例如 hash、list 等,是不可以直接采用更细粒度的操作来 Sharding 的,即使强制分散到不同 node 中,也会造成 slot 的覆盖错误。
缓存数据的批量操作无法充分支持,如 mset / mget 并不能直接操作到所有对应 key中,除非是具有相同 slot。 这是由于 Sharding机制原理决定的,举一反三,若是存在事务操作,也存在相关的限制(另外稍微注意,截止目前,不同node 本身也是无法事务关联的)。
2.3 Redis Cluster的相关细节考虑