redis哨兵、redis集群
哨兵
主从:一主两从,如果一个从库挂掉,不影响整体对外服务的,但如果主库挂掉,不能再写入数据了,整个服务就有问题
我们需要保证,高可用:服务的高度可用性 99.999%可用性,使用redis的哨兵(sentinel),保证高可用
主从复制存在的问题
- 主从复制,主节点发生故障,需要做故障转移,可以手动转移:让其中一个slave变成master:哨兵解决
- 主从复制,只能主写数据,所以写能力和存储能力有限:集群解决
哨兵原理
可以做故障判断,故障转移,通知客户端(其是是一个进程),客户端直接连接sentinel的地址
- 多个sentinel发现并确认master有问题
- 选举出一个sentinel作为领导
- 选取一个slave作为新的master
- 通知其余slave成为新的master的slave
- 通知客户端主从变化
- 等待老的master复活成为新master的slave
搭建哨兵
- 三个哨兵:三个进程
- 一主两从:3个redis服务
搭建步骤
第一步:搭建一主两从
# 第一个是主配置文件
daemonize yes
pidfile /var/run/redis.pid
port 6379
dir "/root/redis/data"
logfile 6379.log
# 第二个是从配置文件
daemonize yes
pidfile /var/run/redis2.pid
port 6378
dir "/root/redis/data1"
logfile 6378.log
slaveof 127.0.0.1 6379
slave-read-only yes
# 第三个是从配置文件
daemonize yes
pidfile /var/run/redis3.pid
port 6377
dir "/root/redis/data2"
logfile 6377.log
slaveof 127.0.0.1 6379
slave-read-only yes
把这三个redis服务都启动起来
redis-server ./redis_6379.conf
redis-server ./redis_6378.conf
redis-server ./redis_6377.conf
第二步:搭建哨兵
sentinel.conf这个文件
把哨兵也当成一个redis服务
-
创建三个配置文件分别叫sentinel_26379.conf sentinel_26378.conf sentinel_26377.conf
-
当前路径下创建data1,data2,data3这三个文件夹
vim sentinel_26379.conf
port 26379
daemonize yes
dir /root/redis/data
protected-mode no
bind 0.0.0.0
logfile "redis_sentinel.log"
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
vim sentinel_26378.conf
port 26378
daemonize yes
dir /root/redis/data1
protected-mode no
bind 0.0.0.0
logfile "redis_sentinel1.log"
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
vim sentinel_26377.conf
port 26377
daemonize yes
dir /root/redis/data2
protected-mode no
bind 0.0.0.0
logfile "redis_sentinel2.log"
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
启动三个哨兵
redis-sentinel ./sentinel_26379.conf
redis-sentinel ./sentinel_26378.conf
redis-sentinel ./sentinel_26377.conf
第三步:登录哨兵,查看信息
redis-cli -p 26379
info # 查看哨兵信息
redis-cli -p 6379
info # 查看主从信息
第四步:故障演示
主库停掉,哨兵会自动做故障切换,把6378作为了主库,6377还是从库
把原来6379启动,现在它就变成了从库(不是主库了)
解释
# mymaster 服务名字
# 6379 主库的端口
# 2 两个哨兵认为失效就失效了
# 两个哨兵觉得主库挂掉了,主库就真的挂掉了,就开始做故障切换
sentinel monitor mymaster 127.0.0.1 6379 2
# 这个配置项指定了需要多少失效时间,一个master才会被这个sentinel主观地认为是不可用的。单位海思毫秒
sentinel down-after-milliseconds mymaster 30000
# 这个配置项指定了在发生failover主备切换时最多可以有多少个slave同时对新的master进行同步,这个数字越小,完成failover所需的时间就越长,但是如果这个数字越大,就意味着越多的slave因为replication而不可用。可以通过将这个值设为1,来保证每次只有一个slave处于不能处理命令请求的状态
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
failover-timeout 可以用在以下这些方面:
- 同一个sentinel对同一个master两次failover之间的间隔时间。
- 当一个slave从一个错误的master那里同步数据开始计算时间。直到slave被纠正为向正确的master那里同步数据时。
- 当想要取消一个正在进行的failover所需要的时间
- 当进行failover时,配置所有slaves指向新的master所需的最大时间。不过,即使过了这个超时,slaves依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来了。
python操作哨兵
# python 操作哨兵,代码中需要单独写了,跟之前不一样了
import redis
from redis.sentinel import Sentinel
# 连接哨兵服务器(主机名也可以用域名)
sentinel = Sentinel(
[('127.0.0.1',26379),('127.0.0.1',26379),('127.0.0.1',26379)]
)
print(sentinel)
# 获取主服务器地址
# master=sentinel.discover_master('mymaster')
# print(master)
#
# # 获取从服务器地址
# slave=sentinel.discover_slaves('mymaster')
# print(slave)
# 读写分离
# 获取主服务器进行写入
master = sentinel.master_for('mymaster',socket_timeout=0.5)
w_ret=master.set('foo','bar')
slave=sentinel.slave_for('mymaster',socket_timeout=0.5)
r_ret=slave.get('foo')
print(r_ret)
集群
存在问题
- 并发量:单机redis的qps为10w/s,但是我们可能需要百万级别的并发量
- 数据量:机器内存16g-256g,如果存500g数据呢
解决:加机器,分布式
Redis cluster在2015年的3.0版本加入了,满足分布式的需求
数据分布(分布式数据库)
假设全量的数据非常大500g,单机已经无法满足,我们需要进行分区,分到若干个子集中:数据分片
分区的分片方式
- 顺序分区
原理:100个数据分到3个节点上:1-33第一个节点;34-66第二个节点;67-100第三个节点(很多关系型数据库使用此方式)
mysql的分库分表
- hash分区
原理:hash分区:节点取余,假设3台机器,hash(key)%3,落到不同节点上
节点取余分区
一致性哈希分区
虚拟槽分区
redis使用的分区方案
redis使用hash分区中的虚拟槽分区,总共有16384个槽
为什么redis又16384个槽
一般redis集群节点数,不会超过一千多个,16384就够了;如果槽过多,通信效率也会受影响;综合权衡完,使用16384个槽
原理
5个节点,把16384个槽平均分配到每个节点,客户端会把数据发送到任意一个节点,通过CRV16对key进行哈希对16384进行取余,算出当前key属于那部分槽,属于哪个节点,每个节点都会记录是不是负责这部分槽,如果是负责的,进行保存,如果槽不在自己的范围内,redis cluster是共享消息的模式,它知道哪个节点负责哪个槽,返回结果,让客户端找对应的节点去存服务端管理节点,槽,关系
redis集群搭建的流程
节点(6台机器,一主一从,3个节点),meet(每个节点需要互相感知),指派槽(16384分配给3台机器),复制(一主一从),高可用(主库挂掉,从库会顶上来)
搭建步骤
搭建一个6个台机器,3个节点的集群,另外3台机器是从库,启动两台(一主一从),扩容成4个节点,缩容成3个节点)
第一步:准备6台机器
cluster-enabled yes # 开启cluster
cluster-node-timeout 150000 # 故障转移,转移时间15秒
cluster-config-file nodes-${port}.conf # 给cluster节点增加一个自己的配置文件
cluster-require-full-coverage yes # 只要集群中有一个故障了,整个就不对外提供服务了,这个实际不合理,假设有50个节点,一个节点故障了,所有不提供服务了;需要设置成no
yes # 一个节点出现故障,整个就不提供对外服务了
准备六个配置文件
vim redis-7000.conf
port 7000
daemonize yes
dir "/root/redis/data/"
logfile "7000.log"
dbfilename "dump-7000.rdb"
cluster-enabled yes
cluster-config-file nodes-7000.conf
cluster-require-full-coverage yes
# 快速生成其他配置6个排位置文件
sed 's/7000/7001/g' redis-7000.conf > redis-7001.conf
sed 's/7000/7002/g' redis-7000.conf > redis-7002.conf
sed 's/7000/7003/g' redis-7000.conf > redis-7003.conf
sed 's/7000/7004/g' redis-7000.conf > redis-7004.conf
sed 's/7000/7005/g' redis-7000.conf > redis-7005.conf
启动6台机器
redis-server ./redis-7000.conf
redis-server ./redis-7001.conf
redis-server ./redis-7002.conf
redis-server ./redis-7003.conf
redis-server ./redis-7004.conf
redis-server ./redis-7005.conf
ps -ef |grep redis
第二步:相互感知,分配主从,分配槽
meet:分配槽,指定主从;1 的意思是,每个节点都是一主已从,自动组件主从
redis-cli --cluster create --cluster-replicas 1 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
yes 确认
第三步:主从关系和集群关系
命令
cluster nodes # 查看节点信息
cluster slots # 槽的信息
cluster info # 整体信息
redis-cli -c # 集群模式连接,设置获取值,如果不在当前节点,会自动跳转,并完成数据操作
扩容
8台机器,4个节点的集群
启动两台机器,加入到集群中(meet),两台机制做主从,这个节点分配槽
启动两台集群:一个主,一个从
第一步:两台机器配置
sed 's/7000/7006/g' redis-7000.conf > redis-7006.conf
sed 's/7000/7007/g' redis-7000.conf > redis-7007.conf
第二步:启动新增的两台机器
redis-server ./redis-7006.conf
redis-server ./redis-7007.conf
第三步:两台机器加入集群中去
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000
redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7000
第四部:让7007作为7006的从
redis-cli -p 7007 cluster replicate fb83d0f5c350ccf4c2e067f1b2081e236a266b15
第五步:迁移槽,从每台机器均匀的移动一部分槽给新的机器
redis-cli --cluster reshard 127.0.0.1:7000
扩容完成!
集群缩容
7006管理的槽移走,关闭节点,节点下线,先下从库,再下主
第一步:下线迁槽(7006的1366个槽迁移到7000上)
redis-cli --cluster reshard --cluster-from fb83d0f5c350ccf4c2e067f1b2081e236a266b15 --cluster-to 39ebb8200eea5af3edf893b7ed7b1f0272b6ee8d --cluster-slots 1365 127.0.0.1:7000
yes
redis-cli --cluster reshard --cluster-from fb83d0f5c350ccf4c2e067f1b2081e236a266b15 --cluster-to d61ee6005cd0e93aa8b69a074f89216a5555477e --cluster-slots 1366 127.0.0.1:7001
yes
redis-cli --cluster reshard --cluster-from fb83d0f5c350ccf4c2e067f1b2081e236a266b15 --cluster-to 541aefc31b0b08062e49dc34ee4e86506800addd --cluster-slots 1366 127.0.0.1:7002
yes
第二步:下线节点,关闭节点
# 端口
redis-cli --cluster del-node 127.0.0.1:7000 4667744ea620f5cd12448140cbc4eaffe8f8c0c6 # 先下从,再下主,因为先下主会触发故障转移
redis-cli --cluster del-node 127.0.0.1:7000 fb83d0f5c350ccf4c2e067f1b2081e236a266b15
第三步:关掉其中一个主,另一个从立马变成主顶上,重启停止的主,发现变成了从
python操作集群
# 需要rediscluster模块
# pip3 install redis-py-cluster
from rediscluster import RedisCluster
startup_nodes = [{"host":"127.0.0.1", "port": "7000"},{"host":"127.0.0.1", "port": "7001"},{"host":"127.0.0.1", "port": "7002"}]
# rc = RedisCluster(startup_nodes=startup_nodes,decode_responses=True)
rc = RedisCluster(startup_nodes=startup_nodes)
rc.set("foo", "bar")
print(rc.get("foo"))