这几天在做优化,把应用与rdb超时时间从200ms下降到了50ms。结果rdb在那个时候恰巧出发了aof持久化,整个持久化的过程持续了1.7s,导致线上故障。
rdb持久化的过程是什么?这里可以看redis的官方文档:https://redis.com.cn/redis-persistence.html 和 https://redisbook.readthedocs.io/en/latest/internal/aof.html 。这里可以看出aof是持久化效果最好的方法,但是它依赖文件的大小,aof文件越大,耗时越久。如果关闭了aof,那么rdb就成了一个memcache,断电了而且备库也断电了,那数据就没了。
一般来说1.7s的aof耗时不算是很久,而且每个实例的aof操作其实也挺频繁的,平均20分钟不到就一次,但是aof期间主进程是不工作的,导致这个redis集群执行aof的实例在这个阶段不能正常接受服务请求,但是我们的代码里有两个配置放大了这个情况,进而出现了故障。
第一:我们的服务有重试机制,即如果rdb超时,就会重试3次。后来我们决定这里的重试取消掉,交易链路么,重试非常容易埋雷。
第二:我们发现这1.7s时间内写请求飙升,经分析是由于写请求是sku维度的(exhset),读请求是item维度(exhmget),按照平均sku数量,重试的写请求相比读请求有10+的放大系数。再叠加之前的重试3次。导致雪崩。
通过这个故障,我们通过复盘也发现了我们一些当前链路不合理的地方,比如“这个redis品仓关系专用的,不应该直接影响下单成功率,考虑后续解耦策略”。
其次是阿里云在选择redis的时候看到的qps是最基础的qps,比如我这个集群,说是能扛住384万qps,但是这个384万是压测512字节的key和value得到的。而在实际的业务开发场景里,key和value的大小是远远大于512字节的,所以实际qps是不够的。这里需要SRE同学帮忙来拿线上比较真实的key-value去压测一下真实的qps水平。