4. redis高级特性
4.1 持久化
Redis的数据全部在内存里,如果突然宕机,数据就会全部丢失,因此必须有一种机制来保证Redis的数据不会因为故障而丢失,这种机制就是Redis的持久化机制。
Redis有两种持久化的方式:快照(RDB文件)和追加式文件(AOF文件)
4.1.1 RDB
在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是snapshot快照,它恢复时是将快照文件直接读到内存里。
redis会单独创建一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不会进行任何IO操作的,这就确保了极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是特别敏感,那RDB方式要比AOF方式更加的高校。RDB的缺点是最后一次的数据可能丢失。
Fork
fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等)数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程。子进程读取数据,然后序列化写到磁盘中
rdb默认保存的是dump.rdb文件
你可以对Redis进行设置,让它在"N秒内数据集至少有M个改动"这一条件被满足时,自动保存一次数据集。
你也可以通过调用SAVE或者BGSAVE,手动让Redis进行数据集保存操作。
比如说,以下设置会让Redis在满足"60秒内有至少有1000个键被改动"这一条件时,自动保存一次数据集:
save 60 1000
如何触发RDB快照:
- save的规则满足的情况下,会自动触发rdb规则
- 执行flushall名
- 退出redis登陆
如何恢复rdb文件:
-
将rdb文件放到redis启动目录中即可,redis启动的时候会自动检查dump.rdb文件并恢复其中的数据
127.0.0.1:6379> config get dir
RDB的优点:
- RDB是一个非常紧凑的文件,它保存了某个时间点的数据集,非常适用于数据集的备份,比如你可以在每个小时报保存一下过去24小时内的数据,同时每天保存过去30天的数据,这样即使出了问题你也可以根据需求恢复到不同版本的数据集。
- RDB是一个紧凑的单一文件,很方便传送到另一个远端数据中心,非常适用于灾难恢复。
- RDB在保存RDB文件时父进程唯一需要做的就是fork出一个子进程,接下来的工作全部由子进程来做,父进程不需要再做其他IO操作,所以RDB持久化方式可以最大化Redis的性能。
- 与AOF相比,在恢复大的数据集的时候,RDB方式会更快一些。
RDB的缺点:
- 如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么RDB将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失(丢失最后一次快照后的所有修改)。
- 由于RDB是通过fork子进程来协助完成数据持久化工作的,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。
4.1.2 AOF
默认关闭
以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,也就是「重放」。换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。
AOF默认保存的是appendonly.aof文件
rewrite(AOF重写)
是什么:AOF采用文件追加方式,文件会越来越大为避免出现此种情况,新增了重写机制,当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集,可以使用命令bgrewriteaof
重写原理:AOF文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后再rename),遍历新进程的内存中数据,每条记录有一条的Set语句。重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似
触发机制:Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发
执行步骤:
- Redis执行 fork() ,现在同时拥有父进程和子进程。
- 子进程开始将新AOF文件的内容写入到临时文件。
- 对于所有新执行的写入命令,父进程一边将它们累积到一个内存缓存中,一边将这些改动追加到现有AOF文件的末尾: 这样即使在重写的中途发生停机,现有的AOF文件也还是安全的。
- 当子进程完成重写工作时,它给父进程发送一个信号,父进程在接收到信号之后,将内存缓存中的所有数据追加到新AOF文件的末尾。
- 搞定!现在Redis原子地用新文件替换旧文件,之后所有命令都会直接追加到新AOF文件的末尾。
优势
- 该机制可以带来更高的数据安全性,即数据持久性。Redis中提供了3种同步策略,即每秒同步、每修改同步和不同步。事实上,每秒同步也是异步完成的,其效率也是非常高的,所差的是一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢失。而每修改同步,我们可以将其视为同步持久化,即每次发生的数据变化都会被立即记录到磁盘中。可以预见,这种方式在效率上是最低的。至于无同步,无需多言,我想大家都能正确的理解它。
- 由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。然而如果我们本次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在Redis下一次启动之前,我们可以通过redis-check-aof工具来帮助我们解决数据一致性的问题。
- 如果日志过大,Redis可以自动启用rewrite机制。即Redis以append模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会创建一个新的文件用于记录此期间有哪些修改命令被执行。因此在进行rewrite切换时可以更好的保证数据安全性。
- AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上,我们也可以通过该文件完成数据的重建。因此AOF文件的内容非常容易被人读懂,对文件进行分析(parse)也很轻松。导出(export)AOF文件也非常简单:举个例子,如果你不小心执行了FLUSHALL命令,但只要AOF文件未被重写,那么只要停止服务器,移除AOF文件末尾的FLUSHALL命令,并重启Redis,就可以将数据集恢复到FLUSHALL执行之前的状态。
劣势
- 对于相同数量的数据集而言,AOF文件通常要大于RDB文件。恢复速度慢于rdb。
- 根据同步策略的不同,AOF在运行效率上往往会慢于RDB。总之,每秒同步策略的效率是比较高的,同步禁用策略的效率和RDB一样高效。
4.1.3 选择
RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储
AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾。Redis还能对AOF文件进行后台重写(bgrewriteaof),使得AOF文件的体积不至于过大
只做缓存:如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式。
同时开启两种持久化方式:
- 在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。
- RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。那要不要只使用AOF呢?建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),快速重启,而且不会有AOF 可能潜在的bug,留着作为一个万一的手段。
性能建议
- 因为RDB文件只用作后备用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份一次就够了,只保留
save 900 1
这条规则。 - 如果Enalbe AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了。代价一是带来了持续的IO,二是AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上。默认超过原大小100%大小时重写可以改到适当的数值。
- 如果不Enable AOF,仅靠Master-Slave Replication实现高可用性也可以。能省掉一大笔IO,也减少了rewrite时带来的系统波动。代价是如果Master/Slave同时宕掉,会丢失十几分钟的数据,启动脚本也要比较两个Master/Slave中的RDB文件,载入较新的那个。
4.2 发布订阅
Redis发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
Redis发布订阅(pub/sub)实现了消息系统,发送者(在redis术语中称为发布者)在接收者(订阅者)接收消息时发送消息。传送消息的链路称为信道。
下面的左图展示了频道channel1,以及订阅这个频道的三个客户端--client2、client5和client1之间的关系:
当有新消息通过publish命令发送给频道channel1时,这个消息就会被发送给订阅它的三个客户端
订阅的常用命令
命令 | 描述 |
---|---|
PSUBSCRIBE pattern [pattern ...] | 订阅一个或多个符合给定模式的频道。 |
PUBSUB subcommand [argument [argument ...]] | 查看订阅与发布系统状态。 |
PUBLISH channel message | 将信息发送到指定的频道。 |
PUNSUBSCRIBE [pattern [pattern ...]] | 退订所有给定模式的频道。 |
SUBSCRIBE channel [channel ...] | 订阅给定的一个或多个频道的信息。 |
UNSUBSCRIBE [channel [channel ...]] | 指退订给定的频道。 |
基本操作
[root@host1 ~]# redis-cli
127.0.0.1:6379> SUBSCRIBE bruce
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "bruce"
3) (integer) 1 # 订阅成功后,另起进程发布消息
1) "message"
2) "bruce"
3) "Hello everyone!"
127.0.0.1:6379> PUBLISH bruce "Hello everyone!"
(integer) 1
原理
通过subscribe命令订阅某个频道后,redis-server里维护了一个字段,字典的键就是一个个channel,而字典的值则是一个链表,链表中保存了所有订阅这个channel的客户端。subscribe命令的关键,就是将客户端添加到给定channel的订阅链表中。
通过publish命令向订阅者发送消息,redis-server会使用给定的频道作为键,在它所维护的channel字典中查到记录了订阅这个频道的所有客户端的链表,遍历这个链表,将消息发送给所有订阅者。
Pub/Sub从字面上理解就是发布于订阅,在redis中,你可以设定对某一个key值进行消息发布及消息订阅,当一个key值上进行了消息发布后,所有订阅它的客户端都会受到相应的消息。这一功能最明显的用法就是用作实时消息系统,比如普通的即时聊天,群聊等功能。
4.3 主从复制
4.3.1 主从复制概念
主从复制,是将一台redis服务器的数据,复制到其他的redis服务器。前者成为主节点(master/leader),后者成为从节点(slave/follower);数据的复制是单向 的,只能有主节点到从节点。master以写为主,slave以读为主。
默认情况下,每台redis服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。
作用
- 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
- 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
- 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
- 读写分离:可以用于实现读写分离,主库写、从库读,读写分离不仅可以提高服务器的负载能力,同时可根据需求的变化,改变从库的数量;
- 高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。
必要性
- 单机可能发生单点故障,且单机所承受的压力较大
- 单机的内存容量有限,且单台redis最大使用内存不应搞超过20G
主从复制原理
- Slave节点向Master节点发送sync指令,以请求数据同步
- Master节点在接收到sync指令后,会执行一次BGSAVE指令,将当前Master节点中的数据保存到对应的RDB文件中。当Master节点完成RDB文件的导出后,再将导出的RBD文件发送给Slave节点。由于在这个过程中Master节点依旧有可能发生数据写入操作,在这种情况下Master节点会将执行的指令放入到对应的缓冲区
- Slave节点在接受到Master节点导出的RDB文件之后,会删除现有节点的所有数据,然后加载这个RDB文件的内容到Slave节点
- 当Slave节点数据加载完成之后,Master会将缓冲区中暂存的指令发送到Slave节点
- Slave 执行收到的指令,完成数据的同步
完全复制:当从节点是第一次与主节点建立连接的时候,那么就会执行全量重同步。
增量复制:从Slave节点的复制偏移量在Master节点的复制积压区中寻找待同步的数据
4.3.1 主从复制搭建
-
快速在单机上搭建三个redis服务:
[root@host1 redis6]# pwd
/usr/etc/redis6
[root@host1 redis6]# cp redis.conf redis-6379.conf
[root@host1 redis6]# vim redis-6379.conf
port 6380
pidfile /var/run/redis_6380.pid
logfile "6380.log"
dbfilename dump-6380.rdb[root@host1 redis6]# cp redis-6379.conf redis-6380.conf
[root@host1 redis6]# cp redis-6379.conf redis-6381.conf
[root@host1 redis6]# sed -i 's/6379/6381/g' redis-6381.conf
[root@host1 redis6]# sed -i 's/6379/6380/g' redis-6380.conf
[root@host1 redis6]# redis-server redis-6379.conf
[root@host1 redis6]# redis-server redis-6380.conf
[root@host1 redis6]# redis-server redis-6381.conf
[root@host1 redis6]# ps -ef |grep redis
root 3871 1 0 15:01 ? 00:00:00 redis-server 127.0.0.1:6379
root 3877 1 0 15:01 ? 00:00:00 redis-server 127.0.0.1:6380
root 3883 1 0 15:01 ? 00:00:00 redis-server 127.0.0.1:6381
root 3891 2523 0 15:01 pts/0 00:00:00 grep --color=auto redis -
配置从机
[root@host1 ~]# redis-cli -p 6380
127.0.0.1:6380> SLAVEOF 127.0.0.1 6379
OK
127.0.0.1:6380> info replicationReplication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_repl_offset:14
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:69d1714c6d02070853a9b706108183cca88a9ec0
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:14
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:14
主机中的状态:
[root@host1 redis6]# redis-cli
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6380,state=online,offset=70,lag=0
slave1:ip=127.0.0.1,port=6381,state=online,offset=70,lag=0
master_failover_state:no-failover
master_replid:69d1714c6d02070853a9b706108183cca88a9ec0
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:70
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:70
如果要在配置文件中配置:
[root@host1 ~]# vim /usr/etc/redis6/redis-6380.conf
replicaof 127.0.0.1 6379
如果主机断开,从机的角色依旧,因此整个redis没有了写操作
4.3.3 哨兵模式
上面的集群搭建之后,如果Master节点崩溃了,在上面的情况下不会将Slave节点转换为Master节点,因此Master节点崩溃之后整个Redis集群就不能再执行写入操作。
为了解决这个问题,提高系统的可用性,Redis提供了Sentinel(哨兵)来实现Slave节点到Master节点的转换。
"哨兵"节点本质上也是一个Redis节点,但是和Master节点和Slave节点不同,"哨兵"节点只是监视Master节点和Slave节点,并不执行相关的业务操作。
"哨兵"的主要有以下几个作用:
- 监控Redis节点运行状态
- 通知:当被监控的Redis节点出现问题时,Sentinel可以通过向API或者管理员以及其它应用发送通知
- 自动故障转移:当一个主服务器不能正常工作时,Sentinel会开始一次自动故障迁移,它会在失效的Redis集群中寻找一个有效的节点,并将它升级为新的Master节点,并见原来失效的Master节点降级为Slave节点。当客户端试图访问已经失效的Master节点时,Redis集群也会想客户端返回新的Master节点的地址,使得Redis集群可以使用新的Master节点代替失效的Master节点
由于使用单个的"哨兵"来监视Redis集群的节点也不是完全可靠的,因为"哨兵"节点也有可能会出现故障,因此,一般情况下会使用多个"哨兵"节点来监视整个Redis集群,如下图所示:
由于存在多个哨兵节点,因此在RedisSentinel中,对于Redis节点的下线也有区分:
- 主观下线(SubjectivelyDown,即SDOWN):指单个Sentinel节点对集群中的节点作出下线判断
- 客观下线(ObjectivelyDown,即ODOWN):指多个Sentinel节点对集群中的节点作出"SDOWN"判断,并且通过
SENTINEL is-master-down-by-addr
命令互相交流之后,作出Redis节点下线的判断
一个Sentinel节点可以通过向另一个Sentinel节点发送SENTINEL is-master-down-by-addr
命令来询问对方是否认为给定的节点已经下线
4.3.3.1 实现原理
对于节点的检测,主要通过以下三种方式来进行检测:
- 每个Sentinel会每隔10s向主节点中发送INFO指令,通过该指令可以获得整个Redis节点的拓扑图。在这个时候,如果有新的节点加入或者有节点退出当前的集群,那么Sentinel就能够感知到拓扑图结构的变化。
- 每个Sentinel节点每隔2s会向指定的Channel发布自己对Master节点是否正常的判断以及当前Sentinel节点的信息,通过订阅这个Channel,可以获得其它Sentinel节点的信息以及对Master节点的存活状态的判断
- 每个Sentinel节点每隔1s就会向所有节点(包括Sentinel节点、Master节点以及Slave节点)发送PING指令来检测节点的存活状态
主节点的选举流程:
当一个Sentinel节点判断Master节点不可用时,首先进行"SDOWN"(主观下线),此时,这个Sentinel通过SENTINELis-masterdown-by-addr指令获取其它哨兵节点对于当前Master节点的判断情况,如果当前哨兵节点对于当前Master节点的下线判断数量超过了在配置文件中定义的票数,那么该Master节点就被判定为"ODOWN"(主观下线)
Sentinel节点列表中也会存在一个LeaderSentinel,该Sentinel会从原主节点的从节点中选出一个新的主节点,具体步骤如下所示:
- 首先,过滤i掉所有的ODOWN节点
- 选择slave-priority最大的节点,如果存在则选择这个节点为新的主节点,如果没有则继续下面的流程
- 选出复制偏移量最大的节点,如果有则返回;如果没有则继续执行下面的流程
- 选择run_id(服务运行id)最小的节点
- 当选择出新的主节点之后,LeaderSentinel节点会通过SLAVEOFNOONE命令让选择出来的节点成为主节点,然后通过SLAVEOF命令让其他节点成为该节点的从节点
4.3.3.2 配置哨兵
-
新建一个配置
[root@host1 ~]# cd /usr/etc/redis6/
[root@host1 redis6]# vim sentinel.confsentinel monitor myredis 127.0.0.1 6379 1
-
启动哨兵
[root@host1 redis6]# redis-sentinel sentinel.conf
6060:X 29 Aug 2022 15:55:57.566 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
6060:X 29 Aug 2022 15:55:57.566 # Redis version=6.2.2, bits=64, commit=00000000, modified=0, pid=6060, just started
6060:X 29 Aug 2022 15:55:57.566 # Configuration loaded
6060:X 29 Aug 2022 15:55:57.567 * Increased maximum number of open files to 10032 (it was originally set to 1024).
6060:X 29 Aug 2022 15:55:57.567 * monotonic clock: POSIX clock_gettime
.
.-__ ''-._ _.-
.
. ''-._ Redis 6.2.2 (00000000/0) 64 bit
.-.-```. ```\/ _.,_ ''-._ ( ' , .-` | `, ) Running in sentinel mode |`-._`-...-` __...-.
-.|'_.-'| Port: 26379 |
-.._ / _.-' | PID: 6060
-._-._
-./ .-' .-'
|-._
-.-.__.-' _.-'_.-'| |
-.-._ _.-'_.-' | https://redis.io
-._-._
-..-'.-' .-'
|-._
-.-.__.-' _.-'_.-'| |
-.-._ _.-'_.-' |
-._-._
-..-'_.-' _.-'
-._
-..-' _.-'
-._ _.-'
-..-'6060:X 29 Aug 2022 15:55:57.567 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
6060:X 29 Aug 2022 15:55:57.568 # Sentinel ID is 823bbf5c4c3a7f59258e80cbdfbbc5956b105474
6060:X 29 Aug 2022 15:55:57.568 # +monitor master myredis 127.0.0.1 6379 quorum 1
6060:X 29 Aug 2022 15:55:57.569 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
6060:X 29 Aug 2022 15:55:57.570 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379 -
将主机关掉,查看哨兵和从机的状态
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379> shutdown
哨兵的状态:
6060:X 29 Aug 2022 15:57:51.508 # +new-epoch 1
6060:X 29 Aug 2022 15:57:51.508 # +try-failover master myredis 127.0.0.1 6379
6060:X 29 Aug 2022 15:57:51.511 # +vote-for-leader 823bbf5c4c3a7f59258e80cbdfbbc5956b105474 1
6060:X 29 Aug 2022 15:57:51.511 # +elected-leader master myredis 127.0.0.1 6379
6060:X 29 Aug 2022 15:57:51.511 # +failover-state-select-slave master myredis 127.0.0.1 6379
6060:X 29 Aug 2022 15:57:51.594 # +selected-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379
6060:X 29 Aug 2022 15:57:51.594 * +failover-state-send-slaveof-noone slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379
6060:X 29 Aug 2022 15:57:51.695 * +failover-state-wait-promotion slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379
6060:X 29 Aug 2022 15:57:51.700 # +promoted-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379
6060:X 29 Aug 2022 15:57:51.700 # +failover-state-reconf-slaves master myredis 127.0.0.1 6379
6060:X 29 Aug 2022 15:57:51.773 * +slave-reconf-sent slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
6060:X 29 Aug 2022 15:57:52.764 * +slave-reconf-inprog slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
6060:X 29 Aug 2022 15:57:52.764 * +slave-reconf-done slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
6060:X 29 Aug 2022 15:57:52.865 # +failover-end master myredis 127.0.0.1 6379
6060:X 29 Aug 2022 15:57:52.865 # +switch-master myredis 127.0.0.1 6379 127.0.0.1 6381
6060:X 29 Aug 2022 15:57:52.865 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6381
6060:X 29 Aug 2022 15:57:52.865 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ myredis 127.0.0.1 6381
6060:X 29 Aug 2022 15:58:22.915 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ myredis 127.0.0.1 6381
6381的状态:
127.0.0.1:6381> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=14405,lag=1
master_failover_state:no-failover
master_replid:1de7351677ade4ba03c81e9675abbdb8cf4f6088
master_replid2:69d1714c6d02070853a9b706108183cca88a9ec0
master_repl_offset:14537
second_repl_offset:9665
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:43
repl_backlog_histlen:14495
127.0.0.1:6381> get k1
"v1"
6379回来后的状态:
6060:X 29 Aug 2022 15:57:52.865 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6381
6060:X 29 Aug 2022 15:57:52.865 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ myredis 127.0.0.1 6381
6060:X 29 Aug 2022 15:58:22.915 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ myredis 127.0.0.1 6381
6060:X 29 Aug 2022 16:20:15.288 # -sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ myredis 127.0.0.1 6381
6060:X 29 Aug 2022 16:20:25.274 * +convert-to-slave slave 127.0.0.1:6379 127.0.0.1 6379 @ myredis 127.0.0.1 6381
127.0.0.1:6379> info replication # 恢复后成为从机
# Replication
role:slave
master_host:127.0.0.1
master_port:6381
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:99498
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:1de7351677ade4ba03c81e9675abbdb8cf4f6088
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:99498
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:99344
repl_backlog_histlen:155
-
哨兵模式详细配置文件
sentinel的端口号,如果配置3个Sentinel,只需要修改这个port即可,即:26380、26381、26382
port 26381
设置当前sentinel是否放入后台运行
daemonize yes
设置当前sentinel的日志输出文件
logfile "/tmp/sentinel/sentinel-26381.log"
该sentinel对应的进程对应的文件描述符
pidfile "/var/run/redis-sentinel-26381.pid"
监视127.0.0.1:6379、6380、6381的节点,且至少有2个Sentinel判断主节点失效,才可以自动故障迁移
sentinel monitor myslave-2 127.0.0.1 6379 2
sentinel monitor mymaster 127.0.0.1 6380 2
sentinel monitor myslave-1 127.0.0.1 6381 2那么Sentinel将这个服务器标记为主观下线(subjectively down,简称SDOWN )
sentinel down-after-milliseconds mymaster 60000
4.4 缓存穿透和雪崩
redis缓存的使用,极大的提升了应用程序的性能和效率,特别是数据查询方面。但同时,它也带来了一些问题。其中,最要害的问题,就是数据的一致性问题,如果对数据的一致性要求很高,就不能使用缓存。
缓存穿透
当有大量查询请求未命中缓存时,引起对后台数据库的频繁访问,导致数据库负载压力增大,这种现象就叫做缓存穿透。
引起的原因:
黑客大量访问不存在的key,导致数据库处理大量请求
解决方法:
- 缓存空对象:将无效的key存进Redis中,若果数据库查询某个key不存在时,同样将这个key缓存到Redis缓存中,并设置value为NULL,表示不存在。如果攻击请求的key每次都相同,该方法有效;如果攻击请求的key每次随机生成,则同样会产生缓存穿透问题。
- 布隆过滤器:过滤掉一些不存在的key。布隆过滤器判定为true时,key可能存在于数据库中,也可能不存在;判定为false时,key一定不存在于数据库。
缓存击穿 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/7b2ec1bea77d4c7ca9c78abbb55cf62a.png#pic_center)
当Redis中存在某些极热点数据时,即有大量请求并发访问的key-value数据。当极热点key-value数据突然失效时,缓存未命中引起对后台数据库的频繁访问,这种现象叫缓存击穿。
引起的原因:
缓存上极热点数据突然失效
解决方法:
- 对极热点key设置永不过期
- 使用互斥锁。如果缓存失效的情况,只有拿到锁才可以查询数据库,降低了在同一时刻访问数据库的请求量,防止数据库崩溃。缺点是会导致系统的性能变差。
缓存雪崩 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/690687c9026f436da80d2ed91d15f678.png#pic_center)
当某⼀时刻发⽣⼤规模的缓存失效的情况,例如缓存服务宕机、大量key在同一时间过期,这样的后果就是⼤量的请求进来直接打到DB上,可能导致整个系统的崩溃,称为雪崩。如果运维重启宕机的数据库,马上又会有大量新的请求流量到来,再次引起数据库宕机。
引起的原因:
redis宕机、重启
大量数据使用了同一过期时间
解决方法:
- 引入随机性,在原有缓存失效时间上加上一个随机值,避免大量数据在同一时间失效。
- 通过请求限流、熔断机制、服务降级等手段,降低服务器负载。
- 实现缓存组件的高可用,防止单点故障、机器故障、机房宕机等一系列问题。
- 提高数据后台数据库的容灾能力。