前言
众所周知,Redis作为一款内存型K/V数据库通常会被使用在以下三种场景:当做NoSQL数据库;当做缓存;当做消息队列或者计算之类的场景。
之前在负责公司内部基于Redis分布式缓存系统的时候,经常会发现各个业务研发对于Redis数据库的滥用、乱用等问题导致的集群容量不断增长(恶性增长),或者各种超时问题不断复发的问题。由此,对于Redis的相关技术细节学习后,对于使用上做一些限制,从而可以优雅的避免容量不断的恶性增长(毕竟内存现在是越来越贵了),以及业务方频发的超时现象。
一、键值设计
1.key名设计
- 1.禁止包含特殊字符(比如空格、换行、单双引号以及其他转义字符)
- 2.建议以业务名为前缀,以冒号分割来构造一定规则的key名(比如业务名:表名:id)
- 3.控制key的长度(key太长内存也不容忽视)
注意:前两个规范可能大家很能理解,但第三个规范笔者之前也遇到过这种业务场景确实比较尴尬,业务方计算用户活跃数,key名均以用户的pin和时间戳作为key,而通常这种key名称很长,value仅仅是一个活跃标签(0或1、true或false),这种情况下,当用户量上千万之后,对于内存的占用是相当厉害的,这时候就需要对key进行重新设计来合理使用内存了
2.value设计
- 1.拒绝大key操作
- string类型控制在10KB以内,hash、list、set、zset元素尽量不超过5000
- 非字符串的bigkey,不要使用del删除;尽量使用scan家族命令进行扫描删除
- 防止bigkey过期时间自动删除问题(因为过期删除其实也是调用的del操作,阻塞后该操作是不会出现在慢查询中的)
- 2.设计key时使用合适的数据类型(在资源利用和性能之间作平衡)
比如在key名设计中的案例来说,用来统计用户活跃数其实也是可以使用其他数据结构的,比如bitmap等。因此选择一个合适的数据结构对于后期的成本核算以及维护来说都是比较友好的
- 3.
一定要控制
key的生命周期
当然,也一定需要知道业务方是把redis当做什么工具去使用的,具体是什么场景。比如说业务方就是将redis作为缓存来使用,对于后端数据库做一个削峰填谷的作用,那么久一定要对相关的key做生命周期的管理;而如果是当小型db去使用,那么可能更需要考虑的是数据的持久性和一致性
二、命令使用
推荐的命令
- O(N)命令关注N的数量
比如hgetall、lrange、smembers、zrange等,操作时需要注意范围。不明确范围的使用scan家族命令
- 使用批量操作提高效率(带m的)
比如,mset,mget,hmset,hmget等,也可以借助pipeline提高效率。但是批量的元素也需要控制,这个和实际的数据量有关
建议禁止的命令
禁止使用keys、flushall、hmgetall等命令
为防止业务研发的误操作,通常可以在交付redis实例之前将默认命令rename掉;而真正需要删除或者遍历key时可以使用scan家族命令
除非必要情况,不要持续使用monitor
禁止使用select功能来在单redis实例做多db区分
三、客户端使用
客户端分为两种,一种为业务使用数据库的客户端,第二种属于redis的管理员客户端,后者通常用于维护优化redis实例
避免多应用共享一个redis实例
建议做好业务拆分,公共数据服务化
使用带有连接池的客户端,有效控制链接
高并发下建议客户端添加熔断功能(例如netflix hystrix)
密码认证
是必须设置的
生产服务中一定要设置合理的用户认证
合理评估业务场景,并设置最大内存以及内存淘汰策略(maxmemory和maxmemory-policy)
建议maxmemory单实例最大不要超过10G;5种policy根据实际业务场景进行设置
合理设置redis实例的持久化策略
aof和rdb
四、运维测的常用工具
- 数据同步:redis-port
- bigkey搜索:scan、iscan
- 慢查询:slowlog get
- 热点key寻找:redis-faina