键值设计
Key名设计
可读性和可管理性:
以业务名(或数据库名)为前缀(防止
key
冲突),用冒号分隔,比如业务名:表名:id
ugc:video:1
简洁性:
保证语义的前提下,控制
key
的长度,当key
较多时,内存占用也不容忽视,例如:
user:{uid}:friends:messages:{mid}简化为u:{uid}:fr:m:{mid}。
不要包含特殊字符:
反例:包含空格、换行、单双引号以及其他转义字符
Value设计
拒绝bigkey
:
防止网卡流量、慢查询,
string
类型控制在10KB以内,hash、list、set、zset
元素个数不要超过5000。反例:一个包含200万个元素的
list
。非字符串的
bigkey
,不要使用del
删除,使用hscan、sscan、zscan
方式渐进式删除。同时要注意防止
bigkey
过期时间自动删除问题。
- 例如一个200万的
zset
设置1小时过期,会触发del
操作,造成阻塞。- 而且该操作不会不出现在慢查询中(
latency
可查),查找方法和删除方法。
选择适合的数据类型
例如:实体类型(要合理控制和使用数据结构内存编码优化配置,例如
ziplist
,但也要注意节省内存和性能之间的平衡)
反例:
set user:1:name tom
set user:1:age 19
set user:1:favor football
正例:
hmset user:1 name tom age 19 favor football
控制key
的生命周期:
redis
不是垃圾桶,建议使用expire
设置过期时间(条件允许可以打散过期时间,防止集中过期),不过期的数据重点关注idletime
。
命令使用
O(N)
命令关注N
的数量:
例如
hgetall、lrange、smembers、zrange、sinter
等并非不能使用,但是需要明确N的值。有遍历的需求可以使用
hscan、sscan、zscan
代替。
禁用命令:
禁止线上使用
keys、flushall、flushdb
等,通过redis
的rename
机制禁掉命令,或者使用scan
的方式渐进式处理。
合理使用select
:
redis
的多数据库较弱,使用数字进行区分,很多客户端支持较差,同时多业务用多数据库实际还是单线程处理,会有干扰。
使用批量操作提高效率:
原生命令:例如
mget、mset
。非原生命令:可以使用
pipeline
提高效率。
但要注意控制一次批量操作的元素个数(例如500以内,实际也和元素字节数有关)。
注意两者不同:
原生是原子操作,
pipeline
是非原子操作。
pipeline
可以打包不同的命令,原生做不到。
pipeline
需要客户端和服务端同时支持。
不建议过多使用Redis
事务功能:
Redis
的事务功能较弱(不支持回滚),而且集群版本(自研和官方)要求一次事务操作的key
必须在一个slot
上。
- 可以使用
hashtag
功能解决。
Redis
集群版本在使用Lua
上有特殊要求:
所有
key
都应该由KEYS
数组来传递,redis.call/pcall
里面调用的redis
命令。
key
的位置,必须是KEYS array
, 否则直接返回error
"-ERR bad lua script for redis cluster, all the keys that the script uses should be passed using the KEYS arrayrn"
所有
key
,必须在1个slot
上,否则直接返回error
,"-ERR eval/evalsha command keys must in same slotrn"
monitor
命令:
必要情况下使用
monitor
命令时,要注意不要长时间使用。
客户端使用
避免多个应用使用一个Redis
实例:
不相干的业务拆分,公共数据做服务化。
使用连接池:
可以有效控制连接,同时提高效率,标准使用方式:
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
//具体的命令
jedis.executeCommand()
} catch (Exception e) {
logger.error("op key {} error: " + e.getMessage(), key, e);
} finally {
//注意这里不是关闭连接,在JedisPool模式下,Jedis会被归还给资源池。
if (jedis != null)
jedis.close();
}
熔断功能:
高并发下建议客户端添加熔断功能(例如
netflix hystrix
)
合理的加密:
设置合理的密码,如有必要可以使用
SSL
加密访问(阿里云Redis
支持)
淘汰策略:
根据自身业务类型,选好
maxmemory-policy
(最大内存淘汰策略),设置好过期时间。默认策略是
volatile-lru
,即超过最大内存后,在过期键中使用lru
算法进行key
的剔除,保证不过期数据不被删除。
- 但是可能会出现
OOM
问题。
相关工具
数据同步:
redis
间数据同步可以使用:redis-port
big key
搜索:
redis
大key
搜索工具
热点key
寻找:
内部实现使用
monitor
,所以建议短时间使用redis-faina
,阿里云Redis
已经在内核层面解决热点key
问题。
删除bigkey
:
redis 4.0
已经支持key
的异步删除。