Redis入门实战
Redis是一种开源(BSD 许可)内存数据结构存储,高性能的key-value数据库。
功能优势
- 性能极高:读速度大约11万次/秒,写速度大约8万次/秒
- 支持丰富的数据类型:Strings, Lists, Sets, Hashes, Sorted Sets, Streams 等等
- 原子性和持久化: 单个操作是原子性,多个操作也支持事务(通过Multi,Exec指令),可持久化到硬盘上
- 丰富的特性:支持发布/订阅,key过期机制,管道等特性
版本历史
Redis版本号的命名规则:版本号第二位如果是奇数,则为非稳定版本(例如2.7、2.9、3.1)
- Redis 1.0 是 Redis 数据库的第一个正式版本,于2009年3月发布
- Redis 3.0 在2015年4月发布,引入Redis集群模式
- Redis 5.0 新的Stream数据类型,重构Redis核心代码(slave 替换未 replica )
- Redis 6.0 在2020年4月发布,引入ACL权限管控和多线程IO,客户端缓存
- Redis 7.0 ,引入Function,Multi-part AOF
redis多IO线程模型只用来处理网络读写请求,对于redis的读写命令,依然是单线程处理
一、部署安装
从源安装Redis(linux和macos)
wget https://download.redis.io/redis-stable.tar.gz
tar -xzvf redis-stable.tar.gz
cd redis-stable
make
sudo make install #默认安装目录/usr/local/bin
windows环境
https://github.com/MicrosoftArchive/redis/releases 直接下载最新版本Redis-x64-3.2.100,选择msi格式的安装包,配置文件是redis.windows-service.conf
二、支持数据类型
三、持久化机制
Redis支持两种方式的持久化,一种是RDB方式、另一种是AOF(append-only-file)方式,两种持久化方式可以单独使用其中一种,也可以将这两种方式结合使用。
1.RDB模式(默认开启)
RDB是Redis数据的非常紧凑的单文件时间点表示形式(二进制文件),也叫快照,非常适合备份。
- 配置规则(redis.conf)
save 900 1 #表示900s以内至少发生1个key变化(新增、修改、删除),则重写rdb文件
save 300 10 #表示300s以内至少发生10个key变化(新增、修改、删除),则重写rdb文件
save 60 1000 #表示60s以内至少发生1000个key变化(新增、修改、删除),则重写rdb文件
save "" #关闭RDB持久化机制
- 手动持久化
通过redis-cli 连接上去,手动执行save
命令或者bgsave
命令进行一次快照操作,通过lastsave
可以获取最近一次成功执行快照的时间(unix时间戳格式)
bgsave
是异步执行快照的,bgsave写入的数据就是fork进程时redis的数据状态,一旦完成fork,后续执行的新的客户端命令对数据产生的变更都不会反应到本次快照,save
是同步的,即快照操作未完成是无法响应来自客户端的请求,会阻塞。而bgsave
是异步,快照的同时服务器还可以响应请求。
- 快照过程
redis使用fork函数fork出一个子进程,由子进程将内存中的数据写入硬盘中的临时文件(直接copy一份内存),当子进程写入完,用临时文件替换旧的RDB文件 - 恢复过程:Redis启动后会读取RDB快照文件,并将数据从硬盘载入到内存,具体时间取决于数据量和服务器性能
手动执行
FLUSHALL
命令,清空redis内存数据,也会执行一次快照操作
手动执行SHUTDOWN
命令,Redis服务器正常关闭之前,执行一次快照操作
2.AOF模式(默认关闭)
AOF采用日志的形式来记录每个写操作,并追加到文件中(普通文本文件)
- 配置方式
appendonly yes #yes开启,no关闭
appendfilename "appendonly.aof" #文件名
- 写文件三种方式
appendfsync always #每次收到写命令就立即强制写入磁盘,最慢,但保证完全的持久化,不推荐使用
appendfsync everysec #每秒强制写入磁盘一次,在性能和持久化做折中,推荐使用
appendfsync no #完全依赖操作系统,性能最好,持久化没保证。
- 重写机制
由于AOF文件是记录每次的写操作,所以文件会越来越来,所以需要有重写机制。 重写的机制有点类似于快照的方式,主进程先fork一个子进程,子进程全量遍历内存中的数据,然后逐个系列到新AOF文件中,重写过程,主进程的数据更新操作,会追加到旧的AOF文件中,并且追加到AOF重写缓存中,当子进程重写完成后,再把缓存中的数据追加到新的AOF文件,把新的AOF文件重命名正式的文件名字,此后所有操作都会被写入新的AOF文件中。 - 配置重写触发机制
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb #当AOF文件大小是上次rewrite后大小的一倍且AOF文件达到64mb后触发重写机制
Redis 7.0.0开始使用 multipart AOF,AOF文件拆分成一个基础AOF文件和多个增量AOF文件
3.优缺点对比
- RDB数据恢复块,但是完整性和一致性不高,可能最后一次备份时宕机了,丢失的数据较多,且备份时占用内存大(内存中的数据是原来的两倍)
- AOF 文件内容多,文件会越来越大,恢复比较慢,但是数据完整性和一致性较高,使用
appendfsync everysec
最多丢失1s数据 - 一般两种模式都会开启,同时保证恢复速度和完整性,当两种都开启时,优先从AOF文件恢复
四、部署模式:
1.主从复制
Redis 主从复制是指将一个 Redis 服务器(称为主节点)的数据复制到多个其他 Redis 服务器(称为从节点)的过程。
假设:主节点172.16.1.100, 从节点172.16.1.101
#./redis-cli 连接
replicaof 172.16.1.100 6379 #建立主从复制
replica no one #断开主从,成为主节点
持久化配置vim redis.conf
replicaof 172.16.1.100 6379
(1)主从复制流程
主从复制.png主从刚建立连接的时候,先全量同步,然后再增量同步。任何时候都是优先增量同步,不行再全量同步。
主从复制只能保证数据最终一致性,不能保证实时一致性,从节点数据会略滞后。
(2)主从复制流程好处
- 1.负载均衡:读操作分摊到多个从节点,减轻主节点的负载
- 2.高可用性:可通过keepalived+vip的方式,实现主节点出现故障时,快速切换到从节点,使其成为主节点
- 3.数据备份:通过复制数据到从节点,相当于对数据进行备份
2.哨兵模式
Redis 哨兵模式是 Redis 的高可用方案之一,它通过引入哨兵节点来监控主从节点的状态,并在主节点下线时自动将一个从节点切换为新的主节点,从而实现故障转移和自动故障恢复,哨兵至少要3台。
假设:主节点172.16.1.100, 从节点172.16.1.101,从节点172.16.1.102
- 启动哨兵(每台都启动哨兵3台)
redis-sentinel sentinel.conf
- 哨兵配置文件
sentinel.conf
port 26379 #指定端口
daemonize yes #指定是否以守护进程方式运行哨兵节点,默认为 yes
pidfile "sentinel.pid" #指定守护进程的 PID 文件路径
logfile "sentinel.log" #指定日志文件路径
dir /usr/local/redis #指定哨兵工作目录
sentinel monitor mymaster 172.16.1.100 6379 2 #配置要监控的主节点的名称、主节点的 IP 和端口号以及判断主节点是否下线的配置参数
#sentinel monitor <master-name> <ip> <port> <quorum>
sentinel down-after-milliseconds mymaster 30000 #哨兵ping Redis 30000毫秒还未回复,判断redis不可达
sentinel failover-timeout mymaster 180000 #进行故障转移,超过3分钟,表示故障转移失败
sentinel parallel-syncs mymaster 1 #选出新master,剩余slave向master发起同步数据的并发数
sentinel auth-pass mymaster pwd # 如果主节点设置密码,哨兵需要配置连接密码
故障转移过程
-
主观下线:每个Sentinel节点会每隔1秒对主节点、从节点、其他Sentinel节点发送ping命令做心跳检测,当这些节点超过down-after-milliseconds没有进行有效回复,Sentinel节点就会对该节点做失败判定,这个行为叫做主观下线
-
客观下线:当Sentinel主观下线的节点是主节点时,该Sentinel节点会通过sentinel
is-master-down-by-addr
命令向其他Sentinel节点询问对主节点的判断,当达到quorum
数时,主节点客观下线 -
哨兵领导者选举 : 当Sentinel节点对主节点做了客观下线,会从哨兵节点选举出一个领导者,用于故障转移。具体过程如下:1)当哨兵确认主节点主观下线,通过
is-master-down-by-addr
命令询问的同时,也要求将自己设置为领导者;2)收到命令的哨兵节点,如果没有投票给其他哨兵,则投票给该哨兵节点;3)当哨兵发现自己票数达到quorum
数 ,它成为领导者 -
故障转移
当选择出哨兵领导者,它将执行故障转移,具体如下:1)过滤掉不健康的节点(主观下线等);2)选择slave-priority(从节点优先级)最高的从节点列表,存在则返回,3)选择复制偏移量最大的从节点(复制的最完整)存在则返回;4)选择runid最小的从节点;5)哨兵领导者对选举出来从节点 执行replica no one
命令使其成为master节点,Sentinel领导者节点会向剩余的从节点发送命令,让它们成为新主节点的从节点;6)Sentinel节点集合会将原来的主节点更新为从节点,并保持着对其关注,当其恢复后命令它去复制新的主节点
Springboot连接哨兵配置application.properties:
spring.redis.database=0
spring.redis.password=xxxxx
spring.redis.sentinel.master=mymaster
spring.redis.sentinel.nodes=172.16.1.100:26379,172.16.1.101:26379,172.16.1.102:26379
哨兵永远不会剔除副本和哨兵,即使他们长时间无法访问。 比如更换机器,旧的副本和哨兵配置还在,如果需要获取最新的,需要向所有 Sentinels 发送
SENTINEL RESET mastername
命令:它们将在接下来的 10 秒内刷新副本列表,仅添加从当前主 INFO 输出中列为正确复制的副本和哨兵
3.集群模式
- Codis:由国人前豌豆荚大神开发的redis集群方案,Go语言开发,包含多个组件:codis-proxy,codis-dashboard,codis-group,codis-fe,内置redis版本最高版本3.2.8,目前已停止维护。早期Redis-cluster 没有经过严格的测试和生产验证,所以并没有广泛推广开来,才衍生出第三方的方案。
- Twemproxy:是由Twitter开源的集群化方案,痛点无法在线扩容、缩容。
- Redis-cluster :Redis官网自带集群模式,也叫分片集群(推荐)
搭建一个最小的分片集群,包含3个master节点,每个master包含一个slave 节点:
1)创建启动6个实例节点:
分别是:172.16.47.3:6001 172.16.47.3:6002 172.16.47.3:6003 172.16.47.4:6001 172.16.47.4:6002 172.16.47.4:6003
port 6001 #每个实例的端口号
cluster-enabled yes # 开启集群功能
cluster-config-file nodes.conf # 集群的配置文件名称,不需要我们创建,由redis自己维护,相对于工作目录
# 节点心跳失败的超时时间
cluster-node-timeout 5000
# 工作目录
dir /opt/redis-cluster/6001
# 绑定地址
bind 0.0.0.0
# 让redis后台运行
daemonize yes
# 注册的实例ip
replica-announce-ip 172.16.47.3
# 保护模式
protected-mode no
# 数据库数量
databases 1
# 日志相对于工作目录
logfile run.log
重点是
cluster-enabled yes
和cluster-config-file nodes.conf
2)创建集群
redis-cli --cluster create --cluster-replicas 1 172.16.47.3:6001 172.16.47.3:6002 172.16.47.3:6003 172.16.47.4:6001 172.16.47.4:6002 172.16.47.4:6003
redis5.0 之前使用redis安装包下的src/redis-trib.rb来实现的
./redis-trib.rb create --replicas 1 172.16.47.3:6001 172.16.47.3:6002 172.16.47.3:6003 172.16.47.4:6001 172.16.47.4:6002 172.16.47.4:6003
,因为redis-trib.rb是有ruby语言编写的所以需要安装ruby环境。
- 查看集群信息
redis-cli -p 6001 cluster nodes #查看集群节点信息
redis-cli -p 6001 cluster info #查看集群信息
- 操作数据
redis-cli -p 6001 -c #一定要加-c 才能自动跳转节点
cluster keyslot a #查看Key a 槽位置 范围(0~16384)
cluster help #查看集群命令详情
3)操作集群
- 增加节点
redis-cli --cluster add-node {新节点IP:PORT} {集群中任一节点IP:PORT}
redis-cli --cluster add-node 172.16.47.3:6004 172.16.47.3:6001
redis-cli --cluster add-node 172.16.47.4:6004 172.16.47.3:6001 #(从节点)
redis-cli --cluster reshard 172.16.47.3:6001 #分配槽位
redis-cli -c -p 6004 cluster replicate 主节点id #让172.16.47.4:6004变成172.16.47.3:6004 的从节点
添加节点后,要记得分配槽位
- 删除节点
redis-cli --cluster del-node {集群中任一节点IP:PORT} {要删除的节点ID}
1.如果是从节点,直接删除
redis-cli --cluster del-node 172.16.47.3:6001 要删除的节点ID #删除节点
2.如果是主节点,要先移动槽位
redis-cli --cluster reshard 172.16.47.3:6001 #重新分配槽位,按提示把要删除的节点上槽位移动到其它master节点
redis-cli --cluster del-node 172.16.47.3:6001 要删除的节点ID #删除节点
删除主节点需要先移动槽位到其它主节点,删除从节点可以直接删除。
redis-cli --cluster help
查看集群操作详细命令
SpringBoot 连接redis-cluster application.properties 配置
spring.redis.database=0
spring.redis.password=xxxxx
spring.redis.cluster.nodes= 172.16.47.3:6001,172.16.47.3:6002,172.16.47.3:6003,172.16.47.4:6001,172.16.47.4:6002,172.16.47.4:6003
五、常见问题
- 缓存常见三种特殊场景:缓存穿透(无效key)、缓存雪崩(大量key同时过期)、缓存击穿(单一key过期)
- 如何保证缓存与数据库双写一致性?(删除缓存)