Redis篇:Redis高级之主从、集群、哨兵、缓存优化


详情见:http://www.liuqingzheng.top/db/Redis系列/08-Redis系列之-Redis-Cluster/

一、Redis主从复制

1.1 单实例存在的问题

复制代码
  • 1
机器故障;容量瓶颈;QPS瓶颈

1.2 什么是主从复制

架构:一主一从,一主多从

作用:
    做读写分离
    做数据副本
    扩展数据性能

注意:
    一个maskter可以有多个slave
    一个slave只能有一个master
    数据流向是单向的,从master到slave

1.3 主从复制原理

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
1. 副本库通过slaveof 127.0.0.1 6379命令,连接主库,并发送SYNC给主库 2. 主库收到SYNC,会立即触发BGSAVE,后台保存RDB,发送给副本库 3. 副本库接收后会应用RDB快照 4. 主库会陆续将中间产生的新的操作,保存并发送给副本库 5. 到此,我们主复制集就正常工作了 6. 再此以后,主库只要发生新的操作,都会以命令传播的形式自动发送给副本库. 7. 所有复制相关信息,从info信息中都可以查到.即使重启任何节点,他的主从关系依然都在. 8. 如果发生主从关系断开时,从库数据没有任何损坏,在下次重连之后,从库发送PSYNC给主库 9. 主库只会将从库缺失部分的数据同步给从库应用,达到快速恢复主从的目的

1.4 主库是否要开启持久化

如果不开有可能,主库重启操作,造成所有主从数据丢失!

1.5 辅助配置(主从数据一致性配置)

复制代码
  • 1
  • 2
  • 3
min-slaves-to-write 1 min-slaves-max-lag 3 # 那么在从服务器的数量少于1个,或者三个从服务器的延迟(lag)值都大于或等于3秒时,主服务器将拒绝执行写命令

1.6 配置方式

1.6.1 方式1 slave命令

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
6380是从,6379是主 在6380上执行(去从库配置,配置主库) slaveof 127.0.0.1 6379 #异步 slaveof no one #取消复制,不会把之前的数据清除

1.6.2 方式2 配置文件

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
slaveof ip port # 配置从节点ip和端口 slave-read-only yes # 从节点只读,因为可读可写,数据会乱 mkdir -p redis1/conf redis1/data redis2/conf redis2/data redis3/conf redis3/data vim redis.conf # 编辑redis配置信息 ----------------------------------------------- daemonize no pidfile redis.pid bind 0.0.0.0 protected-mode no port 6379 timeout 0 logfile redis.log dbfilename dump.rdb dir /data slaveof 10.0.0.101 6379 # 加入左边两行 slave-read-only yes ----------------------------------------------- cp redis.conf /home/redis2/conf/ cp redis.conf /home/redis3/conf/ # 启动redis服务 docker run -p 6379:6379 --name redis_6379 -v /home/redis1/conf/redis.conf:/etc/redis/redis.conf -v /home/redis1/data:/data -d redis redis-server /etc/redis/redis.conf docker run -p 6378:6379 --name redis_6378 -v /home/redis2/conf/redis.conf:/etc/redis/redis.conf -v /home/redis2/data:/data -d redis redis-server /etc/redis/redis.conf docker run -p 6377:6379 --name redis_6377 -v /home/redis3/conf/redis.conf:/etc/redis/redis.conf -v /home/redis3/data:/data -d redis redis-server /etc/redis/redis.conf info replication

二、哨兵

2.1 主从复制高可用

复制代码
  • 1
  • 2
  • 3
# 主从复制存在的问题 1 主从复制,主节点发生故障,需要做故障转移,可以手动转移:让其中一个slave变成master (哨兵来做:高可用) 2 主从复制,只能主写数据,所以写能力和存储能力有限(集群来做)

2.2 原理:一个sentinel就是一个进程

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
1 多个sentinel发现并确认master有问题 2 选举触一个sentinel作为领导 3 选取一个slave作为新的master 4 通知其余slave成为新的master的slave 5 通知客户端主从变化 6 等待老的master复活成为新master的slave

image

2.3 安装配置

2.3.1 配置文件信息

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
# 配置开启sentinel监控主节点 mkdir -p redis4/conf redis4/data redis5/conf redis5/data redis6/data redis6/conf vi sentinel.conf ---------------------配置文件--------------------------------------- port 26379 daemonize yes dir 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 ------------------------------------------------------------------- # 配置文件解释 sentinel monitor mymaster 127.0.0.1 6379 2 sentinel down-after-milliseconds mymaster 30000 sentinel parallel-syncs mymaster 1 sentinel failover-timeout mymaster 1800001)sentinel monitor <master-name> <ip> <redis-port> <quorum> # 告诉sentinel去监听地址为ip:port的一个master,这里的master-name可以自定义,quorum是一个数字,指明当有多少个sentinel认为一个master失效时,master才算真正失效2)sentinel auth-pass <master-name> <password> # 设置连接master和slave时的密码,注意的是sentinel不能分别为master和slave设置不同的密码,因此master和slave的密码应该设置相同。3)sentinel down-after-milliseconds <master-name> <milliseconds> # 这个配置项指定了需要多少失效时间,一个master才会被这个sentinel主观地认为是不可用的。 单位是毫秒,默认为30秒4)sentinel parallel-syncs <master-name> <numslaves> # 这个配置项指定了在发生failover主备切换时最多可以有多少个slave同时对新的master进行 同步,这个数字越小,完成failover所需的时间就越长,但是如果这个数字越大,就意味着越 多的slave因为replication而不可用。可以通过将这个值设为 1 来保证每次只有一个slave 处于不能处理命令请求的状态。5)sentinel failover-timeout <master-name> <milliseconds> ''' failover-timeout 可以用在以下这些方面: 1. 同一个sentinel对同一个master两次failover之间的间隔时间。 2. 当一个slave从一个错误的master那里同步数据开始计算时间。直到slave被纠正为向正确的master那里同步数据时。 3.当想要取消一个正在进行的failover所需要的时间。 4.当进行failover时,配置所有slaves指向新的master所需的最大时间。不过,即使过了这个超时,slaves依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来了。 '''

2.3.2 搭建过程

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
1 搭一个一主两从 # 创建三个配置文件: # 第一个是主配置文件 daemonize yes pidfile /var/run/redis.pid port 6379 dir "/opt/soft/redis/data" logfile “6379.log” # 第二个是从配置文件 daemonize yes pidfile /var/run/redis2.pid port 6378 dir "/opt/soft/redis/data2" logfile “6378.log” slaveof 127.0.0.1 6379 slave-read-only yes # 第三个是从配置文件 daemonize yes pidfile /var/run/redis3.pid port 6377 dir "/opt/soft/redis/data3" logfile “6377.log” slaveof 127.0.0.1 6379 slave-read-only yes # 把三个redis服务都启动起来 ./src/redis-server redis_6379.conf ./src/redis-server redis_6378.conf ./src/redis-server redis_6377.conf 2 搭建哨兵 # sentinel.conf这个文件 # 把哨兵也当成一个redis服务器 创建三个配置文件分别叫sentinel_26379.conf sentinel_26378.conf sentinel_26377.conf # 当前路径下创建 data1 data2 data3 个文件夹 #内容如下(需要修改端口,文件地址日志文件名字) port 26379 daemonize yes dir ./data3 protected-mode no bind 0.0.0.0 logfile "redis_sentinel3.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 # 启动三个哨兵 ./src/redis-sentinel sentinel_26379.conf ./src/redis-sentinel sentinel_26378.conf ./src/redis-sentinel sentinel_26377.conf # 登陆哨兵 ./src/redis-cli -p 26377 # 输入 info # 查看哨兵的配置文件被修改了,自动生成的 # 主动停掉主redis 6379,哨兵会自动选择一个从库作为主库 redis-cli -p 6379 shutdown # 强制批量停掉某些进程 pkill -9 redis-server

2.3.3 python操作哨兵(客户端链接)

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
import redis from redis.sentinel import Sentinel # 连接哨兵服务器(主机名也可以用域名) # 10.0.0.101:26379 sentinel = Sentinel([('127.0.0.1', 26379), ('127.0.0.1', 26380), ('127.0.0.1', 26381) ], socket_timeout=5) 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 Cluser:集群

3.1 问题

复制代码
  • 1
  • 2
  • 3
# 存在问题 1 并发量:单机redis qps为10w/s,但是我们可能需要百万级别的并发量 2 数据量:机器内存16g--256g,如果存500g数据呢?

3.2 解决

复制代码
  • 1
  • 2
# 解决:加机器,分布式 redis cluster 在2015年的 3.0 版本加入了,满足分布式的需求

3.3 数据分布(分布式数据库)

3.3.1 存在问题

假设全量的数据非常大,500g,单机已经无法满足,我们需要进行分区,分到若干个子集中

3.3.2 分区方式

分区方式 特点 产品
哈希分布 数据分散度高,建值分布于业务无关,无法顺序访问,支持批量操作 一致性哈希memcache,redis cluster,其他缓存产品
顺序分布 数据分散度易倾斜,建值业务相关,可顺序访问,支持批量操作 BigTable,HBase
复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
- 顺序分区 -原理:100个数据分到3个节点上 1--33第一个节点;34--66第二个节点;67--100第三个节点(很多关系型数据库使用此种方式) - hash分区:原理:hash分区: 节点取余 ,假设3台机器, hash(key)%3,落到不同节点上 -节点取余分区 -一致性哈希分区 -虚拟槽分区 -redis使用虚拟槽分区,总共有16284个槽 -原理:5个节点,把16384个槽平均分配到每个节点,客户端会把数据发送给任意一个节点,通过CRC16对key进行哈希对16383进行取余,算出当前key属于哪部分槽,属于哪个节点,每个节点都会记录是不是负责这部分槽,如果是负责的,进行保存,如果槽不在自己范围内,redis cluster是共享消息的模式,它知道哪个节点负责哪些槽,返回结果,让客户端找对应的节点去存服务端管理节点,槽,关系

具体见:http://www.liuqingzheng.top/db/Redis系列/08-Redis系列之-Redis-Cluster/

3.4 原生安装流程

集群的概念流程:节点,meet,指派槽,复制,高可用

3.4.1 配置开启节点

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
# 搭建一个6台机器,3个节点的集群,另外3台机器是从库,启动两台(一主一从),扩容成4个节点,缩容成3个节点 -准备6个配置文件 port ${port} daemonize yes dir "/opt/redis/redis/data/" logfile "${port}.log" # masterauth 集群搭建时,主的密码 cluster-enabled yes # 开启cluster cluster-node-timeout 15000 # 故障转移,超时时间 15s cluster-config-file nodes-${port}.conf # 给cluster节点增加一个自己的配置文件 cluster-require-full-coverage yes #只要集群中有一个故障了,整个就不对外提供服务了,这个实际不合理,假设有50个节点,一个节点故障了,所有不提供服务了,需要设置成no # 快速生成其他配置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台机器 ./src/redis-server redis-7000.conf ./src/redis-server redis-7001.conf ./src/redis-server redis-7002.conf ./src/redis-server redis-7003.conf ./src/redis-server redis-7004.conf ./src/redis-server redis-7005.conf ps -ef |grep redis

3.4.2 meet,分配槽,指定主从

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
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 # 3个命令 cluster nodes cluster slots cluster info # 链接服务的 redic-cli -c # 集群模式链接,设置获取值,如果不在当前节点,会自动转过去,并完成数据操作

3.5 官方安装工具(ruby脚本)

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
# 下载编译安装ruby wget https://cache.ruby-lang.org/pub/ruby/2.5/ruby-2.5.8.tar.gz tar -zxvf ruby-2.5.8.tar.gz cd ruby ./configure -prefix=/usr/local/ruby make && make install cd /usr/local/ruby cp bin/ruby /usr/local/bin # ruby类似于python3 cp bin/gem /usr/local/bin # gem类似于pip ruby -v # 检查版本 # 安装rubygem redis ### 更换gem源 gem sources -l # 移除https://rubygems.org源 gem sources --remove https://rubygems.org/ # 增加https://gems.ruby-china.com/源 gem sources -a https://gems.ruby-china.com/ # 查看 gem sources -l ## 安装gem redis gem install redis -v 3.3.3 # 查看 gem list check redis gem # 安装redis-trib.rb cd /opt/soft/redis/src ./redis-trib.rb 弃用了,需要使用 # 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

3.6 集群扩容

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
# 启动两台集群:一个主,一个从 -第一步启动两台机器 sed 's/7000/7006/g' redis-7000.conf > redis-7006.conf sed 's/7000/7007/g' redis-7000.conf > redis-7007.conf redis-server conf/redis-7006.conf redis-server conf/redis-7007.conf -这两台机器加入到机器中(add-node) ./src/redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000 ./src/redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7000 -让7007作为7006的从 ./src/redis-cli -p 7007 cluster replicate 62b1982a2430731609a4393cb303fa47d9a5b930 -迁移槽:从每台机器均匀的移动一部分槽给新的机器 ./src/redis-cli --cluster reshard 127.0.0.1:7000 # 希望迁移多少个槽:4096 # 希望那个id是接收的:7006的id # 传入source id :all # yes

3.7 集群缩容

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
# 第一步:下线迁槽(把7006的1366个槽迁移到7000上) ./src/redis-cli --cluster reshard --cluster-from 62b1982a2430731609a4393cb303fa47d9a5b930 --cluster-to 6d65ffac96847c2a1ebb7240a7e218ccc843c7eb --cluster-slots 1365 127.0.0.1:7000 yes ./src/redis-cli --cluster reshard --cluster-from 62b1982a2430731609a4393cb303fa47d9a5b930 --cluster-to 0c47e4ff6523169ac293cdb5afcf65de2f3b7465 --cluster-slots 1366 127.0.0.1:7003 yes ./src/redis-cli --cluster reshard --cluster-from 62b1982a2430731609a4393cb303fa47d9a5b930 --cluster-to fdd4532103143b59a6761973cf0eaeee94ab9820 --cluster-slots 1366 127.0.0.1:7002 yes # 第二步:下线节点 忘记节点,关闭节点 redis-cli --cluster del-node 127.0.0.1:7000 b1daf008b8b9706230f31be3f462fc6bd469db50 # 先下从,再下主,因为先下主会触发故障转移 redis-cli --cluster del-node 127.0.0.1:7000 62b1982a2430731609a4393cb303fa47d9a5b930 # 第三步:关掉其中一个主,另一个从立马变成主顶上, 重启停止的主,发现变成了从

3.8 python操作集群(redis-py-cluster)

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
# 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"))

四、缓存优化

4.1 缓存更新策略

复制代码
  • 1
  • 2
  • 3
  • 4
LRU/LFU/FIFO算法剔除:例如maxmemory-policy(到了最大内存,对应的应对策略) ​ LRU -Least Recently Used,没有被使用时间最长的 ​ LFU -Least Frequenty User,一定时间段内使用次数最少的 ​ FIFO -First In First Out 最早放的,先剔除

4.2 缓存穿透,击穿,雪崩

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
### 缓存穿透 # 描述: 缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。 # 解决方案: 1 接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截; 2 从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击 3 通过布隆过滤器实现 ### 缓存击穿 # 描述: 缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力 # 解决方案: 设置热点数据永远不过期。 ### 缓存雪崩 #描述: 缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。 # 解决方案: 1 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。 2 如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。 3 设置热点数据永远不过期。
posted @   马氵寿  阅读(194)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
展开