Redis 使用规范

基础规范

  1. 必须配置访问密码

理由:裸奔的 Redis 不仅存在被外部盗取数据的风险,在内部管理上也极易出现误操作,如误连造成数据被覆盖、丢失!

  1. 必须以非 root 用户启动

理由:Redis 的设计过于灵活,这让攻击者可以远程通过 root 运行的 redis 服务获取到操作系统 root 权限!

  1. 禁止将 Redis 当做持久化存储使用

理由:Redis 虽然支持 AOF、RDB 持久化,但是并不会记录每条操作的详细时间戳(对比 MySQL 的 binlog 会详细记录执行时间),出现误操作时无法进行精确回滚!

  1. 禁止不同业务混合部署使用同一套 Redis(公共数据做服务化)

理由:

  1. Redis 为单线程模型,不同业务的数据存储在一起,除了管理上混乱,单线程模型下只要有一个请求命令变慢,就会影响所有存储在同 Redis 中的所有请求!
  2. 虽然 Redis 支持多个 db,但是请求并不会被隔离,比如请求 0 号库的一个慢操作,也一样样会阻塞其它 1、2、3、4 库的连接和请求!
  3. 容易出现 key 冲突(可以通过将服务名作为缓存前缀来避免);
  4. 由于不同服务的数据量不一样,共用实例容易导致一个服务把另一个服务的热数据挤出去。

  1. 选择相对较新的版本,强烈建议5.0以上版本

理由:除了 5.0 版本引入了更多新特性及 bug 修复外,5.0 对 Redis 的内存碎片管理效率带来了极大的提升,而碎片绝对是 Redis 的一大性能杀手,但早期的 2.x、3.x、4.x 版本都没有很好的解决这一问题!

  1. 使用带有连接池的数据库,可以有效控制连接,同时提高效率

  1. 选择合适的 maxmemory-policy(最大内存淘汰策略)

默认策略是 volatile-lru,即超过最大内存后,在过期键中使用 lru 算法进行 key 的剔除,保证不过期数据不被删除,但是可能会出现 OOM 问题。

键值设计

  1. 建议以业务名为前缀(防止 key 冲突),以冒号分割来构造一定规则的 key 名称

理由:好的 key 名称可以提高可读性和可管理性。

  1. key 名称禁止包含特殊字符,比如空格、换行、单双引号等其它转义字符等

理由:带有特殊符号的 Key,在读取或管理时会带来想不到的各种异常和不便。

  1. 控制 key 名称长度,建议 64 字符以内,避免 Key 过多带来较大的内存开销

理由:内存是昂贵的,几千万或者上亿个的 Key 时,额外的内存开销不容忽视。

示例:user:{uid}:friends:messages:{mid} 可以简化为 u:{uid}:fr:m:{mid}。

  1. 控制 value 大小,如果超过 512 字节必须进行压缩存储,最大不能超过 1K

理由:

  1. Redis的所有数据都存储在内存中!内存中!内存中!!(不管 Redis 开不开启持久化,所有数据都是存储在内存中),而内存的成本是非常高的;
  2. 除了成本外,这种大容量的数据存储在 Redis 中,在访问的 QPS 稍微高一些时,网卡的压力会非常大,大概率会发生网卡流量打满情况(瞬时吞吐量 = QPS * 单个请求对象大小)。这种情况建议走独立的图片存储服务、应用程序缓存或 CDN 等方式,对于过长的字符串(512个字节以上)建议进行序列化或压缩后再存储!
  3. 较大的 value,写入速度也会受影响,整体影响写入的吞吐量。

  1. 选择合适的数据类型

操作命令

  1. 禁止使用 keys、flushall、flushdb 等命令

理由:keys 的正则匹配是阻塞式、全量扫描过滤的,对于单线程服务的 Redis 来说是致命的,几十万个 key 的匹配查询在高并发访问下就有可能将 Redis 打崩溃!建议使用 scan 代替 keys!

另外,flushall、flushdb 等命令也要禁用,可以通过 Redis 的 rename 机制禁掉命令。

  1. 慎用复杂度 O(N) 的命令

理由:例如 hgetall、smembers、lrange、zrange 等并非不能使用,但是需要明确 N 的值。项目刚上线之初 hash、set 或者 list 存储的成员个数较少,但是随着业务发展成员数量极有可能会膨胀的非常大,如果仍然采用上述命令不加控制,会极大拖累整个 Redis 服务的响应时间,建议有遍历的需求可以使用 hscan、sscan、zscan 代替!

  1. 合理使用批处理命令提高效率

理由:

  1. 原生命令如 mget、mset,非原生命令如 pipeline,但要注意控制一次批量操作的元素个数(例如 500 以内,具体和元素大小有关);
  2. Redis 由于处理效率非常高效,基本上都是微秒级别,超过 1 毫秒就应该算是慢操作,使用批量处理命令核心优化点就是减少网络 IO 开销,特别是对于一些 php 短连接效果尤其明显。但是注意每次操作不易过多,否则会阻塞其它请求命令!

注意原生命令与 pipeline 之间的不同:

  1. 原生是原子操作,pipeline 是非原子操作;
  2. pipeline 可以打包不同的命令,原生做不到;
  1. pipeline 需要客户端和服务端同时支持。

  1. 避免大批量 key 集中过期

理由:集中大批量 key 过期会短时间抢占大量的 CPU 资源,并有可能阻塞主线程响应。key 集中过期常见在大数据计算结果使用了同样的过期命令,建议分批写入设置不同的过期时间!

  1. 不建议过多使用 Redis 事务

理由:Redis 的事务功能较弱(不支持回滚),而且集群版本(自研和官方)要求一次事务操作的 key 必须在一个 slot 上(可以使用 hashtag 功能解决)

  1. Redis 集群版本在使用 Lua 上有特殊要求
  1. 所有 key 都应该由 KEYS 数组来传递,redis.call/pcall 里面调用的 redis 命令,key 的位置必须是 KEYS array,否则直接返回 error "-ERR bad lua script for redis cluster, all the keys that the script uses should be passed using the KEYS array";
  2. 所有的 key 必须在 1 个 slot 上,否则直接返回 error "-ERR eval/evalsha command keys must in same slot"。

  1. 必要情况下才使用 monitor 命令时,注意不要长时间使用

内存优化

  1. Redis 节点内存上限不能超过 20G

理由:

  1. 在 4.0 版本之前的 Redis 主从架构下,master 主节点发生故障,切换到新主节点后,其它从节点挂载到新主需要进行一次全量数据重传,如果 slave 节点提供只读服务,则构建完成前会一直处于阻塞状态,而过大的内存数据会极大延长新集群的构建时长。大容量内存使用建议使用 RedisCluster,通过多分片来降低单节点的内存使用量;
  2. Redis 新版本通过记录同步点位一定程度上缓解了新主切换时的全量复制重传问题,但实际也要依赖业务写入情况和主从复制预留 buffer 大小,按照经验高吞吐情况下大概率仍会发生全量复制重传情况,所以强烈建议单节点尽量控制内存使用上限在 20G 以内。

  1. 合理设计 key 过期时间,满足业务情况下越小越好

理由:内存是昂贵的!根据业务合理设置 key 的过期时间,满足业务需求就好,严禁不设置或者设置过久的过期时间策略!注意 expire 和 expireat 的使用区别!

  1. 不要将所有数据全部都放到 Redis 中

理由:内存是昂贵的!只存储高频访问的数据,严禁将流水日志等只访问一次的数据存入 Redis 中!

  1. 必须设置内存最大值,且必须可用内存不小于10%

理由:

  1. 服务器内存是有限的,不设限的内存使用会造成服务器内存失控;
  2. 保持 Redis 服务有充足的可用内存,虽然数据使用内存达到最大上限后会触发自动清理,但是这种清理有严重的滞后性,在高频写入时已经严重影响新的请求写入了!

集群架构

  1. 禁止私自将线下节点挂载到线上集群

理由:redis 的权限管理较弱,仅仅通过地址和密码即可连接到线上集群,但这种操作会对线上服务的稳定性带来极大隐患,比如高可用的选主切换,给运维人员带来极大的干扰!

  1. 禁止线上业务使用级联复制架构

理由:级联复制架构在网络不稳定的环境下,如果上游复制节点出现问题,会造成下游 slave 节点的数据全量复制重传,对下游的服务请求带来很大的安全隐患。

  1. 读写分离集群架构,Redis 版本必须在 3.2 以上

理由:由于 Redis 过期 Key 的清理采用惰性删除策略,即主节点的 Key 过期后不是立马被清理,而是逐批扫描清理或者被访问时主动清理,且从节点 Key 的清理只能依赖主节点的同步删除,slave 自己是不能主动发起清理的。这种模式下如果 slave 提供读请求,在清理不及时时就可能读到脏数据。3.2 之后的版本解决了这种问题,不再给请求返回数据。

  1. 主从集群架构下,如果需要持久化下建议主库关闭从库开启

理由:

  1. 之前有人认为 Redis 的持久化都是追加写,SAS 的磁盘就可以。但是实际上在 Redis 高并发写入情况下,SAS 盘的吞吐是远远跟不上的,特别在单机部署多套 Redis 服务的情况下,强烈建议使用 SSD。磁盘的刷新如果过慢,会直接阻塞 Redis 主线程写入;
  2. 在主从集群模式下,建议主节点关闭持久化,从节点开启,当然如果数据只是用作临时缓存也可以都关闭持久化,具体取决于你的业务场景对缓存的依赖程度。

参考资料

  1. Redis使用的21条军规(规范)
  2. 阿里云Redis开发规范
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值