Redis横向扩容带来的性能衰退

问题背景

某应用每次查询需要通过mget从Redis批量获取大批key的数据,某次Redis集群改造,将该应用读取的Redis集群由原来的4个分片扩展为20个分片。改造完成后应用读取Redis耗时出现大幅上升

问题原因

目前Redis集群通过特定的hash策略将key映射到不同的分片上,且hash策略通常与业务无关。这就造成了业务上一次批量获取的key的数据,可能分布在多个分片上。

客户端在使用mget批量获取数据时,需要多次网络IO从不同的分片上去获取数据。而目前公司框架部门封装的Redis客户端的实现为串行IO,也就是说会串行的从多个实例上读取数据

而随着集群分片数量的增多,数据分散在更多的分片上,导致客户端mget批量获取数据时需要更多的网络IO,最终导致耗时上升。同时网络连接数量上升也会对Redis实例的性能产生负面影响。

解决方案

  • 串行IO 改 并行IO/异步IO
  • 从业务上,通过hash-tag将一次查询的key都映射到同一分片上

第一种方案利用并行,耗时取决于最慢的一次IO,但同时并行会带来额外的开销和编码复杂度。

第二种方案性能最高,只需要一次IO,但是编码方案与业务强耦合,带来很高的维护成本,且可能导致数据倾斜。而且有时候业务上的不确定性,根本无法实现。

结论

当单个实例容量达到上限时,多实例横向扩容确实在大多数情况下能提升性能,但是也需要考虑可能带来的性能衰退的问题

参考

Facebook’s Memcached Multiget Hole: More Machines != More Capacity

缓存系列文章–无底洞问题