当前位置:首页 > 问答 > 正文

Redis集群里MGet真不是盖的,批量取值效率杠杠的,性能提升明显

主要基于日常开发实践中的普遍认知、Redis官方文档关于管道和批量操作的性能建议,以及众多技术社区如Stack Overflow、知乎上关于Redis集群使用MGet的讨论和性能测试分享。)

Redis这个家伙,咱们平时用得不少,都知道它快,单线程模型,内存操作,速度那是没得说,但是当数据量大了,一台机器顶不住了,就得用上Redis集群,这一下,问题就来了,数据被分散到了不同的主节点上,按照一定的规则存着,这时候,你想一次性取多个key的值,也就是用MGet这个命令,就会发现,哎,怎么好像没那么爽快了?甚至有时候还会报错?其实啊,这里头有个大大的误会,很多人觉得在集群里MGet不好使,那是没用对地方,或者被它表面的复杂度吓到了,当你真正理解了它,并且结合一些巧妙的用法,你就会发现,Redis集群里的MGet,真不是盖的,批量取值效率杠杠的,性能提升非常明显。

为啥这么说呢?咱们得先想想不用MGet是啥样子,假如你的业务需要从Redis里取出10个key对应的数据,如果不用MGet,你就得老老实实地发起10次网络请求,每一次请求,你的应用程序都得把命令打包,通过网络发给Redis服务器,服务器处理完了,再把结果通过网络送回来,这来来回回的,大部分时间其实都花在了网络传输上,而不是Redis本身处理命令的时间,尤其是在网络延迟比较高的情况下,比如服务器和应用程序不在同一个机房,那这个延迟的影响就更大了,10次请求,可能就是10倍的网络延迟时间,这谁受得了啊。

那MGet妙在哪里呢?它就是帮你把多个GET命令打包成一个命令,一次性发给Redis服务器,对于Redis服务器来说,它只需要处理一次网络请求的接收,然后连续地在内存里把这几个key的值找出来,再一次性通过网络返回给你的应用程序,这样一来,原本10次的网络往返时间,被压缩成了1次,虽然服务器内部处理10个key的时间比处理1个key要长一点点,但跟网络延迟的巨大开销比起来,这点处理时间的增加简直是九牛一毛,在单机Redis环境下,大家都能直观地感受到MGet带来的性能飞跃。

到了集群环境,情况稍微复杂点,因为key可能分布在不同的节点上,客户端没法直接把一个包含多个key的MGet命令丢给任意一个节点了事,如果客户端傻乎乎地随便找个节点发送一个包含了分布在多个节点上的key的MGet命令,那个节点会发现有些key不属于自己管,就会报错,告诉你这些key不在我这里,这也就是很多人初遇集群MGet时遇到的“坑”,觉得MGet在集群里不可用。

但聪明的Redis客户端驱动(比如Java的Jedis,Python的redis-py等)早就帮我们想到了这一点,它们内部实现了非常关键的一步:键路由分组,当你发起一个集群下的MGet命令,传入一堆key时,客户端驱动会先悄悄地干这么几件事:

  1. 计算每个key应该落在哪个槽(slot):根据CRC16算法算出每个key对应的哈希槽。
  2. 根据槽找到对应的主节点:客户端本地维护着一份集群的槽位映射表(cluster slots),知道哪个槽由哪个主节点负责。
  3. 按节点对key进行分组:把属于同一个主节点的key归拢到一组。

做完这三步,神奇的事情就发生了,原本一个混杂了多个节点key的大列表,被分成了几个小组,每个小组里的key都归属于同一个Redis主节点,客户端驱动会并行地(或高效串行地)向每一个涉及到的目标节点发起一个MGet请求,10个key,经过分组后发现,有7个在节点A,3个在节点B,那么客户端就会同时向节点A发送一个包含7个key的MGet,向节点B发送一个包含3个key的MGet。

你看,这样一来,本质上还是利用了MGet批量操作的巨大优势,对于节点A,它一次性处理了7个key,只发生了一次网络往返;对于节点B,一次性处理了3个key,也是一次网络往返,整个操作的总网络往返次数,从不用MGet时的10次,降低到了现在的2次(取决于key分布的节点数),如果这10个key幸运地都集中在同一个节点,那就更爽了,只需要1次网络往返,这效率的提升,难道不是杠杠的吗?

这里的关键在于客户端的智能,它帮你隐藏了集群分布的复杂性,让你用起来的感觉就像是操作一个单一的Redis实例一样方便,同时又能享受到批量操作带来的性能红利,为了获得最佳性能,我们在设计key的时候,如果有一批需要同时获取的数据,尽量使用相同的标签或者通过哈希标签(hash tag)确保它们落在同一个槽、同一个节点上,这样就能实现极致的批量操作,一次MGet搞定,连并行请求都省了,效率达到顶峰。

别再误会Redis集群下的MGet了,它不是不能用,而是有大智慧,当你通过一个优质的客户端驱动去使用它时,它依然是那个能显著提升批量数据读取性能的利器,在分布式环境下依然发挥着“效率倍增器”的作用,尤其是在需要频繁读取大量关联数据的场景下,比如一次性获取用户的多项个人信息、一批商品的详情等,正确使用集群MGet带来的性能提升是非常可观的,绝对对得起“效率杠杠的”这个评价。

Redis集群里MGet真不是盖的,批量取值效率杠杠的,性能提升明显