Redis 主从复制、哨兵模式、集群架构

工作用途

|--------|----------------------------------|
| 验证码 | 存缓存--> 利用 Redis 自动过期特性 |
| 有顺序的数据 | 列表 List--> 有序队列、任务排队、消息通知 |
| 去重 | 集合 Set--> 数据去重、黑白名单、用户状态判断、点赞去重 |
| 排行榜 | 有序集合 ZSet--> 排行榜、优先级排序、有序数据展示 |

多台Redis

为什么需要多台Redis?

业务量太大=>一台服务器无法高效提供服务

单点故障=>一台服务器挂了,没有其他的备份服务

访问Redis过程:

  • 获取用户的需求
  • 访问Redis数据库
  • 如果Redis数据库中有数据->直接返回
  • 如果Redis数据库中没有数据->去MySql取数据->存到Redis中->返回

Redis主从

  • 容灾恢复->一台挂了,还能使用
  • 数据备份
  • 水平扩容,支持高并发
  • 实现读写分离
主从切换
复制代码
#主从Redis配置
[root@localhost ~]# cp /etc/redis.conf /etc/redis6379.conf 
[root@localhost ~]# cp /etc/redis.conf /etc/redis6389.conf 
[root@localhost ~]# cp /etc/redis.conf /etc/redis6399.conf

#主配置文件
[root@localhost ~]# >/etc/redis6379.conf #清空
[root@localhost ~]# cat /etc/redis6379.conf 
daemonize yes			#表示一个后台程序
bind 127.0.0.1 192.168.100.172
port 6379
protected-mode no	#保护模式
requirepass 12345678
dir /redisdata
dbfilename dump.rdb
appendonly no
loglevel notice	#日志文件
logfile /redisdata/6379.log
pidfile /var/run/redis_6379.pid
masterauth 12345678

[root@localhost ~]# redis-server /etc/redis6379.conf 
[root@localhost ~]# netstat -tulnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 192.168.1.129:6379      0.0.0.0:*               LISTEN      1540/redis-server 1 
tcp        0      0 127.0.0.1:6379          0.0.0.0:*               LISTEN      1540/redis-server 1

#从配置文件-->改6379端口就好->6389/6399
[root@localhost ~]# cp /etc/redis6379.conf /etc/redis6389.conf
:%s/6379/6389/g		vim中的查找替换
[root@localhost ~]# cp /etc/redis6379.conf /etc/redis6399.conf
:%s/6379/6399/g

只需在从配置文件中添加
replicaof 192.168.1.129 6379	#指定Redis主服务器

[root@localhost redis-8.6]# mkdir /redisdata

#启动服务
先启动主
[root@localhost ~]# redis-server /etc/redis6379.conf
再启动从
[root@localhost ~]# redis-server /etc/redis6389.conf
[root@localhost ~]# redis-server /etc/redis6399.conf

[root@localhost ~]# redis-cli -h 127.0.0.1 -p 6379 -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> ping
PONG
[root@localhost ~]# redis-cli -h 127.0.0.1 -p 6389 -a 123456
[root@localhost ~]# redis-cli -h 127.0.0.1 -p 6399 -a 123456

#测试
主:能读能写
  127.0.0.1:6379> get k1
  "a100"
  127.0.0.1:6379> set k1 a200
  OK
从:只能读
  127.0.0.1:6389> get k1
  "a200"
  127.0.0.1:6389> set k1 a300
  (error) READONLY You can't write against a read only replica.
在主上做修改之后,查看从是否同步数据了

*常见问题

  • 启动报错:数据目录/redisdata6399不存在 =>需创建目录
  • 启动不报错,服务没起来:
  • 看日志/redisdata/6379.log

root@localhost \~# less /redisdata/6379.log

  • 配置文件错误

==========================

主从复制数据同步原理

全量同步

主从复制模式第一次建立连接时,会执行全量同步(全量复制)。什么是全量同步呢?将master节点的所有数据都拷贝给slave节点,slave接收到数据文件后,存盘并加载到内存中

Replication Id:简称replid,是数据集的标记,id一致则说明是同一数据集。每一个master都有唯一的replid,slave则会继承master节点的replid

offset:偏移量。随着记录在repl_baklog中的数据增多而逐渐增大。slave完成同步时也会记录当前同步的offset。如果slave的offset小于master的offset,说明slave数据落后于master,需要更新

∴slave做数据同步,必须向master声明自己的replid和offset,master才可以判断到底需要同步哪些数据

完整流程描述:
  1. slave节点请求增量备份

  2. master节点判断replid,发现不一致,拒绝增量同步

  3. master将完整内存数据生成RDB,发送RDB到slave

  4. slave清空本地数据,加载master的RDB

  5. master将RDB期间的命令记录在repl_baklog,并持续将log中的命令发送给slave

  6. slave执行接收到的命令,保持与master之间的同步

    #查看主从关系
    127.0.0.1:6399> info replication

    Replication

    role:slave #角色是从
    master_host:192.168.1.129
    master_port:6379
    master_link_status:up
    master_last_io_seconds_ago:7
    master_sync_in_progress:0
    slave_read_repl_offset:3596
    slave_repl_offset:3596
    replica_full_sync_buffer_size:0
    replica_full_sync_buffer_peak:0
    master_current_sync_attempts:1
    master_total_sync_attempts:1
    master_link_up_since_seconds:2531

    127.0.0.1:6379> info replication

    Replication

    role:master
    connected_slaves:2
    slave0:ip=192.168.1.129,port=6389,state=online,offset=3806,lag=0,io-thread=0
    slave1:ip=192.168.1.129,port=6399,state=online,offset=3806,lag=0,io-thread=0
    master_failover_state:no-failover
    master_replid:732331b1e869e2d885e24e1ca863b25bb43e8109
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:3806
    second_repl_offset:-1

新增一台虚拟从主机

scp = 跨服务器远程拷贝文件 / 文件夹基于 SSH 安全加密传输,相当于 Linux 之间的远程复制粘贴

复制代码
[root@web-server ~]# scp root@192.168.1.129:/package/redis-8.6.zip ./
root@192.168.1.129's password: 
redis-8.6.zip                                                                                                 100% 4952KB  44.6MB/s   00:00    
[root@web-server ~]# unzip redis-8.6.zip 
Archive:  redis-8.6.zip
[root@web-server ~]# cd redis-8.6
[root@web-server redis-8.6]# ls
[root@web-server redis-8.6]# make && make install

[root@web-server redis-8.6]# vim /etc/redis6379.conf
[root@web-server redis-8.6]# mkdir /redisdata
[root@web-server redis-8.6]# redis-server /etc/redis6379.conf

主Redis-->192.168.1.129

从Redis-->192.168.1.100

==========================

*当主机down之后,从机会不会变成主?

主:shutdown/kill

root@localhost \~# redis-cli -h 127.0.0.1 -p 6379 -a 123456 shutdown

从:观察(info replication)

==>从机不会变成主机

*主机恢复后,主从关系是否恢复

主:

root@localhost \~# redis-server /etc/redis6379.conf

root@localhost \~# redis-cli -h 127.0.0.1 -p 6379 -a 123456

从:

==>会恢复主从关系

*从机down之后,重新上线还会继续同步数据吗

从机down-->主机写数据-->从机启

==>会继续同步数据

==========================

主从从模式

解决主同步压力太大了

操作方法:在二级从节点上,切换主

直接更改主

127.0.0.1:6379> slaveof 192.168.100.143 6379

127.0.0.1:6379> info replication

==========================

关闭主从

127.0.0.1:6379> slaveof no one

恢复--> slaveof 主IP 主端口

127.0.0.1:6379> slaveof 192.168.1.129 6379

==========================

主从复制的缺点:

1、主挂了,不会有从接盘 =>没有写功能

2、主同步压力会比较大,主从从复制有延迟

Redis哨兵

当主节点挂掉时,自动从 从节点里选出新主 ,完成故障转移

吹哨人(3个以上-奇数)=>监控主节点状态=>异常

=>发起投票(确定是否下线)

=>选举从为新主节点=>完成切换操作

实现功能:

主从监控

故障转移:主故障,将其他从切换为主

配置中心:客户端连接哨兵,获取主节点

消息通知:将故障转移结果发送给从节点

哨兵配置文件

默认:root@localhost \~# vim /package/redis-8.6/sentinel.conf

复制代码
/etc/sentinel26379.conf
[root@localhost ~]# cat /etc/sentinel26379.conf 
bind 0.0.0.0
port 26379
protected-mode no
daemonize yes
pidfile "/var/run/redis-sentinel26379.pid"
loglevel notice
logfile "/redisdata/sentinel26379.log"
dir "/redisdata"

sentinel monitor mymaster 192.168.1.129 6379 2
sentinel auth-pass mymaster 123456

#启动哨兵
[root@localhost ~]# redis-sentinel /etc/sentinel26379.conf
[root@localhost ~]# redis-server /etc/sentinel26389.conf --sentinel
验证哨兵

将主down掉

root@localhost \~# redis-cli -h 127.0.0.1 -p 6379 -a 123456 shutdown

看进展

看配置文件

在从机,观察是否有新主Redis产生

常见问题:哨兵没法正常工作

启服务:查看服务是否正常启动(ps,netstat.lsof......)

写配置文件:配置文件是否写正确(bind,master......)

有延迟查看日志文件,看日志是否更新-->在工作

root@localhost \~# less /redisdata/sentinel26389.log

哨兵工作原理(↑上图所示)

*SDOWN:主观下线(一个哨兵自己确认Master Down)

+sdown master mymaster

*ODOWN:客观下线(多个哨兵确认Master Down)

+odown master mymaster 进行投票达到票数2

*新定哨兵王:+vote-for-leader

各个哨兵选举出一个领导者->做故障迁移(将从变成主)的工作

采用RAFT:先到先得机制

*确认新的主节点:+selected-slave

*权限->高->slave_priority:100/replica-priority 100(数字越小优先级越高)

*偏移量->offset->越大优先级越高(slave_repl_offset:133259)

*进行故障迁移

*将新Master:slaveof no one =>主

*再向从发送命令,修改配置文件

==========================

老Master上线后,会继续变成主吗?

==> 不会重新变回主

延迟比较大

哨兵主要解决的问题:主从切换,没有解决主压力大的问题

==========================

Redis集群

集群:(多台机器组合在一起提供服务),提供服务高并发

*高可用:一台down了,还有其他的主机可提供服务(服务不间断)

*分布式:服务的数据分布在多台不同的主机上(更强可扩展性)

*水平扩展:可以无限加机器扩容

*海量存储

集群实现的功能

读写分离

支持数据高可用

支持水平扩展(扩容和缩容)

集群内置了sentinel的故障转移机制,不需要单独使用哨兵功能

核心架构:数据分片和哈希槽

1、数据分片:把所有数据分成16384个哈希槽(slot),每个主节点负责一部分槽

2、哈希槽:客户端写入key-->Redis计算CRC16(key)%16384得到槽号-->根据槽号找到对应的主节点-->数据存在该节点上

节点角色和通信

节点类型

*主节点:写->存储数据

*从节点:通过异步复制,同步主节点的数据

当主节点Down掉,升级为主节点

去中心化

*集群中没有中心管理节点,每个节点Gossip协议与其他节点进行通信

*每个节点都维护一份完整的群集元数据(节点信息,每个槽位在哪个节点......)

*节点定期通过PING/PONG消息检测节点状态

客户端请求路由

*重定向模式:

客户端随便连某一台节点->GET/SET/......->CRC16(key)%16384

如果槽位归当前节点=>直接执行命令

如果不归当前节点=>向客户端返回MOVE ->告知正确的节点->切换到正确节点

*代理模式:

客户工具在初始化从集群获取一份槽位映射表缓存到本地,当执行时,根据映射表获取正确连接节点

准备工作:6台Redis服务器=>单独主
复制代码
[root@localhost redisdata]# cat /etc/redis-cluster-6379.conf 
daemonize yes
bind 127.0.0.1 192.168.1.129
port 6379
protected-mode no
requirepass "123456"
dir "/redisdata/cluster6379"
dbfilename "dump.rdb"
appendonly no
loglevel notice
logfile "/redisdata/cluster6379/6379.log"
pidfile "/var/run/redis_cluster_6379.pid"
masterauth "123456"

#开启集群配置 
cluster-enabled yes
#集群配置文件 
cluster-config-file nodes-6379.conf
#节点超时时间 
cluster-node-timeout 5000

#构建命令
[root@localhost redisdata]# redis-cli -a 123456 -p 6379 --cluster create 192.168.1.129:6349 192.168.1.129:6359 192.168.1.129:6369 192.168.1.129:6379 192.168.1.129:6389 192.168.1.129:6399 --cluster-replicas 1

如构建失败
1、kill掉当前进程
2、删除node节点配置
3、重启进程
4、构建

#连接集群
*任意选择一个节点:
[root@localhost redisdata]# redis-cli -a 123456 -p 6349 -c
#查看同步情况

127.0.0.1:6349> info replication

#查看集群节点

127.0.0.1:6349> cluster info

#查看不同槽位号-->对应不同节点

127.0.0.1:6349> cluster keyslot k1

#读写操作(-c 自动路由,跳转)

root@localhost redisdata# redis-cli -a 123456 -p 6349 -c

#槽位

高可用与故障转移

故障迁移

M: 192.168.1.129:6349-->192.168.1.129:6399 slots:0-5460

M: 192.168.1.129:6369-->192.168.1.129:6389 slots:10923-16383

M: 192.168.1.129:6359-->192.168.1.129:6379 slots:5461-10922

主Down=>自动进行了故障迁移

192.168.1.129:6359> shutdown

not connected>

旧主UP-->变slave

集群扩容与缩容

扩容

1、写两个配置文件 :分别在两台机器上创建--> 新加 1 主 + 1 从

(从):192.168.1.129:6300.conf (主): 192.168.1.100:6300.conf

复制代码
[root@localhost ~]# cp /etc/redis-cluster-6379.conf /etc/redis-cluster-6300.conf
[root@localhost ~]# sed -i 's/6379/6300/g' /etc/redis-cluster-6300.conf
[root@localhost ~]# cat /etc/redis-cluster-6300.conf 
daemonize yes													#后台运行 Redis 进程
bind 127.0.0.1 192.168.1.129
port 6300
protected-mode no											#关闭保护模式	允许外部IP连接Redis
requirepass "123456"
dir "/redisdata/cluster6300"					#指定数据目录	每个节点的数据独立存放,避免冲突
dbfilename "dump.rdb"
appendonly no
loglevel notice
logfile "/redisdata/cluster6300/6300.log"
pidfile "/var/run/redis_cluster_6300.pid"
masterauth "123456"										#集群节点间认证密码 必须和requirepass一致

#开启集群配置 
cluster-enabled yes
#集群配置文件 
cluster-config-file nodes-6300.conf
#节点超时时间 
cluster-node-timeout 5000							#超过5秒未响应,哨兵会认为节点故障
[root@localhost ~]# mkdir /redisdata/cluster6300

2、服务启动(此时各自都是一个独立的Master)

复制代码
[root@localhost ~]# redis-server /etc/redis-cluster-6300.conf 
[root@localhost ~]# ps aux|grep redis

*命令扩容-->在线完成,无需停服务

3、新Master加入集群

redis-cli -a 123456 --cluster add-node <新节点:port> <集群节点IP:port>

查看最新集群信息(新主没有slot,不能存数据)

root@localhost \~# redis-cli -a 123456 -p 6349 --cluster check 192.168.1.129:6349

4、重新分配slots

复制代码
[root@localhost ~]# redis-cli -a 123456 -p 6349 --cluster reshard 192.168.1.129:6349
M: 1f4dca26a45f92ce292632fae8905f4d230c2b5f 192.168.1.129:6300
   slots: (0 slots) master
How many slots do you want to move (from 1 to 16384)? 3000	#输入需要多少个
What is the receiving node ID? 1f4dca26a45f92ce292632fae8905f4d230c2b5f		#输入接收目标6300的hash串
Source node #1: all			#从哪里接收slots
是否执行:yes

[root@localhost ~]# redis-cli -a 123456 -p 6349 --cluster check 192.168.1.129:6349
M: 1f4dca26a45f92ce292632fae8905f4d230c2b5f 192.168.1.129:6300
   slots:[0-998],[5461-6461],[10923-11921] (2999 slots) master

5、为新主6300分配新的从

redis-cli --cluster add-node <从节点:port> < 集群里任意一个已存在节点IP:port> --cluster-slave --cluster-master-id <主节点ID> -a 密码

root@localhost \~# redis-cli -a 123456 -p 6349 --cluster add-node 192.168.1.100:6300 192.168.1.129:6300 --cluster-slave --cluster-master-id 1f4dca26a45f92ce292632fae8905f4d230c2b5f

6、检查状态

redis-cli -a 123456 cluster nodes

缩容

*清除从节点:192.168.1.100:6300

获取从节点的id:6eae41f3278bdbb56de4af41a3ce2a0f4070bea2

删除

redis-cli -a 123456 --cluster del-node <集群任意节点IP:端口> <要删除的从节点ID>

root@localhost \~# redis-cli -a 123456 -p 6349 --cluster del-node 192.168.1.129:6399 6eae41f3278bdbb56de4af41a3ce2a0f4070bea2

*清除主节点:192.168.1.129:6349

清空主节点slots

redis-cli -a 123456 --cluster reshard < 集群任意节点IP:端口 >

root@localhost \~# redis-cli -a 123456 -p 6349 --cluster reshard 192.168.1.129:6349

输入需要多少个:3000

输入接收目标:hash串(不是6349的)

从哪里接收slots:6349的id

是否执行

删除
  1. 先删从节点 → 2. 再把主节点槽移走 → 3. 最后删主节点

redis-cli -a 123456 -p <集群任意节点> --cluster del-node <要删除的节点地址> <要删除的节点ID>

复制代码
#第一步:看 6300 有多少槽
redis-cli -a 123456 -p 6349 --cluster check 192.168.1.129:6349

#第二步:开始迁移槽位
redis-cli -a 123456 -p 6349 --cluster reshard 192.168.1.129:6300

How many slots do you want to move?-->5461
What is the receiving node ID?-->8961f71370b5f6cc3313b6d8aad0fe0f2e517328
↑你要把槽移给谁?6349 的 ID
redis-cli -a 123456 -p 6300 CLUSTER NODES | grep 6349
Please enter all the source node IDs.-->3bd2a82c7636185d7a2fd85b2e15663894cf282e
↑从谁那里拿走槽?6300的ID
redis-cli -a 123456 -p 6300 CLUSTER NODES | grep 6300
done
Do you want to proceed?-->yes

#第三步:检查 6300 槽位是否变成 0
redis-cli -a 123456 -p 6349 --cluster check 192.168.1.129:6349

# 第四步:删除 6300 主节点
redis-cli -a 123456 -p 6349 --cluster del-node 192.168.1.129:6349 3bd2a82c7636185d7a2fd85b2e15663894cf282e

Redis测试与监控

业务/功能模块上线=>测试=>观察数据

项目的组成:linux系统+代码+MySql+Redis......

*测试做什么?-->功能是否正常

*压力测试:看系统在多大并发下系统会崩溃-->系统的最大并发

系统:

CPU、MEM、DISK、NET

模块Redis:

*内存使用情况:

root@localhost \~# redis-cli -a 123456 -p 6349 info memory

used_memory:2641680

*查看Redis状态

root@localhost \~# redis-cli -a 123456 -p 6349info stats

instantaneous_ops_per_sec:2-->QPS:吞吐量,每天处理请求的数量

acl_access_denied_auth:0-->认证失败次数,过高黑客攻击

  • keyspace_hits /misses(命中率)
  • instantaneous_ops_per_sec(QPS)
  • rejected_connections(拒绝连接)
  • evicted_keys(内存溢出删数据)
  • expired_keys(过期 key)
  • total_commands_processed(总命令)
  • latest_fork_usec(持久化卡顿)--> RDB 持久化耗时,太大 (>10000) 会卡顿
  • master_repl_offset(主从同步)-->判断主从同步是否正常

root@localhost \~# redis-cli -a 123456 -p 6349 --bigkeys-->可进行拆分

hotkeys热门key(短期内被非常高频率访问)-->每个分类商品有一个key-->秒杀商品-->拆分

root@localhost \~# redis-cli -a 123456 -p 6349 --hotkeys

压力测试
集群模式

root@localhost \~# redis-benchmark -a 123456**--cluster** -c 50 -n 100000 -t get

-c 客户端越多压力越大

单机模式

root@localhost \~# redis-benchmark -a 123456 -p 6349 -c 1000 -n 100000 -t get

相关推荐
IT大白鼠5 天前
Redis 系列 · 第 01 篇——认知入门:Redis 是什么
redis·nosql
彧azz5 天前
Linux 环境下 Redis 学习总结:数据类型、持久化、锁、事务、主从与缓存问题
linux·redis·笔记·学习·面试
lbb 小魔仙5 天前
OpenClaw + cpolar 实战:远程 NAS、分享小游戏、RDP,再配置公网 AI 入口
数据库·人工智能·redis·oracle·prometheus
夕除5 天前
redis--018
redis
两锭子5 天前
Redis基础
redis
烟沙九洲5 天前
Redis 缓存穿透、缓存击穿、缓存雪崩
数据库·redis
字节探索5 天前
Redis 只会当缓存用?这 10 大实战场景,让你的系统快到飞起
redis·后端
于樱花森上飞舞5 天前
【Redis】哨兵详解
java·开发语言·数据库·redis
Rain的Java大神之路6 天前
如何快速上传10G文件
java·spring boot·redis·后端·mysql·spring cloud·面试
Wang's Blog6 天前
Java 接入Redis: 通用命令与键管理
java·服务器·redis