目录
Redis 配置
Redis持久化
RDB(Redis DataBase)
AOF(Append Only File)
Redis发布订阅
Redis 发布订阅命令
Redis 主从复制
Redis集群环境配置
复制原理
哨兵模式
Redis缓存穿透、缓存击穿和缓存雪崩
缓存穿透
缓存击穿
缓存雪崩
学习参考: 【狂神说Java】Redis最新超详细版教程通俗易懂
Redis 的配置文件位于 Redis 安装目录下,文件名为 redis.conf(Windows 名为 redis.windows.conf。
redis.conf分为一些模块,我们将通过这些模块来解释Redis的配置
# Redis configuration file example
# 当需要需要内存大小的时候 可以指定内存大小
# Note on units: when memory size is needed, it is possible to specify
# 它通常的形式是1k 5GB 4M等等
# it in the usual form of 1k 5GB 4M and so forth:
#
# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes
#
# units 单位对大小写不敏感
# units are case insensitive so 1GB 1Gb 1gB are all the same.
# 指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件
include .\path\to\local.conf
include c:\path\to\other.conf
# 绑定的主机地址
bind 127.0.0.1
# 保护模式
protected-mode
# 端口设置
port 6379
# Redis 默认不是以守护进程的方式运行,可以通过该配置项修改,使用 yes 启用守护进程
# 否则一退出进程就结束了
# Windows的配置文件没有这一项
deamonize yes
# 当 Redis 以守护进程方式运行时,Redis 默认会把 pid 写入 /var/run/redis.pid 文件,可以通过 pidfile 指定
pidfile /var/run/redis.pid
# 指定日志记录级别,Redis 总共支持四个级别:debug、verbose、notice、warning,默认为 notice
loglevel notice
# 日志记录方式,默认为标准输出,如果配置 Redis 为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给 /dev/null
logfile ""
# 默认数据库的数量
databases 16
# 指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合
# 分别表示 900 秒(15 分钟)内有 1 个更改,300 秒(5 分钟)内有 10 个更改以及 60 秒内有 10000 个更改
save 900 1
save 300 10
save 60 10000
# 持久化如果出错,是否还需要继续工作
stop-writes-on-bgsave-error yes
# 是否压缩rdb文件,需要消耗一些cpu资源
rdbcompression yes
# 保存rdb文件的时候 进行一些校验
rdbchecksum yes
# rdb文件保存的目录
dir ./
# Redis密码设置 默认没有密码 可以通过命令设置 :config set requirepass '123456'
requirepass foobared
# Redis 最大客户端的数量
maxclients 10000
# Redis 配置最大的内容容量
maxmemory
# 内存达到上限之后的处理策略
maxmemory-policy noeviction
# 默认是不开启aof模式的,默认是rdb方式持久化,在大部分的情况下,rdb完全够用
appendonly no
# 持久化文件名字
appendfilename "appendonly.aof"
# 每次修改都会同步 消耗性能
appendfsync always
# 每秒执行一次同步 可能会丢失这1s的数据
appendfsync everysec
# 不执行同步
appendfsync no
Redis是内存数据库,如果不将内存中的数据状态保存到硬盘,那么一旦服务进程退出,服务器中的数据库状态也会消失。所以Redis也提供了持久化功能。
什么是RDB?
在指定的时间间隔将内存中的数据集快照写入磁盘,也就是Snapshot(快照),它恢复时是将快照文件直接读取到内存里。
Redis会单独创建fork一个子进程来持久化,会将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的。这就确保了极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能会丢失。
RDB保存的文件是 dump.rdb,可以在配置文件中进行配置。
在Redis配置的时候,SNAPSHOTTING模块,可以自己定义在多少秒内,进行多少次更新操作。
我们来试试修改配置文件中的这个部分,让60s内修改文件五次,就触发rdb操作。
目前在Redis文件夹下,就有一个dump.rdb,现在可以删掉它来查看我们的修改后的触发rdb的操作是否可以执行。
五次 修改操作
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2
OK
127.0.0.1:6379> set k3 v3
OK
127.0.0.1:6379> set k5 v5
OK
127.0.0.1:6379> set k4 v4
OK
新生成的rdb文件
触发机制:
如何恢复rdb文件?
# 如果在这个目录下存在dump.rdb文件,启动就会自动恢复其中的数据
127.0.0.1:6379> config get dir
1) "dir"
2) "D:\\Enviroment\\Redis-x64-3.2.100"
RDB的优点:
RDB的缺点:
一般来说,RDB的文件配置其实完全够用,不需要特别的更改。
将我们所有的命令都记录下来。
以日志的形式来记录每个写操作,将Redis执行过的所有指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据。换言之,Redis重启的话就根据日志文件的内容将写指令从前到后执行一次完成数据的恢复工作。
AOF 保存的是 appendonly.aof 文件
在Redis配置的时候,简单的讲了讲 APPEND ONLY MODE,默认情况下是不开启的,需要手动进行配置,把appendonly 改为yes就开启了aof
# aof模式默认是没有开启的,需要手动进行配置为yes开启
appendonly yes
# aof
appendfilename "appendonly.aof"
# rewirte 重写
# 如果aof文件大于64m,那么就太大,会触发重写机制.aof默认文件就是无限追加,文件就会越来越大.
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
重启以后,aof就生效了,可以看到Redis启动目录下多了一个appendonly.aof文件。
现在我们来set三个数据试试
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2
OK
127.0.0.1:6379> set k3 v3
OK
接着我们打开appendonly.aof ,可以看到它把我们的操作命令都记录了下来。
*2
$6
SELECT
$1
0
*3
$3
set
$2
k1
$2
v1
*3
$3
set
$2
k2
$2
v2
*3
$3
set
$2
k3
$2
v3
如果aof文件有错误,redis是无法启动起来的。
现在试着在appenonly.aof文件中乱加入一些字符,来破坏aof文件,保存以后再启动redis。
*2
$6
SELECT
$1
0
*3
$3
set
$2
k1
$2
v1
*3
$3
set
$2
k2
$2
v2
*3
$3
set
$2
k3
$2
v3
I wiill destory you!!!!!!!!!aof!
启动redis显示错误
那么这个时候该如何去处理呢?redis给我们提供了一个工具 :redis-check-aof --fix
在Windowns下,使用cmd打开 redis-check-aof.exe ,然后输入:redis-check-aof --fix appendonly.aof 即可完成修复
# cmd 命令下打开 redis-check-aof.exe
D:\Enviroment\Redis-x64-3.2.100>redis-check-aof.exe
# 提示使用 redis-check-aof.exe [--fix] 命令
Usage: redis-check-aof.exe [--fix]
# 输入修复命令
D:\Enviroment\Redis-x64-3.2.100>redis-check-aof --fix appendonly.aof
0x 6e: Expected prefix 'I', got: '*'
AOF analyzed: size=142, ok_up_to=110, diff=32
This will shrink the AOF from 142 bytes, with 32 bytes, to 110 bytes
# 确定是否修复
Continue? [y/N]: y
# 成功修复
Successfully truncated AOF
这个时候再打开appendonly.aof可以看到刚刚乱输入的符号已经没有了,并且redis也能够重启成功。
AOF的优点:
AOF的缺点:
Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
Redis 客户端可以订阅任意数量的频道。
下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:
当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:
序号 | 命令及描述 |
---|---|
1 | PSUBSCRIBE pattern [pattern ...] 订阅一个或多个符合给定模式的频道。 |
2 | PUBSUB subcommand [argument [argument ...]] 查看订阅与发布系统状态。 |
3 | PUBLISH channel message 将信息发送到指定的频道。 |
4 | PUNSUBSCRIBE [pattern [pattern ...]] 退订所有给定模式的频道。 |
5 | SUBSCRIBE channel [channel ...] 订阅给定的一个或多个频道的信息。 |
6 | UNSUBSCRIBE [channel [channel ...]] 指退订给定的频道。 |
实例(一)测试订阅消息、发布消息、接受消息
订阅端
# 订阅一个频道
127.0.0.1:6379> subscribe clawsFM
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "clawsFM"
3) (integer) 1
发布端
# 消息发布 clawFM发布一条hello
127.0.0.1:6379> publish clawsFM 'hello'
(integer) 1
推送以后的订阅端
# 订阅一个频道
127.0.0.1:6379> subscribe clawsFM
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "clawsFM"
3) (integer) 1
# 等待读取推送的消息
# 消息
1) "message"
# 这个 消息来自 clawsFM
2) "clawsFM"
# 消息内容
3) "hello"
概念
主从复制,是将一台Redis服务器的数据,复制到其他Redis服务器。前者称为主节点(master、leader),后者称为从节点(slave/follwer),数据的复制是单向的,只能由主节点到从节点。Master以写为主,Slave以读为主。
默认情况下,每台Redis服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个节点只能有一个主节点。
主从复制的作用:
一般来说,要将Redis运用于工程项目中,只使用一台Redis是万万不能的
电商网站上的商品,一般都是一次上传,无数次浏览,也是多读少写的情况。
主从复制,读写分离,80%都是在进行读操作,这是为了减缓服务器的压力。
一般来说,主从分离的最低配置是一主两从,在实际开发中,主从复制是必须要使用的,因为真实的项目不可能是单机。
我们只需要配置从库就好了,不用配置主库,因为Redis本身就是主节点。
使用info replication 查看当前库的信息,可以看到当前库的角色是master 以及 connected_slaves:0 为0,也就是说没有从机。
# info replication 查看当前库的信息
127.0.0.1:6379> info replication
# Replication
# 角色
role:master
# 0 :没有从机
connected_slaves:0
master_replid:0a1a6b7a7a4a21aa8d0dbcf182600f3898c0ad35
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
复制三个配置文件,修改对应的信息
# 进入配置文件目录
[root@clawsServer bin]# cd /usr/local/bin/cconfig
[root@clawsServer cconfig]# ls
redis.conf
# 将配置文件复制三份 以端口号区分开来
[root@clawsServer cconfig]# cp redis.conf redis-6379.conf
[root@clawsServer cconfig]# cp redis.conf redis-6380.conf
[root@clawsServer cconfig]# cp redis.conf redis-6381.conf
[root@clawsServer cconfig]# ls
redis-6379.conf redis-6380.conf redis-6381.conf redis.conf
修改完毕后接下来开启3个服务器,连接redis服务
[root@clawsServer bin]# redis-server cconfig/redis-6380.conf
[root@clawsServer bin]# redis-server cconfig/redis-6382.conf
redis-server cconfig/redis-6382.conf
使用 ps -ef|grep redis 命令可以看到当前有三个redis进程了。
但是在每台服务器上,使用info replication命令可以发现每台服务器它的角色都是master。当然redis服务器本身就是一个master,所以我们要进行配置。
该如何配置主从关系呢?只需要配置从机即可,让从机去认某一台服务器是它的master。
在一台从机的Redis服务器上使用 SLAVEOF 命令,现在我们让6379端口号为master,所以我们让6380和6382这两台服务器使用此命令来配置自己的主机。
6380服务器
6380服务器的主从复制状态:
6382服务器
6382主从复制状态:
此时再使用查看6379服务器,可以看到已经连接上了两台从机了。
真实的主从配置应该是在配置文件中配置,这样的话是永久的。现在我们使用的命令,这是暂时的。
那么如何在配置文件中配置呢?
打开从机的配置文件,replicaof <主机ip> <主机端口>,这样配置以后,从机启动以后就是从机了。
主从配置细节:
主机负责写,从机负责读。主机中的所有信息和数据都会自动被从机保存。
实例(一):测试主机写数据和从机写入数据
主机写入数据成功
从机写入数据失败
实例(二):主机断开连接,从机依旧连接到主机,但是没有写操作,这个时候主机如果回来了,从机依旧可以获取到主机写的信息。
现在关闭master 6379服务器
# 关闭6379服务器
127.0.0.1:6379> SHUTDOWN
not connected> exit
可以看到6379的进程已经没有了
在6380服务器上获取keys
# 在主机断开情况下,查看主从复制信息仍然看到从机6380的主机为6379,这个并没有发生改变。
127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:down
master_last_io_seconds_ago:-1
master_sync_in_progress:0
slave_repl_offset:3062
master_link_down_since_seconds:599
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:306567a1b3c8a3f9d773ac16b827438c95ca53b9
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:3062
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:43
repl_backlog_histlen:3020
# 获取keys 可以获取到
127.0.0.1:6380> keys *
1) "k1"
再使6379连接回来
[root@clawsServer bin]# redis-server cconfig/redis-6379.conf
[root@clawsServer bin]# redis-cli
127.0.0.1:6379> set k3 v3
OK
在6382上获取k3
127.0.0.1:6382> get k3
"v3"
实例(三)从机断开连接
现在让6380服务断开连接。
# 断开6380的连接
127.0.0.1:6380> shutdown
not connected> exit
查看当前进程,6380进程已终止
在主机上写入数据
# 查看当前主从复制信息
127.0.0.1:6379> info replication
# Replication
role:master
# 只有一台服务器在连接了
connected_slaves:1
slave0:ip=127.0.0.1,port=6382,state=online,offset=1593,lag=0
master_replid:9f3fb66306e4aad2e414cd5749ec90ec3f415687
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1593
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1593
# set k5
127.0.0.1:6379> set k5 v5
OK
此时恢复6380服务器的连接,获取k5的值为空。此时查看主从复制的信息,发现6380变成主机了,这是因为我们一开始配置主从信息的时候使用的是命令行,如果重启了,就会变成主机。
# 重连6380服务
[root@clawsServer bin]# redis-server cconfig/redis-6380.conf
# 启动6380 redis-cli
[root@clawsServer bin]# redis-cli -p 6380
# 获取k5的值
127.0.0.1:6380> get k5
# 获得的值为空
(nil)
# 查看主从复制信息,因为一开始使用命令slaveof,在关机后重启就失效了,现在6380自己就是主机了.
127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:0
master_replid:a805c95322fb18050642304b6c95ea1afc180a9b
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
重新配置主从信息,变成从机以后,它得到了k5的值。
# 重新配置主从信息
127.0.0.1:6380> slaveof 127.0.0.1 6379
OK
# 获取到了k5的值
127.0.0.1:6380> get k5
"v5"
Slave 启动成功后连接到master后会发送一个sync同步命令
Master接到命令后,启动后台的存盘进程,同时收集所有接受到用于修改数据命令集,在后台进程执行完毕后,master将传送整个数据文件到slave,并完成一次完全同步。
全量复制:而slave服务在接受到数据库文件数据后,将其存盘并加载到内存中
增量复制:Master继续将新的收集到的修改命令依次传递给slave,完成同步 (比如现在在主机写入数据,马上在从机获取,这是增量复制做到的)
但是只要重新连接到master,一次完全同步(全量复制)将被自动执行,我们的数据一定可以在从机中得到
另外一种主从复制模式
刚刚我们的主从复制的思想是一主两从
另外一种主从复制模式,层层链路模式,第二个服务器即是从机,也是主机。
我们让服务器实现这种主从复制思想
6379仍然为我们的主服务器,6380为6379的从机,6382为6380的从机。
修改6382主机为6380
127.0.0.1:6382> slaveof 127.0.0.1 6380
OK
此时查看三个服务器各自的主从复制信息
6379:
可以看到6380依旧为从节点
6382
如果这个模式下主机宕机了怎么办?
如果主机宕机了,我们可以使用slaveof no one 使用这个命令的服务器变为主机,其他节点就可以手动连接到最新的主节点
使6379宕机
此时剩下两台服务器的配置信息
在6380服务器上使用 slaveof no one 命令,再查看主从信息可以看到6380变为主机了
127.0.0.1:6380> slaveof no one
OK
127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6382,state=online,offset=1358,lag=1
master_replid:f3718d07ec13c91cc18f0f13bb78825bcae7a014
master_replid2:79968b80f750f53df091e90e867372ace9b592eb
master_repl_offset:1358
second_repl_offset:1317
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:29
repl_backlog_histlen:1330
如果这个时候6379恢复连接,那么它也不再是主机了,需要重新配置为主机。
它能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库。
哨兵模式是一种特殊模式,首先Redis提供了哨兵的命令,哨兵是一个独立进程,作为进程,他会独立运行,其原理是哨兵通过发送命令,等待Redis服务响应,从而监控运行的多个Redis实例。
这里的哨兵有两个作用
然而一个哨兵进程对Redis服务进行监控,可能会出现问题,如果哨兵进程也终止了怎么办?为此我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式。
假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1主观的认为主服务器不可用。这个现象成为主观下线。当后面的哨兵也检测到主服务器不可用,并且当数量达到一定值时,那么哨兵之间就会进行一次投票,投票结果由一个哨兵发起,进行failover[故障转移]操作,切换成功后,就会通过发布订阅模式,让各个哨兵把之间监控的从服务器实现切换主机,这个过程称为客观下线。
实例(一):测试哨兵模式
sentinel monitor myredis 127.0.0.1 6379 1
端口号后面这个数字1,代表主机宕机,slave投票看让谁接替成为主机
现在的主从复制模式仍然是一主二从,让6379宕机。
在哨兵的进程中看到已经选举6382为master
6382主从复制信息
如果现在6379连接回来了,它会变为从机。
哨兵模式的优点
哨兵模式的优点 :
参考: REDIS缓存穿透,缓存击穿,缓存雪崩原因+解决方案
概念
key对应的数据在数据源并不存在,每次针对于此key的请求从缓存获取不到,请求都会到数据源,从而会压垮数据源。比如用一个不存在的id获取用户信息,不论缓存和数据库都没有,若黑客利用此漏洞进行攻击有可能压垮数据库。
如果出现了这种问题,有两种解决方案:布隆过滤器和缓存空对象。
布隆过滤器:将所有可能存在的数据hash到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层数据存储系统的查询压力
缓存空对象:如果一个查询返回的数据为空,我们仍会把这个空结果进行缓存,但是他的过期时间很短。
一个key非常的热点,在不停的扛着大并发,大并发集中对这个点进行访问,当这个key在失效的瞬间,持续的大并发就会穿破缓存,直接请求数据库,就像在一个屏障上凿开一个洞。
当某个key在过期的瞬间,有大量请求并发访问,这类数据一般是热点数据,由于缓存过期,会同时访问数据库来查询数据,并写回缓存,会导致数据库压力瞬间压力过大。
解决方案:
设置热点数据永不过期
从缓存层面来看,没有设置过期时间,所以不会出现热点key过期后产生的问题
加互斥锁
分布式锁:使用分布式锁,保证对于每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可。这种方式将高并发的压力转移到分布式锁,因此对分布式锁考研很大。
缓存雪崩,是指在某一个时间段,缓存集中过期失效,Redis宕机。
产生雪崩的原因之一,比如双十一的一点,很快会迎来一波抢购,这波商品都放入了缓存,假设缓存时间一个小时对于数据库而言,会产生周期性的压力波峰,于是所有的请求都会到达存储层,存储层的调用量会暴增,造成存储层也挂掉情况。
其实集中过期倒不是非常致命的,比较致命的是缓存雪崩,是缓存服务器某个节点宕机或断网。因为自然形成的缓存雪崩,一定是在某个时间段集中创建缓存,这个时候数据库也是可以顶住压力的,无非就是对于数据库产生的周期性压力而已,而缓存服务节点宕机,对于数据库服务器造成的压力是不可预知的。很有可能瞬间把数据库压垮。
解决方案
redis高可用
这个思想的含义是,既然redis有可能挂掉,那么多设几台redis,这样一台挂掉以后其他还可以继续工作,其实就是搭建集群
限流降级
这个解决方案的思想是,在缓存失效后,通过加锁或者队列来控制数据库读写的线程数量,比如对某个key值只允许一个线程的查询和写缓存,其他线程等待
数据预热
将数据预热的含义是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中,在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。