redis主从、哨兵、集群
redis主从、哨兵、集群
redis实际生产过程中可能出现的问题:
- 机器宕机,redis直接停用,影响业务
- 容量瓶颈,内存大小不够
- QPS瓶颈,读的并发量很高很高,一个服务不够
redis主从(master-slave)
主从实现的功能:
- 做读写分离:主库用来写,从库只用来读
- 做数据副本
- 机器故障时,可以让一个从库变成主库,业务不会收到影响
我们可以做一主一从,也可以做一主多从,一个master可以拥有多个slave,但是一个slave只能有一个master。
redis主从赋值流程:
- 副本(从)库通过slaveof 127.0.0.1 6379命令,连接主库,并发送SYNC给主库
- 主库收到SYNC,会立即触发BGSAVE,后台保存RDB,发送给副本库
- 副本库接收后会应用RDB快照,load进内存
- 主库会陆续将中间产生的新的操作,保存并发送给副本库
- 到此,我们主复制集就正常工作了
- 再此以后,主库只要发生新的操作,都会以命令传播的形式自动发送给副本库.
- 所有复制相关信息,从info信息中都可以查到.即使重启任何节点,他的主从关系依然都在.
- 如果发生主从关系断开时,从库数据没有任何损坏,在下次重连之后,从库发送PSYNC给主库
- 主库只会将从库缺失部分的数据同步给从库应用,达到快速恢复主从的目的
前三步是从库初始化去复制主库,中间是当主库发送变化时,从库跟进更新,最后描述了主库和从库在关闭重启后如何保持同步和主从关系。
redis配置主从
# 命令形式
slaveof 127.0.0.1 6379 # slaveof ip port # 需要从库初始是空的
slaveof no one # 断开主从关系,不在同步
# 配置文件添加
slaveof 127.0.0.1 6379 # 配置从节点ip和端口
slave-read-only yes # 从节点只读,因为可读可写,数据会乱
min-slaves-to-write 1 # 从服务器至少有一个才能执行写
min-slaves-max-lag 3 # 如果有从库延迟了3秒以上,主服务器拒绝写入
验证redis的主从
- 连接redis从库,尝试写入数据,应该被拒绝并提示只读
- 连接redis主库,写入数据,再连接从库取出数据
- 执行
info Replication
查看主从的相关参数
如果主从没能正常连接,要注意可能是防火墙的端口没开,使用
iptables
系列指令去管理一下开放的端口,摆烂式开放端口iptables -F
哨兵Sentinel
上述建立主从的过程,需要人为的去操作,有这么一种场景,如果主库redis服务挂了,那么我们就需要去将从库变为主库,那么操作的这段时间内,写的业务是就处于停滞状态。
于是,这个主从切换的过程,我们可以用自动化的方式实现,可以用哨兵。哨兵会监控当前的库,监控的主库出了故障,就会做主节点转移,将一个从库设置为主库。
哨兵Sentinel也是实现高可用的必备,高可用是指服务的可用性很高,业务上几乎可以一直访问,不会出现故障很久影响很大的情况。
工作流程原理:
- 多个sentinel监控master服务节点,这个master有几个slave
- 多个sentinel发现并确认master有问题(宕机等)
- 选举出一个sentinel作为领导
- 选出一个slave作为新的master
- 通知其余slave成为新master的slave
- 通知客户端的主从变化(一些写的服务会切换到新master)
- 老的master如果重启,则会被管理成为新master的slave
n个sentinel哨兵会管理redis的节点关系,哨兵会根据主节点找到其从节点,主节点故障时做主从切换,而暂时失效的节点(无论主从)复活时,都会被重新连接,作为现在master的slave。
部署哨兵
部署哨兵前,先按照上一步部署主从。那这次我选择在三台机器上部署三个redis。
- 选择已经安装好redis的虚拟机,克隆两台出来
- 第一台原型机的redis服务使用配置为主,按照正常的redis配置即可,port为6379,而这台机器的ip为
10.0.0.4
(这是我的虚拟机网络配置) - 两台克隆机的redis服务配置为从,需要加入slaveof和slave-read-only的配置,将
10.0.0.4
的redis服务作为主服务。
然后我们再去配置哨兵:
-
哨兵配置文件
port 26379 daemonize yes dir /root/redis/data/ bind 0.0.0.0 logfile "redis_sentinel.log" sentinel monitor mymaster 10.0.0.4 6379 2 sentinel down-after-milliseconds mymaster 30000 # 端口启动在26379 # 后台启动 # 工作目录 # 绑定0.0.0.0,外部也能访问到 # 日志文件名 # sentinel monitor <master-name> <master-ip> <port> <n> # 哨兵监控的主节点,mymaster是起的名字,多个哨兵监听的名字一致,ip port是主节点的ip端口, # 2是指几个哨兵认为master有问题就有问题,一般3个哨兵我们就写两个,4个就写三个,大概写一半+1即可,多数认为有问题,哨兵则做主从切换 # 哨兵监控的主节点有多少微秒连接不上,我们就认为有问题,这里是30秒
-
因为每台机器上都有redis,所以我们每台机器上的哨兵配置文件都像上面配置即可。
-
在每一台机器上启动一个哨兵(并不是一台只能启动一个,可以启动多个哨兵服务,但是这样不能采取同样的端口配置了)
redis-sentinel sentinel.conf # 按照配置文件启动哨兵服务
-
每台机器上可以使用
ps aux |grep redis
来查看自己的redis相关服务,按照以上步骤,应该每台机器都会启动一个redis-sentinel服务跑在26379端口 -
测试哨兵是否起到了主从自动切换的功能,连接主库的redis服务,shutdown关闭主库redis服务。
哨兵因为配置了30秒的时间去确认master是否真的挂了,此时如果快速的去重启这个
10.0.0.4
的服务,那么会发现,主库还是主库但如果等待了30秒后,主库没有重启,那么会发现有一个从库变成了主库,使用info指令可以看到,也可以用写入指令来验证。
当有新的master产生后,我们老的master重新连接,则变成从库,也可以info验证。
redis集群
主从和哨兵替我们解决了读写分离和高可用的需求,提高了一些性能,但是如果想更好的提高性能(并发量和数据内存的瓶颈),我们需要加机器来解决,那么redis集群可以为我们提供分布式方案部署redis服务。
多机部署的问题是,怎么将数据分布到多台机器后,我还能快速准确的定位到我想要的数据将其取出。
有两个主流的分区方式,我们称之为数据分片的方式:
- 哈希分布
- 顺序分布
顺序分布式将数据直接切开一样放到多台机器,一般关系型数据库集群会采取这种分区方式,这种方式扩充容量比较方便。
而哈希分布也有两种:节点取余分布,大概过程时我们通过hash算法将key转换为某个值,这个值除以一个值,得到余数以分配到不同节点上,是hash+取余。一致性哈希分区,哈希+顺时针(优化取余)。
redis的策略是:
- 对key进行hash得到数字对16383取余
- 余数对应槽,每个节点被分配了不同的槽
- 这样的策略,通过key可以找到数据所在的节点,存取都按这套规则
集群搭建
一些概念
- 节点:某一台机器
- meet:节点跟节点之间通过meet通信
- 指派槽:16384个槽分给几个节点
- 复制:主从复制
- 高可用:主节点过掉,从节点顶上
搭建步骤:
-
配置文件,这里采取两主两从的集群方案(一个从只能跟一个主,但是一个主可以配多个从,所以也可以做两主四从)
# 集群相关配置 cluster-enabled yes cluster-node-timeout 15000 cluster-config-file node.conf cluster-require-full-coverage yes # 这些配置还是放在redis.conf中,节点本身的配置还是需要配的, # 如工作目录,日志文件等,但是由于布置在多态机器上,所以不需要做文件名字的划分
-
将上述redis.conf配置在4个节点(4台机器相应的位置)
-
正常启动4个节点的redis服务
-
基于已创建的redis服务创造集群
# 一条指令搭建集群(做了meet、复制、主从三大过程) redis-cli --cluster create --cluster-replicas 1 10.0.0.4:6379 10.0.0.5:6379 10.0.0.6:6379 10.0.0.7:6379 # 其中1是一主有1从,如我配置了6个节点,这里的数字为2,则会分配2主4从
ps:这个过程可以分开多个指令去自定义的做这个过程,但相对来步骤繁杂
-
通过info、nodes、slots指令查看相关信息
- info:查看redis服务所有相关信息,可以指定section看某一段
- nodes:查看redis集群的节点信息
- slots:查看每个节点指派槽的信息
-
存值试试,查看各节点的变化,注意,创建集群后,redis-cli无论连接哪个节点,所进行的读写操作将都是基于集群模式的。
也就是都可以写,写完,会自动分配到该分配的槽的节点,任意位置也都能取到之前存放的值。
-
主从切换测试,挂掉一个主节点,看它会怎么做主从切换。
集群扩容(了解)
有时服务量变大,原本的集群已经承受不了了,那么就需要扩容,相应的,当服务量变小,也需要做缩容。其原理是重新指派了槽,所以集群间的数据要做迁移,为了这种迁移的影响变小,最好是成倍扩容(当然了成本也很高)
以下,是在原有集群基础上,添加两个节点(一主一从)的流程
-
准备两台机器并启动其中的redis服务
-
两台机器加入到集群中
redis-cli --cluster add-node 10.0.0.8:6379 10.0.0.4:6379 redis-cli --cluster add-node 10.0.0.9:6379 10.0.0.4:6379
-
让10.0.0.9复制10.0.0.8
redis-cli -h 10.0.0.9 cluster replicate
-
迁移槽
redis-cli --cluster reshard 10.0.0.4:6379
集群缩容(了解)
- 先下线迁移槽
- 下线节点,将节点关闭后,删除节点
放个链接在这里(有空再看):https://www.cnblogs.com/liuqingzheng/articles/17324393.html
python操作哨兵
使用了redis主从和哨兵后,我们连接客户端的方式就发生了变化,应该是一个动态的连接,如果主库挂掉,可以切换到新的主库连接上继续写,读最好也不用我们区分。
import redis
from redis.sentinel import Sentinel
# 哨兵的地址和端口
sentinel = Sentinel([
('10.0.0.4', 26379),
('10.0.0.5', 26379),
('10.0.0.6', 26379)
],socket_timeout=5)
# 获取主服务器地址
master_addr = sentinel.discover_master('mymaster') # 这个和哨兵中配置的master-name一致
# 获取从服务器地址
slave_addr = sentinel.discover_slaves('mymaster')
python利用哨兵读写分离
master = sentinel.master_for('mymaster', socket_timeout=0.5)
w_ret = master.set('key','value')
slave = sentinel.slave_for('mymaster', socket_timeout=0.5)
r_ret = slave.get('key')
python操作集群
搭建集群后,客户端的存取操作也要相应的变成集群模式,python中需要下载rediscluster模块
pip install redis-py-cluster
操作:
from rediscluster import RedisCluster
startup_nodes = [{"host":"10.0.0.4", "port": "6379"},{"host":"10.0.0.5", "port": "6379"},{"host":"10.0.0.6", "port": "6379"},{"host":"10.0.0.7", "port": "6379"}]
# startup_nodes是将所有的集群节点都录入
# rc = RedisCluster(startup_nodes=startup_nodes,decode_responses=True)
rc = RedisCluster(startup_nodes=startup_nodes)
rc.set("key", "bar")
print(rc.get("key"))