目录
目录
1.数据类型
数据类型 | 样例解释 | 优缺点 | 操作 | 应用场景 |
---|---|---|---|---|
string | key:value | 简单 | set、get、del expire incr、decr | 最常用 分布式锁 |
hash | bigkey: {subKey:subval,subkey2:...} | 避免了命名冲突, 可统一删除 (过大时不宜, 应scan迭代删除)
过期时间针对bigkey, 不能对subkey设置过期 | hset hget hscan | |
set | 无重复数据的集合 | 可求交集并集差集 | sadd | 可用作抽奖,存放点赞的人 实现共同关注的人,可能认识的人等功能 |
zset | 有序的无重复数据集合 | 可以用在时事热点信息的排序上 | ||
list | 列表 | 用于消息列表 |
2.memcached VS redis 对比
memcache适合以KV类型,数据量、并发业务量大的场景,支持多线程操作,充分利用CPU,但缓存不能持久化
Redis拥有丰富的数据类型,支持缓存持久化,宕机更容易数据恢复,单线程场景比memcache快
3.部署模式
单机 | 可用性差 | 适用于可以接受缓存穿透的场景 |
---|---|---|
哨兵 | 可用性高 提供了主从的监控,当主节点宕机,从节点快速切换成主, | 适合缓存高可用场景,缺点是不易扩容 |
集群 | 横向扩展-负载均衡 | 适合大数据量的高可用缓存场景,集群模式内存和QPS不受限于单机 通信采用gossip协议,请求逐步打到各个节点上,有一定延迟,但集群压力比较小 |
4.持久化
用于宕机恢复
类型 | 备份内容 | 恢复方式 |
---|---|---|
AOF | (oplog)操作日志 几乎实时备份命令,通常设置1秒备份一次 | 通过记录命令 重复执行进行恢复数据, 效率较低, 但数据比较全 |
RDB | 数据快照(snapshot)快照 每隔一段时间用子线程进行全量备份
| 直接数据的传输覆盖, 数据不全 |
5.过期策略expire
内存与CPU的权衡
策略 | 优点 | 缺点 | |
---|---|---|---|
定时删除 | 到key过期时间立即删除 | 保证内存尽快释放, 保证过期的准时性
| 消耗CPU时间 若过期key很多,删除这些key会比较消耗CPU时间 每设置一个过期时间会创建一个定时器,大量定时器会比较影响性能 |
定期删除 | 定期时间到了会检查key是否过期,过期则删除 | 通过限制删除操作的时长和频率, 来减少对CPU时间的占用 | 会造成一定的内存占用 |
惰性删除 | 再次通过key来获取值的时候,会检查key是否过期,过期则删除 | 删除操作只发生在通过key取值的时候,占用CPU较少 | 更占用内存,若大量数据缓存而不再调用,可能导致内存溢出 |
6.淘汰策略(内存达到阈值)
策略 | 算法 |
---|---|
volatile-lru | 从expire的数据集中挑选最近最少使用的数据淘汰 |
volatile-ttl | 从expire的数据集中挑选将要过期的数据淘汰 |
volatile-random | 从expire的数据集中任意选择数据淘汰 |
allkeys-lru | 从所有key挑选最近最少使用淘汰 |
allkeys-random | 从所有key任意选择数据淘汰 |
no-enviction | 不淘汰数据 |
7.常见术语
术语 | 现象解释 | 解决方案 |
---|---|---|
缓存穿透 | 缓存不命中, 请求越过缓存访问数据库,导致数据库崩掉 | 缓存不存在时,数据库返回null值也存入缓存, 之后直接通过缓存返回null的处理办法 |
缓存雪崩 | 大量缓存在同一时间失效, 请求都打到数据库,导致数据库崩掉 | 加锁或队列(并发控制),缓存失效,对某个key只允许一条线程访问,其它等待 失效时间设置不同,可以在一个时间范围乘个随机数,尽量分布均匀 加二级缓存,二级缓存失效时间大于一级缓存,一级缓存失效,二级可以起到作用 手动reload如果能预计到某个时间点会有大量并发操作,可以设计手动reload缓存 |
缓存预热 | 系统启动时对热点数据进行缓存主动加载 |
8.使用军规
一、键值设计 #
1. key名设计
-
(1)【建议】: 可读性和可管理性
以业务名(或数据库名)为前缀(防止key冲突),用冒号分隔,比如业务名:表名:id
ugc:video:1
-
(2)【建议】:简洁性
保证语义的前提下,控制key的长度,当key较多时,内存占用也不容忽视,例如:
user:{uid}:friends:messages:{mid}简化为u:{uid}:fr:m:{mid}。
-
(3)【强制】:不要包含特殊字符
反例:包含空格、换行、单双引号以及其他转义字符
2. value设计
-
(1)【强制】:拒绝bigkey(防止网卡流量、慢查询)
string类型控制在10KB以内,hash、list、set、zset元素个数不要超过5000。
反例:一个包含200万个元素的list。
非字符串的bigkey,不要使用del删除,使用hscan、sscan、zscan方式渐进式删除,同时要注意防止bigkey过期时间自动删除问题(例如一个200万的zset设置1小时过期,会触发del操作,造成阻塞,而且该操作不会不出现在慢查询中(latency可查)),查找方法和删除方法
-
(2)【推荐】:选择适合的数据类型。
例如:实体类型(要合理控制和使用数据结构内存编码优化配置,例如ziplist,但也要注意节省内存和性能之间的平衡)
反例:
set user:1:name tomset user:1:age 19set user:1:favor football
正例:
hmset user:1 name tom age 19 favor football
3.【推荐】:控制key的生命周期,redis不是垃圾桶。
建议使用expire设置过期时间(条件允许可以打散过期时间,防止集中过期),不过期的数据重点关注idletime。
二、命令使用 #
1.【推荐】 O(N)命令关注N的数量
例如hgetall、lrange、smembers、zrange、sinter等并非不能使用,但是需要明确N的值。有遍历的需求可以使用hscan、sscan、zscan代替。
【建议】 单个请求的返回值控制100KB之内;
2.【推荐】:禁用命令
禁止已禁用使用keys、flushall、flushdb等;有变量需求通过使用scan的方式渐进式处理。
3.【推荐】不要使用select
redis的多数据库较弱,使用数字进行区分,很多客户端支持较差,同时多业务用多数据库实际还是单线程处理,会有干扰。
我们提供的集群不支持多个数据库;
4.【推荐】使用批量操作提高效率
可以使用pipeline提高效率。有mget场景尽量改用pipeline(mget对proxy的消耗比较大)
但要注意控制一次批量操作的元素个数(例如500以内,实际也和元素字节数有关)。
5.【建议】Redis事务功能较弱,不建议使用
我们提供了proxy不支持redis事务功能;Redis的事务功能较弱(不支持回滚),如果非得使用只能直连使用;
7.【建议】必要情况下使用monitor命令时,要注意不要长时间使用。(在平台上有支持,平台管理页面的faina统计使用的是monitor命令)
三、服务使用 #
1.【推荐】
避免多个应用使用一个Redis实例
正例:不相干的业务拆分,公共数据做服务化。
5.【建议】
根据自身业务类型,选好maxmemory-policy(最大内存淘汰策略),设置好过期时间。
默认策略是volatile-lru,即超过最大内存后,在过期键中使用lru算法进行key的剔除,保证不过期数据不被删除,但是可能会出现OOM问题。
其他策略如下:
-
allkeys-lru:根据LRU算法删除键,不管数据有没有设置超时属性,直到腾出足够空间为止。
-
allkeys-random:随机删除所有键,直到腾出足够空间为止。
-
volatile-random:随机删除过期键,直到腾出足够空间为止。
-
volatile-ttl:根据键值对象的ttl属性,删除最近将要过期数据。如果没有,回退到noeviction策略。
-
noeviction:不会剔除任何数据,拒绝所有写入操作并返回客户端错误信息"(error) OOM command not allowed when used memory",此时Redis只响应读操作。
四 附录:删除bigkey #
1. 下面操作可以使用pipeline加速。
1. Hash删除: hscan + hdel
2. List删除: ltrim
3. Set删除: sscan + srem
4. SortedSet删除: zscan + zrem