author:skate
time:2018/12/22
1.设计规范的key名
(1)【建议】: 可读性和可管理性
以业务名(或数据库名)为前缀(防止key冲突),用冒号分隔,比如业务名:表名:id,一般redis Key需要能明显的看出该类型存储的数据是干嘛的
例如 :uc :colibri:id
(2)【建议】:简洁性
保证语义的前提下,控制key的长度,当key较多时,内存占用也不容忽视。
(3)【强制】:不要包含特殊字符
反例:包含空格、换行、单双引号以及其他转义字符。
2.选择合适集合类
使用sortedset、set、list、hash等集合类的O(N)操作时要评估当前元素个数的规模以及将来的增长规模,对于短期就可能变为大集合的key,要预估O(N)操作的元素数量,
避免全量操作,可以使用HSCAN、SSCAN、ZSCAN进行渐进操作。集合元素数量过大在使用过程中会影响redis的实际性能,元素个数建议尽量不要超过5000,元素数量过大可
考虑拆分成多个key进行处理。
3.大key优化方法
redis是单线程运行的,如果一次操作的key(value值很大)很大会对整个redis的响应时间造成负面影响,所以遇到大key近最大可能拆分
单个key的存储的value值很大
场景1:需要对该对象每次都整存整取
a.可以尝试将对象分拆成几个key-value, 使用multiGet获取值,这样分拆的意义在于分拆单次操作的压力,将操作压力平摊到多个redis实例中,降低对单个redis的IO影响,提高整会话响应时间
场景2:每次只需要存取部分数据
a.可以像第一种做法一样,分拆成几个key-value
b.可以将这个存储在一个hash中,每个field代表一个具体的属性,使用hget,hmget来获取部分的value,使用hset,hmset来更新部分属性
hash/set/zset/list中存储元素过多(>5000)
通过增加一层桶的概念,减少元素的数量,以hash为例,原先的正常存取流程是:
hget(hashKey, field);
hset(hashKey, field, value)
现在,固定桶总共的数量,比如1000,每次存取的时候,先在本地计算field的hash值,模除1000,确定该field落在哪个key上(控制每个桶里元素数量)
newHashKey = hashKey + (hash(field) % 1000);
hset(newHashKey, field, value);
hget(newHashKey, field)
set、zset、list也可以类似上述做法,但也有些不适合的场景,比如要保证lpop的数据的确是最早push到list中去的,这个就需要一些附加的属性,或者是在key的拼接上做一些工作(比如list按照时间来分拆)。
4.网络引发的延迟优化
4.1 使用连接池
在客户端连接redis的server时,尽可能使用长连接或连接池,避免频繁创建销毁连接
参考:wiki地址
4.2 使用批操作
批操作意义是减少维护网络连接和传输数据所消耗的资源和时间
a.MSET/MGET/HMSET/HMGET等命令
b.pipelining
pipelining实现在一次交互中执行多条命令,Redis就会依次执行这些命令,并且把每个命令的返回按顺序组装在一起一次返回,
Pipelining只能用于执行连续且无相关性的命令,当某个命令的生成需要依赖于前一个命令的返回时,就无法使用Pipelining了
c.事务
Redis的事务可以确保多条命令执行时的原子性。也就是说Redis能够保证一个事务中的一组命令是绝对连续执行的,在这些命令执行完成之前,绝对不会有来自于其他连接的其他命令插进去执行,
通过MULTI和EXEC命令来把这两个命令加入一个事务中。
需要注意的是,Redis事务不支持回滚
d.Scripting
Redis执行LUA脚本类似于RDBMS的存储过程一样,可以把客户端与Redis之间密集的读/写交互放在服务端进行,避免过多的数据交互,提升性能.
Scripting功能是作为事务功能的替代者诞生的,事务提供的所有能力Scripting都可以做到。Redis官方推荐使用LUA Script来代替事务,Scripting的效率和便利性都超过了事务。
5.合理设置过期时间
a.小key单独设置过期时间(不要集中过去)
b.hash/set/zset/list集合类元素过多,由于只能设置集合本身的过期时间,需要自己设计过期方法,通过hscan、sscan、zscan方式渐进式删除。
如何在设计阶段就设计redis集合类型元素过期
以list为例,比如数据保留最近30天
listkey:表示某一业务链表
20181210101010:valueofkey :表示listkey链表的一个值
lpush listkey 20181210101010:valueofkey
每次读取这个值时,通过值中的时间部分判断是否过期,如果过期实际删除,如果没有过期通过重置这个时间(最好unix时间)来续命
------end------