Redis
数据结构
- key 都是字符串类型
- value 有5种数据类型,分别是:String、Hash、List、Set、Zset
数据操作
- 字符串类型(String):GET/SET/DEL/INCR/SETNX
- 哈希类型(Hash):HSET/HGET/HINCRBY
- 列表(List):LPUSH/RPOP/LRANGE
- 有序集合类型(Zset):ZADD/ZRANGEBYSCORE/ZREVRANGE/ZINCRBY/ZSCORE
过期策略
过期即失效,但不等于删除,有三种过期策略,Redis只使用了定期过期和惰性过期两种
-
定时删除:立即删除过期的key
设置过期时间的同时,为该key创建一个定时器,key过期时立即进行删除
内存释放最及时,但CPU占用最多,当key很多时,需要创建和维护大量定时器
-
惰性删除:只有当访问key时才去检查key是否过期,过期了则删除
CPU占用最少,但内存释放最不及时,当大量key过期却没有被访问时,会造成无效的内存占用
-
定期删除:每隔一段时间对过期的key进行删除
限制了删除时长和频率,CPU占用较少,内存释放较及时
内存淘汰策略
当内存不足以执行写入操作时,使用淘汰策略:
- volatile-lru:在设置了过期时间的键空间中,使用LRU策略
- allkeys-lru:在整个键空间中,使用LRU策略(最常用)
- volatile-lfu:在设置了过期时间的键空间中,使用LFU策略
- allkeys-lfu:在整个键空间中,使用LFU策略(最常用)
持久化机制
为了避免数据丢失了,Redis提供了RDB和AOF两种持久化机制,把数据保存到磁盘。
RDB快照持久化
RDB 把内存数据以快照形式保存到磁盘上,每次将内存中的数据集快照写入磁盘中,在指定目录下生成一个dump.rdb文件,Redis 重启的时候,通过加载dump.rdb文件来恢复数据
- 手动触发(一般不会用): save:同步,会阻塞当前redis服务进行持久化操作 bgsave :异步,Redis进程执行fork操作创建子进程进行持久化操作
- 自动触发: save m n (m秒内数据集存在n次修改,自动触发bgsave)
RDB 适合大规模的数据恢复场景,如备份,全量复制等,异步可以可以最大化性能,速度比 AOF 的恢复速度快,但不能做到实时持久化
Redis默认开启
持久化时,过期的key不会被写入文件,恢复数据时,过期的key不会被导入内存
AOF追加文件持久化
AOF(Append Only File) 持久化,采用日志来记录每个写操作,追加到文件中,重启时再重新执行AOF文件中的命令来恢复数据,主要解决数据持久化的实时性问题,来保证数据的一致性和完整性,但当记录内容增多时,文件变大,数据恢复速度变慢。
默认不开启,可以通过配置项开启,且允许同时开启AOF和RDB
过期的key不会被持久化,过期的key被删除时,向AOF文件追加一条del命令
注意事项
-
大Key: key 对应的value占用字节数特别多
- 读取成本高
- 容易导致慢查询(过期、删除)或请求超时
- 主从复制异常,服务阻塞,无法正常响应请求
解决办法
-
将大key拆分为小key
-
数据压缩,将value压缩后写入redis,读取时解压后再使用。压缩算法可以是gzip、snappy、lz4等, 如果存储的是JSON字符串,可以考虑使用MessagePack进行序列化。
通常压缩率高,解压耗时就长
-
区分冷热,热数据缓存在内存中,冷数据保存在db中
-
热Key:Key的QPS特别高,容易导致Server实例出现CPU负载突增或者不均
解决办法
-
在业务服务侧设置Localcache,降低访问Redis的QPS,如Java的Guava、Golang的Bigcache
Redis代理的热Key承载能力,本质上是结合了“热Key发现”、“LocalCache”两个功能
-
分流。将key:value这一个热Key复制写入多份,例如key1:value,key2:value,访问的时候访问多个key,但value相同,以此将qps分散到不同实例上,降低负载。但代价是,更新时需要更新多个key,存在数据短暂不一致的风险
-
-
批量操作可能导致慢查询
-
缓存穿透:缓存未命中,查询绕过缓存,直接查询数据库
在高并发场景下,热key如果过期,会有大量请求同时击穿至db,影响db性能和稳定
如果有系统bug或人为攻击故意大量查询一定不存在的数据,也可能导致db响应慢甚至宕机
解决办法:
- 缓存空值。当查询到一个在缓存和数据库中都不存在的key时,则可以对该key缓存一个空value,下次再查时缓存直接返回空值
- 布隆过滤器。布隆过滤器使用哈希技术能快速判断一个key在数据库中一定不存在或可能存在(存在假阳性),减少无效访问db
-
缓存雪崩:大量缓存同时过期
同一时间有大量key集中过期时,也会导致大量请求落到db上,导致查询变慢,甚至出现db无法响应新的查询
解决办法
- 将缓存失效时间分散开,比如在原有的同一失效时间基础上增加一个随机值
- 使用缓存集群,避免单机宕机造成的缓存雪崩。