redis哨兵、redis集群

哨兵

主从:一主两从,如果一个从库挂掉,不影响整体对外服务的,但如果主库挂掉,不能再写入数据了,整个服务就有问题

我们需要保证,高可用:服务的高度可用性 99.999%可用性,使用redis的哨兵(sentinel),保证高可用

主从复制存在的问题

  1. 主从复制,主节点发生故障,需要做故障转移,可以手动转移:让其中一个slave变成master:哨兵解决
  2. 主从复制,只能主写数据,所以写能力和存储能力有限:集群解决

哨兵原理

可以做故障判断,故障转移,通知客户端(其是是一个进程),客户端直接连接sentinel的地址

  1. 多个sentinel发现并确认master有问题
  2. 选举出一个sentinel作为领导
  3. 选取一个slave作为新的master
  4. 通知其余slave成为新的master的slave
  5. 通知客户端主从变化
  6. 等待老的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服务

  1. 创建三个配置文件分别叫sentinel_26379.conf sentinel_26378.conf sentinel_26377.conf

  2. 当前路径下创建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)

集群

存在问题

  1. 并发量:单机redis的qps为10w/s,但是我们可能需要百万级别的并发量
  2. 数据量:机器内存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 确认

第三步:主从关系和集群关系

image-20230109160702903.png

命令

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 

扩容完成!

image-20230109161919726

集群缩容

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

第三步:关掉其中一个主,另一个从立马变成主顶上,重启停止的主,发现变成了从

image-20230109164008395.png

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"))
posted @ 2023-01-09 16:44  荀飞  阅读(73)  评论(0编辑  收藏  举报