说明:个人原创,本人在一线互联网大厂维护着几千套集群,关于redis使用的一些坑进行了经验总结,希望能给大家带来一些帮助
适用场景:并发量大、访问量大的业务
规范:介绍军规内容
解读:讲解军规设置原因,解读比军规内容更重要
写在前面的话:
总是在灾难发生后,才想起容灾的重要性;
总是在吃过亏后,才记得曾经有人提醒过。
一、基础规范【5条】
1. 必须配置访问密码
解读:裸奔的Redis除了方便被外部盗取数据外,内部管理上也极易出现误操作风险,如误连造成数据被覆盖、丢失!
2.必须以非root用户启动
解读:Redis的设计过于灵活,这直接让攻击者可以远程通过root运行的redis服务获取到操作系统root权限!
3.禁止将Redis当做持久化存储使用
解读:Redis虽然支持AOF、RDB持久化模式,但是并不会记录每条操作的详细时间戳(对比MySQL的binlog会详细记录执行时间),出现误操作时无法进行精确回滚!
4.禁止不同业务混合部署使用同一套Redis
解读:(1)Redis为单线程模型,不同业务的数据存储在一起,除了管理上混乱,单线程模型下只要有一个请求命令变慢,就会影响所有存储在同Redis中的所有请求!
(2)虽然redis支持多个db,但是请求并不会被隔离,比如请求0号库的一个慢操作,也一样样会阻塞其它1、2、3、4库的连接和请求!
5.选择相对较新的版本,强烈建议5.0以上版本
解读:除了5.0版本引入了更多新特性及bug修复外,5.0对Redis的内存碎片管理效率带来了极大的提升,而碎片绝对是Redis的一大性能杀手,但早期的2.x、3.x、4.x版本都没有很好的解决这一问题!
二、键值设计【4条】
1.建议以业务名为前缀,以冒号分割来构造一定规则的key名称
解读:好的Key名称可以提高可读性和可管理性
2.Key名称禁止包含特殊字符,比如空格、换行、单双引号及其他转义字符等
解读:带有特殊符号的Key,在读取或管理时会带来想不到的各种异常和不便
3.控制key名称长度,建议64字符以内,避免Key过多带来较大的内存开销
解读:内存是昂贵的,几千万或者上亿个的Key时,额外的内存开销不容忽视
4.控制Value大小,如果超过512字节必须进行压缩存储,最大不能超过1K
解读:(1)Redis的所有数据都存储在内存中!内存中!内存中!!【不管Redis开不开启持久化,所有数据都是存储在内存中】,而内存的成本是非常高的。
(2)除了成本外,这种大容量的数据存储在Redis中,在访问的QPS稍微高一些时,网卡的压力会非常大,大概率会发生网卡流量打满情况【瞬时吞吐量=QPS*单个请求对象大小】。这种情况建议走独立的图片存储服务、应用程序缓存或CDN等方式,对于过长的字符串【512个字节以上】建议进行序列化或压缩后再存储!
(3)较大的Value,写入速度也会受影响,整体影响写入的吞吐量
三、操作命令【4条】
1.禁止使用keys命令进行正则匹配
解读:Keys的正则匹配是阻塞式、全量扫描过滤的,对于单线程服务的Redis来说是致命的,几十万个Key的匹配查询在高并发访问下就有可能将Redis打崩溃!建议使用scan代替keys!
2.慎用复杂度O(N)的命令
解读:例如hgetall、smembers、lrange、zrange等并非不能使用,但是需要明确N的值。项目刚上线之初hash、set或者list存储的成员个数较少,但是随着业务发展成员数量极有可能会膨胀的非常大,如果仍然采用上述命令不加控制,会极大拖累整个Redis服务的响应时间,建议有遍历的需求可以使用hscan、sscan、zscan代替!
3.合理使用批处理命令提高效率
解读:(1)原生命令如mget、mset,非原生命令如pipeline,但要注意控制一次批量操作的元素个数(例如500以内,具体和元素大小有关)。
(2)Redis由于处理效率非常高效,基本上都是微秒级别,超过1毫秒就应该算是慢操作,使用批量处理命令核心优化点就是减少网络IO开销,特别是对于一些php短连接效果尤其明显。但是注意每次操作不易过多,否则会阻塞其它请求命令!
4.避免大批量Key集中过期
解读:集中大批量Key过期会短时间抢占大量的CPU资源,并有可能阻塞主线程响应。Key集中过期常见在大数据计算结果使用了同样的过期命令,建议分批写入设置不同的过期时间!
四、内存优化【4条】
1.Redis节点内存上限不能超过20G
解读:(1)4.0版本之前的Redis主从架构下master主节点发生故障,切换到新主节点后,其它从节点挂载到新主需要进行一次全量数据重传,如果Slave节点提供只读服务,则构建完成前会一直处于阻塞状态,而过大的内存数据会极大延长新集群的构建时长。大容量内存使用建议使用RedisCluster,通过多分片来降低单节点的内存使用量。
(2)Redis新版本通过记录同步点位一定程度上缓解了新主切换时的全量复制重传问题,但实际也要依赖业务写入情况和主从复制预留buffer大小,按照经验高吞吐情况下大概率仍会发生全量复制重传情况,所以强烈建议单节点尽量控制内存使用上限在20G以内。
2.合理设计Key过期时间,满足业务情况下越小越好
解读:内存是昂贵的!根据业务合理设置Key的过期时间,满足业务需求就好,严禁不设置或者设置过久的过期时间策略!注意expire和expireat使用区别!
3.不要将所有数据全部都放到Redis中
解读:内存是昂贵的!只存储高频访问的数据,严禁将流水日志等只访问一次的数据存入Redis中!
4.必须设置内存最大值,且必须可用内存不小于10%
解读:(1)服务器内存是有限的,不设限的内存使用会造成服务器内存失控。
(2)保持Redis服务有充足的可用内存,虽然数据使用内存达到最大上限后会触发自动清理,但是这种清理有严重的滞后性,在高频写入时已经严重影响新的请求写入了!
五、集群架构【4条】
1.禁止私自将线下节点挂载到线上集群
解读:redis的权限管理较弱,仅仅通过地址和密码即可连接到线上集群,但这种操作会对线上服务的稳定性带来极大隐患,比如高可用的选主切换,给运维人员带来极大的干扰!
2.禁止线上业务使用级联复制架构
解读:级联复制架构在网络不稳定的环境下,如果上游复制节点出现问题,会造成下游Slave节点的数据全量复制重传,对下游的服务请求带来很大的安全隐患。
3.读写分离集群架构,Redis版本必须在3.2以上
解读:由于Redis过期Key的清理采用惰性删除策略,即主节点的Key过期后不是立马被清理,而是逐批扫描清理或者被访问时主动清理,且从节点Key的清理只能依赖主节点的同步删除,Slave自己是不能主动发起清理的。这种模式下如果Slave提供读请求,在清理不及时时就可能读到脏数据。3.2之后的版本解决了这种问题,不再给请求返回数据。
4.主从集群架构下,如果需要持久化下建议主库关闭从库开启
解读:(1)之前有人认为Redis的持久化都是追加写,SAS的磁盘就可以。但是实际上在Redis高并发写入情况下,SAS盘的吞吐是远远跟不上的,特别在单机部署多套Redis服务的情况下,强烈建议使用SSD。磁盘的刷新如果过慢,会直接阻塞Redis主线程写入。
(2)在主从集群模式下,建议主节点关闭持久化,从节点开启,当然如果数据只是用作临时缓存也可以都关闭持久化,具体取决于你的业务场景对缓存的依赖程度。
最后说明:
上述21条军规是在互联网大厂经历大规模Redis运维的经验总结,希望能给大家带来一些启发和帮助!
今日微语:
成长是一场和自身的赛事,不必担忧他人会做得比您好,你只需要每日都做得比前一天好就行了。
看完本文有收获?请转发分享给更多人
关注「数据库架构师」,提升数据库技能