上篇文章说到最小资源下的redis主从高可用架构,但毕竟单台服务器的性能有限,随着业务的发展也会出现请求变慢的情况,这时就该对redis做拆分了,和数据库类似,有垂直拆分和水平拆分。
所谓垂直拆分,就是再搭建多个其他的redis主从结构,将部分业务的缓存迁移到这些新redis上;比如在电商业务中,订单服务、购物车服务、支付服务、库存服务等均使用自己独立的redis。
垂直拆分也有一些问题:①架构变得很冗余,每个业务都要维护自己的redis服务;②不适合大型服务,毕竟不可能拆分出出太多redis服务,那维护成本就不可计了。这时候会采用水平拆分的方法,即通过分片的方式,根据某些算法,将不同key-value值,存储到不同的redis分片上;这些分片会按照既定策略存储在不同redis机器中。
redis-cluster的基本原理
redis官方提供了大规模集群方案,redis-cluster方案中,会将整个redis数据库切成16384份(2^14次方),redis集群会将这些分片尽可能均匀的分给所有的redis-node(主节点);为了防止redis-node主节点宕机,每个主节点node也会有自己的slave节点,主节点把自己分到的数据都会同步给slave节点,一旦主节点宕机,redis集群会将其对应的slave节点升级为主节点。
假设集群中有三个主节点A、B、C,每个主节点都有自己的备节点A1、B1、C1,则每个节点默认分得的分片如下:
- A节点包含0 - 5500分片,A1节点会复制A节点的0-5500分片
- B节点包含5501 - 11000分片,B1节点会复制B节点的5501-11000分片
- C节点包含11001 - 16383分片,C1节点会复制C节点的11001 - 16383分片
redis-cluster key值到切片的分配规则
redis-cluster在收到存储数据请求时,会将key值进行CRC16(一种通信领域的冗余校验算法,效率很高)计算,得到32位的数字,之后再 % 16384,根据取模的结果来决定将该key-value对应哪个分片(官方叫hash slot,哈希槽),再根据分片找到对应的redis-node,即完成了key值到node的映射。
redis-cluster支持在一条命令中操作多个key-value值,但前提是这些key-value值都在同一个分片;可以在key中使用{}的方式强制将某些key-value对应到一个分片上,redis只会取{}中的数据进行分片计算。 如下面两个key计算出来的hash slot是一致的。
127.0.0.1:7000> set user:lily{1024} "lily-hello"
OK
127.0.0.1:7000> set email:lily{1024} "lily@123.com"
OK
127.0.0.1:7000> get user:lily{1024}
"lily-hello"
127.0.0.1:7000> get email:lily{1024}
"lily@123.com"
127.0.0.1:7000> CLUSTER KEYSLOT user:lily{1024}
(integer) 2776
127.0.0.1:7000> CLUSTER KEYSLOT email:lily{1024}
(integer) 2776
redis-cluster需要注意的几点
生产环境的redis-cluster集群肯定有多台主节点,每个主节点也会有至少一个备节点,这种架构虽然已经尽量高可用,但也有需要注意的地方。假设集群有主节点A、B、C,以及备节点A1、B1、C1
- 如果主节点A宕了,则集群会将A1提升为主节点,继续提供服务;但如果A、A1同时宕,则整个集群就无法工作了。
- redis主从会自动同步,这种异步操作,也就是主节点先给客户端响应,再同步数据给备节点;如果主节点恰好在同步之前宕了,则本次写入就丢失了。redis本身不提供强完整性存储,这也是其在吞吐率与完整性之间的取舍。
- 如果生产环境网络故障,A、C、A1、B1、C1之间可以互通;B没有宕,而是网络与其他节点不通,客户端能访问B,这时客户端还可以对B进行读写;如果网络在B1晋升主节点之前恢复,则数据不会丢;但如果网络迟迟不通,B1晋升为主节点,待网络恢复后,B会被判定为备节点,客户端在网络中断期间写入的数据就丢了。
搭建集群
-
启动集群模式的redis-server,配置文件redis-server.conf,如下:
port 7000 bind 0.0.0.0 protected-mode no cluster-enabled yes cluster-config-file nodes.conf #nodes.conf会自动生成 cluster-node-timeout 5000 appendonly yes直接用命令启动即可:
nohup redis-server redis-server.conf > redis.log 2>&1 & - 复制上面的配置文件,再多启动几台redis-server,假设启动了8台
-
使用上面的8台redis组建集群,四个主、四个备
redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 \ 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006 127.0.0.1:7007 \ --cluster-replicas 1组完集群之后,可以看下集群状态:
# redis-cli -p 7006 cluster nodes 0a7f459a99ba85e8e36d865aeb7692b2ebc13444 10.57.5.31:7007@17007 master - 0 1764389404276 12 connected 12288-16383 f6d4d103c5f8d208139a172d422f5a74f436a8b1 10.57.5.31:7005@17005 master - 0 1764389405000 14 connected 0-4095 f31d653e839715bdb66fe60fa0fa25510af3049e 10.57.5.31:7000@17000 slave f6d4d103c5f8d208139a172d422f5a74f436a8b1 0 1764389404577 14 connected fde095c3f5808e534066ce45de3b32eb541597c3 10.57.5.31:7001@17001 slave 0a7f459a99ba85e8e36d865aeb7692b2ebc13444 0 1764389404075 12 connected 079934e5c72c08fbdf0e685c3f87aecf6f3a9849 10.57.5.31:7002@17002 slave de98a29bf19da52ea6f7e7b3d691f05602e930b9 0 1764389405581 13 connected c33283d8114d8f3a0a9f3d5f0af29fb0e030e4a9 10.57.5.31:7003@17003 master - 0 1764389405581 15 connected 8192-12287 f7175fe56837212df30592a92ae0a1c879371cab 10.57.5.31:7006@17006 myself,slave c33283d8114d8f3a0a9f3d5f0af29fb0e030e4a9 0 1764389405000 9 connected de98a29bf19da52ea6f7e7b3d691f05602e930b9 10.57.5.31:7004@17004 master - 0 1764389405280 13 connected 4096-8191
可以看到上面有4个主节点,瓜分了16384个分片,并且每个主节点有1个备节点。
redis-cluster扩容和缩容
上面提到redis-cluster默认会尽可能平均地将分片分配到各个主节点上,但同时也支持人工调整分片,可以在不影响整个集群读写的情况下,把一些分片从一个node迁移至其他node,这就为redis-cluster集群扩容、缩容提供了便利。
扩容
4个主节点如下:
# redis-cli -p 7006 cluster nodes | grep master
0a7f459a99ba85e8e36d865aeb7692b2ebc13444 10.57.5.31:7007@17007 master - 0 1764388865648 12 connected 12288-16383
f6d4d103c5f8d208139a172d422f5a74f436a8b1 10.57.5.31:7005@17005 master - 0 1764388866000 14 connected 0-4095
c33283d8114d8f3a0a9f3d5f0af29fb0e030e4a9 10.57.5.31:7003@17003 master - 0 1764388865549 15 connected 8192-12287
de98a29bf19da52ea6f7e7b3d691f05602e930b9 10.57.5.31:7004@17004 master - 0 1764388866651 13 connected 4096-8191
现在要再扩容1主+1备节点
-
继续按照上面的方式,再启动两台redis-server 7008、7009
# ps aux | grep redis root 248584 0.2 0.0 63040 7844 pts/1 Sl 10:50 0:10 redis-server 0.0.0.0:7000 [cluster] root 248638 0.2 0.0 63040 7848 pts/1 Sl 10:51 0:10 redis-server 0.0.0.0:7001 [cluster] root 248754 0.2 0.0 63040 7820 pts/1 Sl 10:54 0:10 redis-server 0.0.0.0:7002 [cluster] root 248769 0.3 0.0 67136 7724 pts/1 Sl 10:54 0:19 redis-server 0.0.0.0:7003 [cluster] root 248784 0.4 0.0 64576 7860 pts/1 Sl 10:54 0:22 redis-server 0.0.0.0:7004 [cluster] root 248799 0.3 0.0 60992 7864 pts/1 Sl 10:54 0:19 redis-server 0.0.0.0:7005 [cluster] root 248814 0.2 0.0 63040 7884 pts/1 Sl 10:54 0:10 redis-server 0.0.0.0:7006 [cluster] root 248832 0.4 0.0 60992 7876 pts/1 Sl 10:55 0:23 redis-server 0.0.0.0:7007 [cluster] root 249143 0.1 0.0 55872 7396 pts/1 Sl 12:17 0:00 redis-server 0.0.0.0:7008 [cluster] root 249177 0.1 0.0 55872 7308 pts/1 Sl 12:18 0:00 redis-server 0.0.0.0:7009 [cluster] -
将7008节点加入到集群中
redis-cli --cluster add-node 127.0.0.1:7008 127.0.0.1:7000可以查看一下节点的状态,如下面7008已经加入到集群中,成为了主节点,但是并没有分得切片:
# redis-cli -p 7006 cluster nodes 0a7f459a99ba85e8e36d865aeb7692b2ebc13444 10.57.5.31:7007@17007 master - 0 1764390168039 12 connected 12288-16383 f6d4d103c5f8d208139a172d422f5a74f436a8b1 10.57.5.31:7005@17005 master - 0 1764390168541 14 connected 0-4095 c33283d8114d8f3a0a9f3d5f0af29fb0e030e4a9 10.57.5.31:7003@17003 master - 0 1764390168541 15 connected 8192-12287 f31d653e839715bdb66fe60fa0fa25510af3049e 10.57.5.31:7000@17000 slave f6d4d103c5f8d208139a172d422f5a74f436a8b1 0 1764390168000 14 connected ee1de1a198b083429ccf79e784464cc5564138de 10.57.5.31:7008@17008 master - 0 1764390169000 0 connected fde095c3f5808e534066ce45de3b32eb541597c3 10.57.5.31:7001@17001 slave 0a7f459a99ba85e8e36d865aeb7692b2ebc13444 0 1764390169043 12 connected f7175fe56837212df30592a92ae0a1c879371cab 10.57.5.31:7006@17006 myself,slave c33283d8114d8f3a0a9f3d5f0af29fb0e030e4a9 0 1764390167000 9 connected 079934e5c72c08fbdf0e685c3f87aecf6f3a9849 10.57.5.31:7002@17002 slave de98a29bf19da52ea6f7e7b3d691f05602e930b9 0 1764390167537 13 connected de98a29bf19da52ea6f7e7b3d691f05602e930b9 10.57.5.31:7004@17004 master - 0 1764390169545 13 connected 4096-8191 -
将7009节点以备节点身份加入到集群中
redis-cli --cluster add-node 127.0.0.1:7009 127.0.0.1:7000 --cluster-slave如下执行结果,可以看到集群自动将7009设置为7008的备用节点:
[OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. Automatically selected master 10.57.5.31:7008 >>> Send CLUSTER MEET to node 127.0.0.1:7009 to make it join the cluster. Waiting for the cluster to join >>> Configure node as replica of 10.57.5.31:7008. [OK] New node added correctly.当然也可以手动指定主节点,如下(不一定非得是7008,任何其他主节点都可以):
redis-cli --cluster add-node 127.0.0.1:7009 127.0.0.1:7000 --cluster-slave --cluster-master-id ee1de1a198b083429ccf79e784464cc5564138de -
手动修改集群中节点的身份
-
主节点修改为备用节点,将7008设置为其他主节点的备用节点:
# redis-cli -p 7008 -c 127.0.0.1:7008> cluster replicate c33283d8114d8f3a0a9f3d5f0af29fb0e030e4a9 OK 127.0.0.1:7008> cluster nodes f7175fe56837212df30592a92ae0a1c879371cab 10.57.5.31:7006@17006 slave c33283d8114d8f3a0a9f3d5f0af29fb0e030e4a9 0 1764390644105 15 connected 0a7f459a99ba85e8e36d865aeb7692b2ebc13444 10.57.5.31:7007@17007 master - 0 1764390646514 12 connected 12288-16383 f6d4d103c5f8d208139a172d422f5a74f436a8b1 10.57.5.31:7005@17005 master - 0 1764390645000 14 connected 0-4095 c540cbb9f7ad78223e3c7adfc647bf0067f2b3a9 10.57.5.31:7009@17009 slave ee1de1a198b083429ccf79e784464cc5564138de 0 1764390645000 15 connected 079934e5c72c08fbdf0e685c3f87aecf6f3a9849 10.57.5.31:7002@17002 slave de98a29bf19da52ea6f7e7b3d691f05602e930b9 0 1764390644808 13 connected fde095c3f5808e534066ce45de3b32eb541597c3 10.57.5.31:7001@17001 slave 0a7f459a99ba85e8e36d865aeb7692b2ebc13444 0 1764390645000 12 connected ee1de1a198b083429ccf79e784464cc5564138de 10.57.5.31:7008@17008 myself,slave c33283d8114d8f3a0a9f3d5f0af29fb0e030e4a9 0 1764390644000 0 connected de98a29bf19da52ea6f7e7b3d691f05602e930b9 10.57.5.31:7004@17004 master - 0 1764390645510 13 connected 4096-8191 f31d653e839715bdb66fe60fa0fa25510af3049e 10.57.5.31:7000@17000 slave f6d4d103c5f8d208139a172d422f5a74f436a8b1 0 1764390645000 14 connected c33283d8114d8f3a0a9f3d5f0af29fb0e030e4a9 10.57.5.31:7003@17003 master - 0 1764390645811 15 connected 8192-122877008成为7003的备用节点后,会自动同步7003节点上的数据;同时7009依旧是7008的备用节点,其也会同步7008的数据。
-
备用节点,晋升为主节点,其实就是手动切换主从
redis-cli -p 7008 CLUSTER FAILOVER TAKEOVER上面的命令会,让7008晋升为主节点,然后7003降级为备节点
-
备用节点,断开与之前主节点的关系,晋升新的主节点,这种情况需要操作两步:
① 断开7008与7003的主从关系:redis-cli -p 7008 CLUSTER RESET SOFT 不删除7008上面的数据 redis-cli -p 7008 CLUSTER RESET 删除7008上面的数据② 断开之后,7008就游离于集群之外了,将其重新加进来即可;可以看到下面7008成为主节点,但不持有分片
# redis-cli -p 7008 -c 127.0.0.1:7008> CLUSTER MEET 10.57.5.31 7000 OK 127.0.0.1:7008> cluster nodes f7175fe56837212df30592a92ae0a1c879371cab 10.57.5.31:7006@17006 slave c33283d8114d8f3a0a9f3d5f0af29fb0e030e4a9 0 1764392884566 20 connected 0a7f459a99ba85e8e36d865aeb7692b2ebc13444 10.57.5.31:7007@17007 master - 0 1764392884566 12 connected 12288-16383 f6d4d103c5f8d208139a172d422f5a74f436a8b1 10.57.5.31:7005@17005 master - 0 1764392884767 14 connected 0-4095 c540cbb9f7ad78223e3c7adfc647bf0067f2b3a9 10.57.5.31:7009@17009 slave c33283d8114d8f3a0a9f3d5f0af29fb0e030e4a9 0 1764392882560 20 connected 079934e5c72c08fbdf0e685c3f87aecf6f3a9849 10.57.5.31:7002@17002 slave de98a29bf19da52ea6f7e7b3d691f05602e930b9 0 1764392884566 13 connected fde095c3f5808e534066ce45de3b32eb541597c3 10.57.5.31:7001@17001 slave 0a7f459a99ba85e8e36d865aeb7692b2ebc13444 0 1764392883062 12 connected ee1de1a198b083429ccf79e784464cc5564138de 10.57.5.31:7008@17008 myself,master - 0 1764392884000 19 connected de98a29bf19da52ea6f7e7b3d691f05602e930b9 10.57.5.31:7004@17004 master - 0 1764392883000 13 connected 4096-8191 f31d653e839715bdb66fe60fa0fa25510af3049e 10.57.5.31:7000@17000 slave f6d4d103c5f8d208139a172d422f5a74f436a8b1 0 1764392882560 14 connected c33283d8114d8f3a0a9f3d5f0af29fb0e030e4a9 10.57.5.31:7003@17003 master - 0 1764392884000 20 connected 8192-12287
-
-
给7008分配数据分片
可以强制redis集群将分片分给空节点:# redis-cli --cluster rebalance 127.0.0.1:7000 --cluster-use-empty-masters >>> Performing Cluster Check (using node 127.0.0.1:7000) [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. >>> Rebalancing across 5 nodes. Total weight = 5.00 Moving 820 slots from 10.57.5.31:7003 to 10.57.5.31:7008 Moving 820 slots from 10.57.5.31:7005 to 10.57.5.31:7008 Moving 820 slots from 10.57.5.31:7007 to 10.57.5.31:7008 Moving 820 slots from 10.57.5.31:7004 to 10.57.5.31:7008也可以手动迁移:
redis-cli --cluster reshard 127.0.0.1:7000 -
将7009设置为7008的备用节点,类似第4步中的操作,最终5主5备的效果如下:
127.0.0.1:7009> cluster nodes f7175fe56837212df30592a92ae0a1c879371cab 10.57.5.31:7006@17006 slave c33283d8114d8f3a0a9f3d5f0af29fb0e030e4a9 0 1764393418677 20 connected 0a7f459a99ba85e8e36d865aeb7692b2ebc13444 10.57.5.31:7007@17007 master - 0 1764393419178 12 connected 13108-16383 f31d653e839715bdb66fe60fa0fa25510af3049e 10.57.5.31:7000@17000 slave f6d4d103c5f8d208139a172d422f5a74f436a8b1 0 1764393418000 14 connected fde095c3f5808e534066ce45de3b32eb541597c3 10.57.5.31:7001@17001 slave 0a7f459a99ba85e8e36d865aeb7692b2ebc13444 0 1764393418576 12 connected ee1de1a198b083429ccf79e784464cc5564138de 10.57.5.31:7008@17008 master - 0 1764393419078 21 connected 0-819 4096-4915 8192-9011 12288-13107 de98a29bf19da52ea6f7e7b3d691f05602e930b9 10.57.5.31:7004@17004 master - 0 1764393419580 13 connected 4916-8191 f6d4d103c5f8d208139a172d422f5a74f436a8b1 10.57.5.31:7005@17005 master - 0 1764393419580 14 connected 820-4095 079934e5c72c08fbdf0e685c3f87aecf6f3a9849 10.57.5.31:7002@17002 slave de98a29bf19da52ea6f7e7b3d691f05602e930b9 0 1764393418174 13 connected c33283d8114d8f3a0a9f3d5f0af29fb0e030e4a9 10.57.5.31:7003@17003 master - 0 1764393420181 20 connected 9012-12287 c540cbb9f7ad78223e3c7adfc647bf0067f2b3a9 10.57.5.31:7009@17009 myself,slave ee1de1a198b083429ccf79e784464cc5564138de 0 1764393418000 16 connected
缩容
当业务流量高峰过后,会对集群进行缩容,节约成本。这里再把7008、7009两个节点剔除集群。
-
首先要把7008这个主节点上的分片迁移到其他主节点上
redis-cli --cluster reshard 127.0.0.1:7000 -
断开7009和7008与集群的关系
redis-cli -p 7008 cluster reset redis-cli -p 7009 cluster reset -
上面两部操作之后,7008、7009会成为两个主节点,但不承载分片;最后从集群删掉即可。
# redis-cli --cluster del-node 127.0.0.1:7000 ee1de1a198b083429ccf79e784464cc5564138de >>> Removing node ee1de1a198b083429ccf79e784464cc5564138de from cluster 127.0.0.1:7000 >>> Sending CLUSTER FORGET messages to the cluster... []()>>> SHUTDOWN the node.
结言
- redis-cluster提供了大规模集群的成熟解决方案,具体采用sentinel主从结构,还是集群,最终还是要看业务的现状与规划,适合自己才是最好的。
- redis的吞吐率非常高,这跟其异步同步的架构设计有关,也决定了其在一致性方案有点缺陷。
- redis的异步同步机制,决定了即使采用了高可用架构,在极端场景下也会丢数据;如果是对一致性要求非常高的业务,需要从业务层面进行兜底。
- 高可用设计是个很宏大的方向,除了软件架构层面、也涉及到底层基础设施;比如现实中,也会出现一条光缆、网络线路被挖断,整个机房宕掉的情况。最终还是要回归业务需求,设计出最适合当前业务的架构,就是最佳的。
版权声明
本站文章、图片、视频等(除转载外),均采用知识共享署名 4.0 国际许可协议(CC BY-NC-SA 4.0),转载请注明出处、非商业性使用、并且以相同协议共享。
© 空空博客,本文链接:https://www.yeetrack.com/?p=1731
近期评论