Redis 主从,哨兵,集群搭建
前言
记录一下自己对 redis 主从,哨兵,集群三种模式搭建流程,redis的所有部署模式都不复杂,主要是对配置文件的书写,以及各个模式的优缺点分析。
部署环境
操作系统 CentOS7
Redis版本:Redis7.0.5
主从模式
优点:配置简单,快速,读写分离,完全分担了主节点的读压力,并且从节点还可套娃继续配置多层从节点。
缺点:非高可用,主节点宕机,则失去写能力,数据冗余量大,每个从节点100%复制主节点数据。
非高可用架构,生产环境一般不考虑
配置流程:
1、配置从节点 redis.conf 文件
主从节点密码最好都保持一致。
2、配置主节点 redis.conf 文件
则正常设置验证密码和远程连接信息即可
配置效果:
哨兵模式
优点:哨兵模式解决了主从集群中主节点宕机导致不可写入问题,当主节点宕机时,sentinel将会监控到主节点已经不可用,则从剩余可用从节点中选举出新的主节点,从而解决不可写问题。之前的主节点启动之后将会变成从节点加入到集群中。
缺点:依然存在大量数据冗余,并且哨兵节点不会参加数据存储,计算资源存在浪费,存储能力得不到提升,写能力得不到提升,存在中心化。
注意:
哨兵节点本身不存储数据。
哨兵节点至少3个并必须为奇数节点个数 (基于Raft算法进行选举)。
哨兵节点必须独立部署且只跑哨兵进程应用,不要跑其他应用程序,避免哨兵进入TILT模式,其他应用存在硬件资源抢占问题,导致哨兵监控可靠性下降。
哨兵模式基于主从模式。
1主2从+3个哨兵已经是6个计算实例资源。在生产环境中哨兵必须单独部署,不能部署到主节点或子节点上,以保证整个集群的稳定性。
此模式可用于生产环境,高可用架构,保留了redis所有得功能。
Sentinel节点配置流程
(主从模式已经配置好后):
1、配置 sentinel.conf 文件 设置监听 master 地址。会自动通过主节点info信息中读取对应从节点信息。
2、保证所有主从节点密码一致。
3、通过redis-sentinel 命令启动哨兵。
4、spring-boot配置哨兵连接。
如果哨兵节点数过多,可分行配置:
哨兵分主观下线以及客观下线,只有当所有哨兵都认为主节点以及不可用时才会选举投票。在选举期间,整个集群无法对外提供服务。
主观下线
SDOWN: subjectively down 直接翻译的为”主观”失效,即当前sentinel实例认为某个redis服务为”不可用”状态.
客观下线
ODOWN:objectively
down,直接翻译为”客观”失效,即多个sentinel实例都认为master处于”SDOWN”状态,那么此时master将处于ODOWN,ODOWN可以简单理解为master已经被集群确定为”不可用”,将会开启故障转移机制.
集群模式
官方文档:使用 Redis 集群|进行扩展
1、Twemproxy (Twitter开源的Redis代理 Twemproxy)
- 没有友好的监控管理后台界面,不利于运维监控。
- Twemproxy最大的痛点在于,无法平滑地扩容/缩容。对于运维人员来说,当因为业务需要增加Redis实例时工作量非常大。
2、Codis(豌豆荚自主研发)
- 有UI管理界面。
- 可以很好的动态添加节点。
3、官方搭建方案 Redis Cluster
优点:集群模式相对于哨兵模式来说,去除了中心化思想,自动实现了负载均衡,并且数据存储的上限随着节点数的增加而增加。节点之间使用轻量级协议,减少带宽占用,支持动态扩展节点,集群采用哈希槽(hash Slot)来处理实例之间的映射关系,在集群中总共有16384个哈希槽,默认形式是将16384个哈希槽分配给所有的节点,每个实例节点分配一段哈希槽类似数据分区,每个键值按照CRC16算法得到哈希值再将其对16384取模**CRC16(key)mod 16384 **通过最终的结果得到key值存在的哈希槽位置。
1、写能力得到提升。
2、存储能得到提升。
3、去中心化。
缺点:存在数据存储倾斜问题与数据访问倾斜
数据访问倾斜
数据在切片集群的多个实例上分布不均衡,大量数据集中到了一个或几个实例上,存储压力得不到友好分摊且热点数据访问总会落到固定实例上从而导致实例压力增大,最终面临宕机风险。
数据倾斜产生主要原因有三个:
1、保存了bigkey。
bigkey 的 value 值很大(String 类型),或者是 bigkey 保存了大量集合元素(集合类型),会导致这个实例的数据量增加,内存资源消耗也相应增加。而且,bigkey 的操作一般都会造成实例 IO 线程阻塞,如果 bigkey 的访问量比较大,就会影响到这个实例上的其它请求被处理的速度。
为了避免 bigkey 造成的数据倾斜,一个根本的应对方法是,我们在业务层生成数据时,要尽量避免把过多的数据保存在同一个键值对中。如果 bigkey 正好是集合类型,我们还有一个方法,就是把 bigkey 拆分成很多个小的集合类型数据,分散保存在不同的实例上。
2、Slot 分配不均衡。
如果集群运维人员没有均衡地分配 Slot,就会有大量的数据被分配到同一个 Slot 中,而同一个 Slot 只会在一个实例上分布,这就会导致,大量数据被集中到一个实例上,造成数据倾斜。
我们可以通过运维规范,在分配之前,我们就要避免把过多的 Slot 分配到同一个实例。如果是已经分配好 Slot 的集群,我们可以先查看 Slot 和实例的具体分配关系,从而判断是否有过多的 Slot 集中到了同一个实例。如果有的话,就将部分 Slot迁移到其它实例,从而避免数据倾斜。
不同集群上查看 Slot 分配情况的方式不同:如果是 Redis Cluster,就用 CLUSTER SLOTS 命令;如果是 Codis,就可以在 codis dashboard-UI控制板上查看。
3、使用了 Hash Tag。
Hash Tag 是指加在键值对 key 中的一对花括号{}。这对括号会把 key的一部分括起来,客户端在计算 key 的 CRC16 值时,只对 Hash Tag 花括号中的 key 内容进行计算。
假设 key 是 user:profile:3231,我们把其中的 3231 作为 Hash Tag,此时,key 就变成了 user:profile:{3231}。当客户端计算这个 key 的 CRC16 值时,就只会计算3231 的 CRC16 值。否则,客户端会计算整个“user:profile:3231”的 CRC16 值。
使用 Hash Tag 的好处是,如果不同 key的Hash Tag 内容都是一样的,那么,这些 key对应的数据会被映射到同一个 Slot 中,同时会被分配到同一个实例上。
Hash Tag 一般用在什么场景呢?其实,它主要是用在 Redis Cluster 和 Codis中,支持事务操作和范围查询。因为 Redis Cluster 和 Codis 本身并不支持跨实例的事务操作和范围查询,当业务应用有这些需求时,就只能先把这些数据读取到业务层进行事务处理,或者是逐个查询每个实例,得到范围查询的结果。
可以使用 Hash Tag 把要执行事务操作或是范围查询的数据映射到同一个实例上,这样就能很轻松地实现事务或范围查询了。
但是,使用 Hash Tag 的潜在问题,就是大量的数据可能被集中到一个实例上,导致数据倾斜,集群中的负载不均衡。那么,该怎么应对这种问题呢?我们就需要在范围查询、事务执行的需求和数据倾斜带来的访问压力之间,进行取舍了。
我建议是,如果使用 Hash Tag 进行切片的数据会带来较大的访问压力,就优先考虑避免数据倾斜,最好不要使用 Hash Tag 进行数据切片。因为事务和范围查询都还可以放在客户端来执行,而数据倾斜会导致实例不稳定,造成服务不可用。
数据访问倾斜的成因和应对方法:
发生数据访问倾斜的根本原因,就是实例上存在热点数据(比如新闻应用中的热点新闻内容、电商促销活动中的热门商品信息,等等)。一旦热点数据被存在了某个实例中,那么,这个实例的请求访问量就会远高于其它实例,面临巨大的访问压力。
那么,该如何应对呢?
热点数据通常是一个或几个数据,所以,直接重新分配 Slot 并不能解决热点数据的问题。通常来说,热点数据以服务读操作为主,在这种情况下,我们可以采用热点数据多副本的方法来应对。
具体做法是,把热点数据复制多份,在每一个数据副本的 key 中增加一个随机前缀,让它和其它副本数据不会被映射到同一个 Slot 中。这样一来,热点数据既有多个副本可以同时服务请求,同时,这些副本数据的 key 又不一样,会被映射到不同的 Slot中。在给这些 Slot 分配实例时,我们也要注意把它们分配到不同的实例上,那么,热点数据的访问压力就被分散到不同的实例上了。
注意:热点数据多副本方法只能针对只读的热点数据。如果热点数据是有读有写的话,就不适合采用多副本方法了,因为要保证多副本间的数据一致性,会带来额外的开销。对于有读有写的热点数据,我们就要给实例本身增加资源了,例如使用配置更高的机器,来应对大量的访问压力。
注意:
Redis Cluster节点之间会定期交换Gossip消息,以及做一些心跳检测
官方建议Redis Cluster节点数量不要超过1000个,当集群中节点数量过多时,会产生不容忽视的带宽消耗
消息发送频率:节点发现与其他节点最后通信时间超过cluster-node-timeout /2时,会直接发送PING消息
消息数据量:slots槽数组(2kb空间)和整个集群1/10的状态数据(10个节点状态数据约为1kb)
节点部署的机器规模:集群分布的机器越多且每台机器划分的节点数越均匀,则集群内整体的可用带宽越高
Redis Cluster 集群的限制:
key批量操作支持有限:例如mget,mset必须在一个slot
key事务和Lua支持有限:操作的key必须在一个节点
key是数据分区的最小粒度:不支持bigkey分区
不支持多个数据库:集群模式下只有一个db0
复制只支持一层:不支持树形复制结构
Redis Cluster满足容量和性能的扩展性,很多业务'不需要'
大多数时客户端性能会'降低'
命令无法跨节点使用:mget,keys,scan,flush,sinter等
Lua和事务无法跨节点使用
客户端维护更复杂:SDK和应用本身消耗(例如更多的连接池)
很多场景Redis Sentinel已经够用了。
Codis与Redis Cluster集群对比:
Redis Cluster总结
1.Redis Cluster数据分区规则采用虚拟槽方式(16384个槽),每个节点负责一部分槽和相关数据,实现数据和请求的负载均衡
2.搭建Redis Cluster划分四个步骤:准备节点,meet操作,分配槽,复制数据。
3.Redis官方推荐使用redis-trib.rb工具快速搭建Redis Cluster(redis5.0版本之前使用redis-trib,之后版本使用redis-cli命令)
4.集群伸缩通过在节点之间移动槽和相关数据实现,扩容时根据槽迁移计划把槽从源节点迁移到新节点,收缩时如果下线的节点有负责的槽需要迁移到其他节点,再通过cluster forget命令让集群内所有节点忘记被下线节点
5.使用smart客户端操作集群过到通信效率最大化,客户端内部负责计算维护键,槽以及节点的映射,用于快速定位到目标节点
6.集群自动故障转移过程分为故障发现和节点恢复。节点下线分为主观下线和客观下线,当超过半数节点认为故障节点为主观下线时,标记这个节点为客观下线状态。从节点负责对客观下线的主节点触发故障恢复流程,保证集群的可用性
7.开发运维常见问题包括:超大规模集群带席消耗,pub/sub广播问题,集群倾斜问题,单机和集群对比等
使用官方redis-cli 命令构建 Redis Cluster 流程(搭建版本7.0.4):
至少6节点,(1主+1从)*3=6节点
redis 5.0版本之前使用redis-trib工具,之后版本使用redis-cli命令
1、设置redis.conf 文件
所有节点的密码相同,然后设置开启集群模式 (更多配置细节查看官网文档)
cluster-enabled yes
redis-cli --cluster create --cluster-replicas 1 192.168.121.145:6379 192.168.121.143:6379 192.168.121.142:6379 192.168.121.141:6379 192.168.121.144:6379 192.168.121.140:6379 -a 【密码】
redis-cli --cluster或者./redis-trib.rb:代表集群操作命令
create:代表是创建集群
--replicas 1或者--cluster-replicas 1 :指定集群中每个master的副本个数为1,此时节点总数 ÷ (replicas + 1) 得到的就是master的数量。因此节点列表中的前n个就是master,其它节点都是slave节点,随机分配到不同master
输入命令后会提示你,请确认集群slot分配,必须输入完整的yes而不是y,不然会跳过slot自动分配,集群不可用。如果未分配则可以使用 redis-cli --cluster fix 127.0.0.1:6379(任意节点) -a 【密码】 命令进行slot修复
通过日志输出看到,集群已经自动创建完毕
输入命令查看当前集群节点信息。
redis-cli -h 【任意节点ip】 -p【端口】 -a【密码】cluster nodes
下图;为节点信息(当前未分配slot)
执行slot分配(可以看到每个master负责的slot槽)
尝试插入值
通过UI工具查看值是否存入。连接集群任意节点即可
可见redis 集群已经成功搭建。
通过spring-boot连接集群: