Redis 概述
redis全称Remote Dictionary Server,主要作为键值对数据库
Redis 安装
yum 安装
shell
sudo yum install redis
sudo systemctl enable redis
sudo systemctl start redis
如需源码安装参考官网 redis.io/docs/latest...
连接redis
shell
redis-cli -h host -p port -a password
Redis 数据结构
redis是一个键值对数据库,其中redis所有的key都是string类型,value则多种多样, 目前社区版redis支持的数据类型有 String 、Hash、 List、 Set、 Sorted set、 Stream、 Bitmap、 Bitfield、 Geospatial ,如果需要支持json可以安装json扩展插件。
下面我们介绍一下常用的6个数据类型
2.1 字符串(String)
String作为最常用的类型,redis对其做了许多优化,String使用SDS存储数据。
SDS 的内部结构如下
长度len 用于存储字符串的当前长度。
空闲空间free 未使用的额外空间数量,用于未来可能的扩展。
字符数组buf 实际存储字符串数据的数组,以NULL
结尾,这使得 SDS 可以重用所有标凑 C 字符串函数。
bash
set key value -- 插入数据
get key -- 获取数据
del key -- 删除数据
del key -- 删除数据
exists key -- 是否存在key
expire key seconds -- 设置key过期时间
keys -- 获取所有key
2.2 列表(List)
类似于消息队列
LPUSH
在列表的头部添加一个新元素;RPUSH
添加到尾部。LPOP
从列表头部移除并返回一个元素;RPOP
执行相同操作,但从列表尾部移除。LLEN
返回列表的长度。LMOVE
原子地将元素从一个列表移动到另一个列表。LRANGE
从列表中提取一定范围的元素。
2.3 集合(Set)
无序且不可重复
SADD
向集合中添加新成员。SREM
从集合中删除指定成员。SISMEMBER
测试字符串是否为集合成员。SINTER
返回两个或多个集合共同拥有的成员集合(即交集)。SCARD
返回集合的大小(又称基数)。
2.4 散列(Hash)
2.5 有序集合(Sorted Set)
可以高效的做排行榜等功能
ZADD
将新成员和相关分数添加到排序集中。如果该成员已存在,则更新分数。ZRANGE
返回在给定范围内排序的排序集的成员。ZRANK
返回所提供成员的排名,假设排序按升序排列。ZREVRANK
返回所提供成员的排名,假设排序集按降序排列。
Redis 高性能优化、配置详解
核心配置整理,仅供参考(不同版本配置可能有所不同,详细配置)
conf
# Redis 监听的 IP 地址
bind 127.0.0.1 -::1
# 是否启用保护模式
protected-mode yes
# Redis 监听的 TCP 端口(默认 6379)
port 6379
# 客户端空闲超时时间(秒)
timeout 0
# TCP keepalive 间隔
tcp-keepalive 300
# 是否以守护进程方式运行 Redis
daemonize no
# 日志级别(debug,verbose,notice,warning)
loglevel notice
# 日志文件路径
logfile ""
# 是否启用系统日志
# syslog-enabled no
# 设置数据库的数量
databases 16
################################ 快照 ################################
# 自动RDB频率
# save 3600 1 300 100 60 10000
# RDB 快照失败时是否停止写入
stop-writes-on-bgsave-error yes
# 是否对 RDB 文件进行 LZF 压缩
rdbcompression yes
# RDB 文件名
dbfilename dump.rdb
# 工作目录,存储持久化文件
dir ./
########################### 主从复制(需要同步主库数据才需设置) #########################
# 需要异步复制哪个主节点的数据
# replicaof <masterip> <masterport>
# 主节点密码
# masterauth <master-password>
# 主节点用户
# masteruser <username>
# 从节点断开连接时是否提供旧数据。
replica-serve-stale-data yes
# 从节点是否只读
replica-read-only yes
# 是否使用无盘复制
repl-diskless-sync yes
# 无盘复制的延迟时间(秒)
repl-diskless-sync-delay 5
# 是否禁用 TCP_NODELAY,减少带宽但增加延迟
repl-disable-tcp-nodelay no
# 复制积压缓冲区的大小
# repl-backlog-size 1mb
# 复制积压缓冲区的生存时间(秒)
# repl-backlog-ttl 3600
# 主从切换的优先级,防止脑裂(数字越小,优先级越高,特殊如果时0则该节点永远不会被选举为master)
replica-priority 100
################################## 安全 ###################################
# 设置访问 Redis 的密码
# requirepass foobared
################################### 连接 ####################################
# 最大同时连接的客户端数量
# maxclients 10000
############################## 内存管理 ################################
# Redis 可使用的最大内存
# maxmemory <bytes>
# 达到 maxmemory 时的淘汰策略
# volatile-lru -> 对设置了过期时间的键使用 lru 算法
# allkeys-lru -> 对所有键使用 lru 算法
# volatile-lfu -> 对设置了过期时间的键使用 lfu 算法
# allkeys-lfu -> 对所有键使用 lfu 算法
# volatile-random -> 随机移除设置了过期时间的键
# allkeys-random -> 随机移除任意键。
# volatile-ttl -> 移除最近将要过期的键
# noeviction -> 不移除任何键,直接返回错误
# maxmemory-policy noeviction
# 淘汰算法的样本数
# maxmemory-samples 5
################################ THREADED I/O #################################
# I/O 线程数(默认 1,即不使用多线程,多核推荐设置cpu数-1)
# io-threads 4
# 是否在读取时使用 I/O 线程
# io-threads-do-reads no
############################## aof日志 ###############################
# 是否启用 AOF 持久化
appendonly no
# AOF 文件名
appendfilename "appendonly.aof"
# AOF fsync 策略
# always每次写入都执行 fsync everysec每秒执行一次 fsync no不执行 fsync,由操作系统决定何时写入磁盘
appendfsync everysec
# AOF 重写期间是否避免 fsync
no-appendfsync-on-rewrite no
# 触发 AOF 重写的增长百分比
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# 启动时是否加载被截断的 AOF 文件,如果aof异常写入会导致启动失败
aof-load-truncated yes
# 在 AOF 重写时使用 RDB 格式,配合RDB混合备份,防止aof文件过大
aof-use-rdb-preamble yes
################ 阻塞命令配置 #####################
# Lua 脚本的最大执行时间
# lua-time-limit 5000
# busy-reply-threshold 5000
############################# 集群配置(仅集群模式才需设置) ###########################
# 是否启用 Redis 集群模式
# cluster-enabled yes
# 节点通信超时时间
# cluster-node-timeout 15000
# 在槽不完整时是否停止服务
# cluster-require-full-coverage yes
################################## 慢日志 ###################################
# 慢查询日志记录的阈值(微秒)
slowlog-log-slower-than 10000
# 慢查询日志的最大条目数
slowlog-max-len 128
# 记录延迟峰值的阈值,0为不监控
latency-monitor-threshold 0
############################### 优化配置 ###############################
# 是否开启主动 rehash,优化内存
activerehashing yes
# Redis 内部任务执行频率,调大可以加快定时任务的执行频率
hz 10
# 是否动态调整 hz
dynamic-hz yes
Redis 缓存策略与过期机制
5.1 常用的缓存淘汰策略(LRU、LFU、TTL)
1. LRU(Least Recently Used,最近最少使用)
- 定义:LRU 策略基于使用时间来淘汰最久未使用的数据。当 Redis 的内存使用达到最大限制时,它会移除最近最少使用的键。
- 适用场景:当缓存的热点数据频繁变动且老数据不再被访问时适用,确保经常被访问的数据保留在内存中。
2. LFU(Least Frequently Used,最少使用频率)
- 定义:LFU 策略基于访问频率来淘汰最少使用的键。每次访问一个键时,都会增加其计数器。当内存不足时,淘汰访问频率最低的键。
- 适用场景:适合那些频繁访问的热数据需要长时间保留的情况。
3. TTL(Time to Live,存活时间)
- 定义:TTL 是为每个键设置一个过期时间,当达到这个时间点时,Redis 会自动删除该键。
- 适用场景:适合需要时间敏感的数据,例如短期有效的会话或临时数据。
Redis 的淘汰策略除了 LRU、LFU 之外,还有一些其他选项
- noeviction:禁止淘汰,内存满后直接返回错误。
- allkeys-lru:所有键都参与 LRU 淘汰,而不仅仅是设置了过期时间的键。
- allkeys-lfu:所有键都参与 LFU 淘汰。
- volatile-lru:仅对设置了过期时间的键使用 LRU 淘汰策略。
- volatile-lfu:仅对设置了过期时间的键使用 LFU 淘汰策略。
- volatile-ttl:优先淘汰那些即将过期的键。
- volatile-random:随机淘汰一些设置了过期时间的键。
- allkeys-random:随机淘汰内存中的任意键。
5.2 数据过期与自动淘汰
Redis 提供两种方式来处理键的过期
- 惰性删除(Lazy Deletion)
当客户端访问某个键时,如果该键已经过期,Redis 才会将其删除。 优点:减少系统资源消耗。 缺点:可能会导致大量的过期数据堆积,占用内存。 - 定期删除(Periodic Deletion)
Redis 会定期扫描一部分设置了过期时间的键,并删除其中已经过期的键。 扫描不是一次性检查所有键,而是采取随机检查的方式以避免影响性能。
5.3 缓存穿透、缓存雪崩与缓存击穿
1. 缓存穿透
- 定义:缓存穿透是指客户端频繁请求不存在的数据,导致每次请求都会到达数据库,无法利用缓存。
- 应对措施
- 布隆过滤器(Bloom Filter) :利用布隆过滤器将所有可能存在的键进行判断,非存在的键直接被过滤,不查询数据库。
- 缓存空值:对于查询结果为空的数据,可以在缓存中保存一个短期的空值,防止频繁查询。
2. 缓存雪崩
- 定义:缓存雪崩是指在同一时间大量缓存数据过期,导致大量请求同时涌向数据库,造成数据库压力过大甚至宕机。
- 应对措施
- 缓存过期时间分散:避免大量键在同一时间过期,使用随机过期时间。
- 请求限流:限制数据库访问请求的频率,防止瞬间的大量流量涌入。
- 多级缓存:在 Redis 上层增加本地缓存,降低 Redis 的压力。
3. 缓存击穿
- 定义:缓存击穿是指某些热点数据(通常是非常高并发的请求)突然失效,导致大量请求同时涌向数据库。
- 应对措施
- 热点数据永不过期:对热点数据设置较长的 TTL 或直接不设置过期时间。
- 互斥锁(Mutex) :当缓存失效时,只有一个线程去加载数据并更新缓存,其它线程等待。
- 请求合并:将多个相同的请求合并为一个,从而减少对数据库的访问。
Redis 事务与分布式锁
lua脚本
Lua 脚本中的所有 Redis 命令会被 Redis 作为一个整体执行,确保操作的原子性。也就是说,脚本中所有命令要么全部执行,要么全部失败,没有中间状态。
需要注意的是,集群环境下,Lua脚本设置的所有key都需要在一个hash槽下,否则会报错。
less
EVAL "redis.call('SET', KEYS[1], 'value1'); redis.call('SET', KEYS[4], 'value2'); return {redis.call('GET', KEYS[1]), redis.call('GET', KEYS[2])}" 2 key1 key2
(error) CROSSSLOT Keys in request don't hash to the same slot
事务
Redis 的事务(Transaction)是一组命令的集合,它们按照顺序执行,提供一种批量执行多个命令的方式。在事务执行期间,Redis 保证命令的顺序性,但不提供传统数据库中的回滚机制。Redis 事务主要通过以下几个命令实现:
- MULTI:事务的开始,标记事务的开始点。
- EXEC:执行事务内的所有命令,Redis 会按顺序执行事务中的命令。
- DISCARD:取消事务,放弃事务中的所有命令。
- WATCH:用于乐观锁机制,监视一个或多个键。如果在事务执行前这些键被其他客户端修改,事务会被中止(EXEC 不会执行任何命令)。
Redis 事务没有回滚机制。如果事务中的某条命令失败,其他命令仍会继续执行。事务的所有命令在 EXEC 执行时才会真正提交。在执行 EXEC 前,所有命令都只是入队,真正的操作只有在 EXEC 时才进行。
什么是 Redis 分布式锁?
Redis 可以通过其原子操作和快速的内存访问特性来实现分布式锁。实现 Redis 分布式锁的原理主要基于redis执行命令或者Lua脚本的原子性(细节可以参考redission)。
Redlock 分布式锁算法
redlock主要解决的问题
- 客户端A在主服务器上获取锁。
- 在将密钥的写入传输到副本之前,主服务器崩溃了。
- 副本被提升为主副本。
- 客户端 B 获取了对 A 已持有锁的同一资源的锁。
Redlock前置条件是多集群,官方说了redlock也并不是绝对安全的,不同集群的TTL不一致同样会导致锁的不一致,为了提升一点可靠性而增加系统的复杂度,我认为这是得不偿失的选择。 redis.io/docs/latest...
Redis 持久化机制
Redis 提供了两种主要的持久化机制------RDB(Redis Database Backup)和 AOF(Append Only File),每种方式都有其优缺点和适用场景。为了确保数据持久化的同时兼顾性能,Redis 还提供了一些优化策略,如混合持久化模式。
8.1 RDB 快照持久化
RDB(Redis Database Backup) 是 Redis 的一种默认持久化机制,通过将内存中的数据定期生成快照保存到磁盘上(每一次都是全量保存)。
开启方式
- save命令,阻塞命令,导致服务不可用
- bgsave命令,非阻塞(推荐)
- 配置 save 3600 2(自动save一小时有两次修改则bgsave一次)
优点 :
RDB 文件是紧凑的二进制文件,数据恢复速度很快。
对 Redis 性能影响较小,因为 Redis 可以异步地保存快照。
缺点 :因为 RDB 是定期保存,可能会丢失最后一次快照到宕机之间的数据。
生成 RDB 文件时,可能会消耗大量的 CPU 和 IO 资源,尤其是数据量大时。
8.2 AOF 持久化与日志重写
AOF(Append Only File) 是另一种持久化方式,它通过将每一个写操作(命令)记录到文件中(类似于WAL),以日志的形式追加保存到磁盘。相比于 RDB,AOF 提供了更强的数据一致性保障,宕机时最多只会丢失一小部分的数据。
开启方式 :appendonly yes
优点 :
AOF 提供了更高的数据一致性。即使 Redis 宕机,也最多只会丢失一小段数据,视配置而定。
通过 AOF 重写机制,可以压缩和优化 AOF 文件,减少磁盘占用和恢复时间。
缺点 :AOF 文件通常比 RDB 文件大,数据恢复较慢。
AOF 模式下频繁的写入可能会对 Redis 性能产生一定影响。
AOF 持久化策略(就是落盘策略,配置appendfsync):
- always: 每次写入都执行 fsync,保证数据不会丢失,但性能开销最大。
- everysec: 每秒执行一次 fsync,兼顾数据安全性和性能,最常用。
- no: 不执行 fsync,由操作系统决定何时将数据写入磁盘,性能最好,但数据安全性较低。
8.3 混合持久化模式
Redis 还支持混合持久化 模式,当开启 appendonly yes
和 aof-use-rdb-preamble yes
时,就启用了混合模式。
在 AOF 文件重写时,Redis 会生成一个混合格式的新持久化文件。新文件的前半部分是 RDB 格式的快照,用于快速恢复大部分数据,后半部分是增量的 AOF 日志,用于记录最近的写操作。这样既提升了数据恢复速度,也减少了磁盘占用。
8.4 持久化策略的选择与优化
要求不丢数据 :建议开启 AOF 并选择 always
模式。这样可以最大限度地确保数据一致性,宕机时不会丢失数据
要求性能优先:如果对数据一致性要求不高,比如只对redis存储了缓存数据,且更关注 Redis 的性能,可以选择仅使用 RDB 快照方式(只用作缓存的话,宕机恢复数据在我看来就是伪命题,恢复的缓存数据真的有用吗,如果缓存的数据已经被更新了,导致数据不一致,反而得不偿失,不如启动空实例,做好数据预热)。
Redis 集群与高可用
在大规模应用场景中,Redis的高可用性和数据分布特性至关重要。Redis 提供了主从复制(Replication)、哨兵机制(Sentinel )和集群架构(Cluster)三种机制来提高高可用性、数据冗余和水平扩展能力。
9.1 Redis 主从复制(Replication)
开启方式 设置replicaof,设置需要同步的主节点的ip
9.2 Redis Sentinel 机制
9.3 Redis Cluster 集群架构
9.4 集群搭建步骤与配置
创建多个redis.conf,修改port防止端口冲突,并开启cluster-enabled
conf
port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
执行命令 redis-cli --cluster create 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 --cluster-replicas 1
,默认情况下redis会根据cluster-replicas自动分配16384(2^14)个hash槽,设置各个节点的主从角色

注意使用redls-cli连接集群时需要指定参数 -c ,否则只是连上当前节点(返回MOVED错误),redis会自动计算key所对应的hash槽,发送命令到对应的节点