14-Redis开发规范

nobility 发布于 2022-11-15 796 次阅读


Redis开发规范

key设计

  • 不要包含特殊字符:不包含空格、换行、单双引号以及其他转义字符
  • 可读性和可管理性:多重语义使用冒号分割分割,减少冲突方便管理(其他符号也是可以的,官方风格是冒号)
  • 简洁性:保证语义的情况下,控制key的长度,3.0版本中少于39字节(4.0版本中少于44字节)的字符串会用embstr编码格式进行存储(与value是连续的空间)更加节省空间

value设计

不使用bigkey

  • 原因:可能会导致网络阻塞,Redis阻塞,集群节点不均匀,频繁序列化导致应用服务器CPU消耗以及内存消耗
  • 阿里云官方标准:string类型在10KB以上的key和hash、list、set、zset元素个数超过5000个的key都是bigkey
  • 排查bigkey方式:
    • 客户端连接超时,有可能是bigkey阻塞造成的
    • 使用redis-cli --bigkeys可以扫描Redis中是否存在bigkey,但是无法定制化参数
    • 使用debug object指定key可以查看key的具体信息,但是只能查看到序列化后的长度,不是具体长度
    • 对redis进行实时监控,当输出流量超过预期时,可能出现了bigkey
  • 删除bigkey:bigKey删除会非常慢,会对redis发生阻塞
    • 隐形删除:过期和重命名等,隐形删除不会记录在慢查询中(从节点同步时会记录在慢查询中)
    • Redis4.0提供了懒删除,即unlink命令,可以做到后台删除,不会阻塞掉主进程

选择合适的数据结构

  • 避免出现数据松散,可以使用hash结构
  • 使用hash时,小hash会采用ziplist,更节省内存,ziplist编码采用的是不同属性使用连续的空间,但是在增加删除元素时性能差,但是属性个数少的情况下影响不大
    • 使用hash-max-ziplist-entries配置参数进行配置超过属性时使用ziplist编码,支持动态配置,默认值是512
    • 使用hash-max-ziplist-value配置参数进行配置属性值长度超过多少时使用ziplist编码,支持动态配置,默认值是64,单位字节
  • 避免不了大hash情况下可采用分段hash,进而避免bigkey,将大hash转化为小hash,根据属性个数进行取模,得到不同下标,对应segment:0、segment:1...
  • 对于统计信息合适的选择
    • 若需要返回具体哪些用户访问过系统,使用set存储
    • 若无需返回具体哪些用户访问过系统,并且不允许存在误差值,那么可以对每个用户ID对应到bitmap中存储
    • 若无需返回具体哪些用户访问过系统,并且允许存在误差值,则可以使用HyperLogLog存储

过期设计

  • 周期数据应该设置过期时间,使用object idletime指定key来查看key的闲置时间
  • 过期时间不宜集中,容易出现缓存穿透和雪崩等问题

命令使用

  • 谨慎使用复杂度为O(n)O(n)复杂度的命令,要清楚n是多少,比如hgetall、lrange、smembers、zrange、sinter等
  • 禁止线上使用keys、flushall、flushdb等,配置文件中rename-command配置项将命令重命名为空字符串,进而禁用命令
  • 合理使用select切换数据库命令,多数据库实际还是单线程处理,单个数据库阻塞时整个redis会阻塞掉
  • 不使用Redis的事务处理,因为不支持回滚
  • 可短时间使用monitor命令进行对Redis的监控,在高并发的情况下,长时间使用可能会将当前客户端的输出缓冲区撑爆,导致使用该命令的客户端崩溃,该命令类似发布订阅模式,等待其他客户端执行的命令并打印

客户端优化

  • 避免多个应用使用同一个Redis:不相干的业务拆分,公共数据做服务化
  • 合理配置连接池
    • 最大连接数和最大空闲连接数应该一样,避免再接近期间反复创建和释放连接
    • 最大连接数估计:期望的并发量命令执行平均耗时=连接数期望的并发量*命令执行平均耗时=连接数,这只是理论值,在根据具体使用情况适当的增大或缩小即可
    • 连接池中连接耗尽时,不要死等,应该设置等待超时时间,避免客户端不好的体验
    • 开启周期性的空闲连接检测
  • 标准的使用连接池
Jedis jedis = null;
try {
  jedis = jedisPool.getResource();	//获取连接对象
  //具体操作
} catch (Exception e) {
	//异常处理
} finally {
  if (null != jedis) {
    jedis.close();	//归还连接
  }
}
此作者没有提供个人介绍
最后更新于 2022-11-15