redis的value
1.value的类型有哪些?
string、list、set、hash、sorted set
2.value的类型如何选择?
根据业务数据类型选用合适的redis数据结构。
示例:
产品基本信息缓存,可使用string
全量城市数据:map
热门榜单景点id:list或者set
如果需要按优先级排序:sorted set
坏示例:
全量城市数据序列化成string,redis数据类型选用string。实际上每次get出来的map,只会用到一个key,却将全量城市数据都get出来了,增加了网络传输时间。
3.避免大key
redis各类型value最大值 大key的性能测试大key潜在的问题
首先大Key在传输键值对时,会对网络造成压力(带宽问题),并且有的proxy会将大内容分片传输,进而再次增加了网络传输时间
其次,如list、hash这类结构,如果使用时间复杂度为O(n)的指令或者使用del命令,那么会造成严重的阻塞
如何缓存大key
参考美团在Redis上踩过的一些坑-4.redis内存使用优化
https://www.iteye.com/blog/carlosfu-2254572
redis大key举例
问题表现
每次在dumper推送数据期间,会造成大量的访问异常(服务500)
问题查找
1、通过error log发现服务异常时,会有大量的redis链接超时
2、通过dumper执行日志,查找耗时的执行流程,且是对redis操作的,发现产生链接超时和对redis执行耗时的操作时间重叠
通过分析dumper代码,发现是由于对 5 库 cm=all_all_redis_ad(数据长度1kw左右) 进行删除时采用的del key,阻塞20-30s
左右,在读取 3 库 de_qp_redis(22w左右)时采用的hkeys,阻塞1.5s左右,redis阻塞导致的链接超时
问题解决
1、解决删除5库cm=all_all_redis_ad的阻塞
解决方法:在dumper时,不对该key进行删除,通过写新key,在把该key rename成旧key,在把新key rename 成该key,解决问题
好处:通过写新key,在dumper数据时原key还可以提供服务,rname操作耗时可以忽略,对服务营销最小;
然后再通过hscan分批删除或unlink(redis 4.0以上版本,python 客户端最新),异步删除旧key,解决删除时造成的阻塞
2、解决hkeys引起的阻塞
解决方法:通过hscan分批读取取代hkeys
问题总结
由于redis是典型的单线程架构,造成阻塞就会影响其他的服务
生产环境中,慎用 keys,hgetall,hkeys等操作,这些操作的时间复杂度都是O(n),大对象上做这些操作会造成阻塞
知识总结
1、对于低版本的redis(2.8以上4.0以下),采用hscan获取大key的元素,分批次删除,直到删除大key的所有元素
2、redis 4.0 以上版本,使用unlink,其执行惰性删除策略,只是将key从keyspace元数据中删除,真正删除时在后台线程异步删除;
3、redis相关配置:
lazyfree-lazy-eviction 默认关闭
针对redis内存使用达到maxmeory,并设置有淘汰策略时;在被动淘汰键时,是否采用lazy free机制;
注意:开启lazy free, 可能使用淘汰键的内存释放不及时,导致redis内存超用,超过maxmemory的限制。此场景使用时,请结合业务测试。
lazyfree-lazy-expire 默认关闭
针对设置有TTL的键,达到过期后,被redis清理删除时是否采用lazy free机制;
此场景建议开启,因TTL本身是自适应调整的速度。
lazyfree-lazy-server-del 默认关闭
针对有些指令在处理已存在的键时,会带有一个隐式的DEL键的操作。如rename命令,当目标键已存在,redis会先删除目标键,如果这些目标键是一个big key,那就会引入阻塞删除的性能问题;
此参数设置就是解决这类问题,建议可开启。
replica-lazy-flush 默认关闭
针对slave进行全量数据同步,slave在加载master的RDB文件前,会运行flushall来清理自己的数据场景;
参数设置决定是否采用异常flush机制。如果内存变动不大,建议可开启。可减少全量同步耗时,从而减少主库因输出缓冲区爆涨引起的内存使用增长。