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槽,发送命令到对应的节点 