Home 成长之路 Leetcode题解 DBA:乐信Redis开发规范

DBA:乐信Redis开发规范

  1. DBA
  2. DBA
  3. 【Redis】

DBA : 乐信Redis开发规范

Created by  lanceli(李志财), last modified on 四月 08, 2021

简介: 本文介绍了在使用乐信Redis的开发规范,从键值设计、命令使用、客户端使用、相关工具等方面进行说明,

通过本文的介绍可以减少使用Redis过程带来的问题。

乐信Redis规范

简介

Redis 是基于单线程模型实现的,也就是 Redis 是使用一个线程来处理所有的客户端请求的,尽管 Redis 使用了非阻塞式 IO,并且对各种命令都做了优化(大部分命令操作时间复杂度都是 O(1)),但由于 Redis 是单线程执行的特点,因此它对性能的要求更加苛刻,再快的系统,也经不住疯狂的滥用,本文介绍了在使用乐信Redis的开发规范,从键值设计、命令使用、优化建议、运营平台等方面进行说明,通过本文的介绍可以减少使用Redis过程带来的问题。

一、键值设计

1. key名设计

(1)【建议】: 可读性和可管理性

命令规范:以英文冒号分隔key,前缀概念的范围的返回从大到小,从不变到可变,从变化幅度小到变化幅度大。业务名:key用途:变量

例如:yoga:user:1,表示 yoga:user:{userID},即瑜伽子系统ID=1的用户信息

(2)【建议】:简洁性

保证语义的前提下,控制key的长度,不超64个字符。

当key较多时,内存占用也不容忽视,例如:

user:friends:messages:{mid} 简化为 u:fr:msg:{mid}

(3)【强制】:不要包含特殊字符

反例:包含空格、换行、单双引号以及其他转义字符

Redis 的 Key 一定要规范,这样在遇到问题时,能够进行方便的定位。Redis 属于无 scheme 的 KV 数据库,所以,我们靠约定来建立其 scheme 语义。其好处:

1、能够根据某类 key 进行数据清理

2、能够根据某类 key 进行数据更新

3、能够方面了解到某类 key 的归属方和应用场景

4、为统一化、平台化做准备,减少技术变更

2. value设计

(1)【强制】:拒绝bigkey

字符串类型:它的big体现在单个value值很大,一般认为超过10KB就是bigkey

非字符串类型:哈希、列表、集合、有序集合,它们的big体现在元素个数太多,元素个数不要超过5000

bigkey的危害

1、Redis集群的内存空间不均匀 由于Redis单线程的特性

2、操作bigkey的通常比较耗时,也就意味着阻塞Redis可能性越大

3、bigkey也就意味着每次获取要产生的网络流量较大,容易打满带宽

4、过期删除的时候会阻塞Redis

以下是压测结果,可直观看出bigkey对性能的影响:

(2)【推荐】:选择适合的数据类型

例如:实体类型(要合理控制和使用数据结构内存编码优化配置,例如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

3.【强制】:控制key的生命周期,redis不是垃圾桶。

如果应用将Redis定位为缓存Cache使用,对于存放的Key一定要设置超时时间!因为若不设置,这些Key会一直占用内存不释放,造成极大的浪费,而且随着时间的推移会导致内存占用越来越大,直到达到服务器内存上限!另外Key的超时长短要根据业务综合评估,而不是越长越好!(某些业务要求key长期有效。可以在每次写入时,都设置超时时间,让超时时间顺延。)

二、Redis命令使用规范

1、【强制】严禁不设置范围的批量操作

  • 例如hgetall、lrange、smembers、zrange、sinter等并非不能使用,但是需要明确N的值,有遍历的需求可以使用hscan、sscan、zscan代替。
  • zrange、 zrangebyscore等多个操作 zset 的函数,严禁使用 zrange myzset 0 -1 等这种不设置范围的操作。请指定范围,如 zrange myzset 0 100,如不确定长度,可使用 zcard 判断长度。
  • hgetall会取出相关 hash 的所有数据,如果数据条数过大,同样会引起阻塞,请确保业务可控。如不确定长度,可使用 hlen 先判断长度。
  • 严禁使用 sunion, sinter, sdiff等一些聚合操作。

2、【强制】禁用 select 函数

select函数用来切换 database,对于使用方来说,这是很容易发生问题的地方,cluster 模式也不支持多个 database,且没有任何收益,dba已通过配置禁用。

3、【强制】禁用命令

禁止线上使用keys、flushall、flushdb等,通过redis的rename机制禁掉命令,或者使用scan的方式渐进式处理。dba已通过配置禁用这些命令。

4、【强制】不推荐使用事务

Redis的事务功能较弱(不支持回滚),而且集群版本(自研和官方)要求一次事务操作的key必须在一个slot上。

三、使用优化建议

1、缩短键值对的存储长度

键值对的长度是和性能成反比的,比如我们来做一组写入数据的性能测试,执行结果如下:

从以上数据可以看出,在 key 不变的情况下,value 值越大操作效率越慢,因为 Redis 对于同一种数据类型会使用不同的内部编码进行存储,比如字符串的内部编码就有三种:int(整数编码)、raw(优化内存分配的字符串编码)、embstr(动态字符串编码),这是因为 Redis 的作者是想通过不同编码实现效率和空间的平衡,然而数据量越大使用的内部编码就越复杂,而越是复杂的内部编码存储的性能就越低。

2、冷热数据分离

不要将所有数据全部都放到Redis中,建议根据业务只将高频热数据存储到Redis中【QPS大于5000】,重要性级别较低的但却需求容量较大的场景可申请完全兼容Redis操作的Pika,对于低频冷数据可以使用MySQL/ElasticSearch等基于磁盘的存储方式。

3、业务数据分离

不要将不相关的数据业务都放到一个 Redis中。一方面避免业务相互影响,另一方面避免单实例膨胀,并能在故障时降低影响面,快速恢复。

4、大文本数据要压缩

对于大文本【超过500 byte】写入到Redis时,一定要压缩后存储!大文本数据存入Redis,除了带来极大的内存占用外,在访问量高时,很容易就会将网卡流量占满,进而造成整个服务器上的所有服务不可用,并引发雪崩效应,造成各个系统瘫痪。

5、使用连接池

使用带有连接池的客户端,可以有效控制连接,同时提高效率

6、缓存 Key 设置失效时间的建议

如果在大型系统中有大量缓存在同一时间同时过期,那么会导致 Redis 循环多次持续扫描删除过期字典,直到过期字典中过期键值被删除的比较稀疏为止,而在整个执行过程会导致 Redis 的读写出现明显的卡顿,卡顿的另一种原因是内存管理器需要频繁回收内存页,因此也会消耗一定的 CPU。

为了避免这种卡顿现象的产生,我们需要预防大量的缓存在同一时刻一起过期,就简单的解决方案就是在过期时间的基础上添加一个指定范围的随机数。

7、限制Redis 分片大小

乐信标准,Redis都有分片,最少一个分片,单分片的大小是4G ,为何不建议一直往上加内存?

  • 单台服务器内存资源有限,不利于扩展
  • 单个分片内存过大,服务器出故障时,影响面大
  • Redis持久化时,虽然操作是异步化,但会有fork进程的操作,这一步是由主进程来完成的,分片内存越大,页表就越大,fork执行时间就越长,就会给主线程带来阻塞风险
  • 不利于平台标准化,后期迁移困难
  • Redis是单进程模型,只能利用一个CPU核心,多分片有利于提高Redis集群能力,充分利用多核性能。

8、认真对待最大内存淘汰策略

根据自身业务类型选择好最大内存淘汰策略,可保证有用数据不被删除,也可避免Redis实例出现OOM,让Redis持续高效。

  • noeviction:不淘汰任何数据,当内存不足时,新增操作会报错,Redis 默认内存淘汰策略
  • allkeys-lru:淘汰整个键值中最久未使用的键值
  • allkeys-random:随机淘汰任意键值
  • volatile-lru:淘汰所有设置了过期时间的键值中最久未使用的键值(乐信默认)
  • volatile-random:随机淘汰设置了过期时间的任意键值
  • volatile-ttl:优先淘汰更早过期的键值

在 Redis 4.0 版本中又新增了 2 种淘汰策略:

  • volatile-lfu:淘汰所有设置了过期时间的键值中,最少使用的键值
  • allkeys-lfu:淘汰整个键值中最少使用的键值

四、运营平台

了解Redis这么多使用规范和优化建议,日常中如何去查看自己应用中使用的Redis实例是否合理呢,通过宙斯Redis健康分析系统(http://zeus.oa.fenqile.com/Redis/redis/show_redis/)即可快速查看

主要功能如下:

1、查找内存占用最高的key

2、查找bigkey

3、查找未设置过期时间的key

Document generated by Confluence on 四月 07, 2023 17:43

补充:Redis的bigKey的危害

Redis中的bigKey(大键值)指的是那些包含大量元素或占用大量内存空间的键。以下是bigKey可能带来的几个显著的危害:

  1. 内存瓶颈
    • 单个bigKey可能占用大量内存,导致Redis实例内存迅速增长,接近或超过最大内存限制(maxmemory)设置,如果没有适当的内存淘汰策略,可能导致其他重要数据无法缓存,甚至发生内存溢出(OOM),从而致使Redis服务不稳定或崩溃。
  2. 性能瓶颈
    • Redis基于单线程模型运行,对bigKey的操作(如读取、修改或删除)会消耗较长时间,这可能导致Redis服务器暂时停止处理其他客户端请求,因为Redis必须先完成当前操作才能继续处理队列中的下一个命令。这种情况下,bigKey操作很容易引起阻塞,增加客户端请求的延迟,产生所谓的“慢查询”。
  3. 阻塞和客户端超时
    • 处理bigKey时,Redis可能长时间处于阻塞状态,客户端在此期间可能因等待响应超时而终止连接,严重影响服务可用性。
  4. 网络拥塞
    • bigKey的传输可能会导致网络带宽占用过大。例如,当bigKey的内容被客户端频繁地获取时,网络流量剧增,特别是在低带宽环境下,可能导致网络拥堵,降低整体系统的性能。
  5. 集群不平衡
    • 在Redis集群环境中,bigKey可能导致集群中某个节点的内存使用率远高于其他节点,破坏数据分片的内存资源均衡,进一步影响整个集群的稳定性与性能。
  6. 扩容困难
    • 当需要迁移bigKey时,由于其大小和复杂性,迁移操作可能会非常耗时,给在线扩容或数据迁移带来挑战。

因此,针对bigKey问题,通常建议采取以下措施:

  • 设计合理的数据结构和编码方式,避免单个键存储过多数据。
  • 定期检查和监控Redis中的大键值,及时优化或合理拆分bigKey。
  • 使用合适的内存淘汰策略,防止bigKey影响其他重要数据的缓存。
  • 对于删除操作,尽量使用异步删除命令(如unlink)减少阻塞时间。
  • 在集群环境中,合理分配数据,避免bigKey集中在单个节点上。

SIMILAR ARTICLES

发表评论

发表评论