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

Redis批量查数据那点事儿,性能到底能不能炸裂体验一下

Redis批量查数据那点事儿,性能到底能不能炸裂体验一下

(引用来源:某技术社区资深用户“码农老张”的分享帖)

今天咱们就来唠唠Redis批量查数据这个事儿,很多人用Redis,就是图它快,单条命令嗖嗖的,但要是遇到一种情况,比如你需要从Redis里捞出成百上千个key对应的数据,你会咋办?新手可能会想,这还不简单,写个循环,一个一个去取呗,但老司机这时候就会露出神秘的微笑,然后告诉你:小伙子,你这样搞,性能可就要炸了——不过是向不好的方向“爆炸”。

(引用来源:Redis官方文档关于Pipelining的介绍)

为啥这么说呢?咱们打个比方,你单条命令去查数据,就像是你去小卖部买瓶水,你走到小卖部,说“老板,来瓶可乐”,老板递给你,你付钱,然后回来,一次往返,现在你要买100瓶水送给队友,如果你还是每次只买一瓶,来回跑100趟,先不说你累不累,小卖部老板看你来回晃悠,可能都想打人了,这来回跑的路程,在网络世界里就是“网络往返延迟”(RTT),每次请求,即使数据量再小,这个来回的时间成本是省不掉的,如果服务器在北京,你在上海,这个延迟可能就有几十毫秒,100次请求,好几秒就没了,这还能叫“高性能缓存”吗?

(引用来源:某大厂内部性能优化案例总结)

那老司机说的“炸裂”的正向性能,靠的是啥?主要就是两板斧:Pipeline(管道)批量命令

先说说Pipeline,这玩意儿还是用买水打比方,这次你学聪明了,拿张纸,写上“我要100瓶可乐”,一次性地交给老板,老板看着单子,一次性把100瓶水搬给你,你一次性付钱,整个过程只跑了一趟,Pipeline就是这个道理,它把多个你要执行的命令(比如100个GET命令)打包,一次性发送给Redis服务器,服务器一口气全部执行完,再把结果打包一次性返回给你,这样,无论你要操作多少个key,网络延迟只有一次,这个性能提升是巨大的,尤其是在需要大量操作的场景下,速度提升几十倍甚至上百倍都很常见,这体验,确实称得上“炸裂”。

(引用来源:Redis命令参考手册)

再说说批量命令,Redis自己也很贴心,它提供了一些原生的批量操作命令,最典型的就是MGETMSET,比如你要同时获取user:1, user:2, user:3这三个用户的信息,你不用发三次GET命令,只需要发一条命令:MGET user:1 user:2 user:3,Redis直接返回一个包含三个结果的列表给你,这比Pipeline还要干脆,因为对于Redis服务器来说,处理一条MGET命令的内部开销,通常比处理Pipeline里打包的多条GET命令要小一点,这就像是小卖部直接推出了“整箱购买”服务,你直接说要一箱可乐,老板搬起来也方便,效率最高。

(引用来源:某云数据库厂商的技术博客)

那问题来了,Pipeline和MGET该怎么选?这里头有点讲究,MGET虽好,但它有个限制:它只能用于同一种操作,而且key的数量如果超级多,比如一次要查10万个key,这条命令本身可能会“卡住”Redis一会儿(因为Redis是单线程的,要处理完你这10万个请求才能喘口气),可能会影响到其他命令的执行,而Pipeline则更灵活,你可以在一个管道里塞入GET、SET、HSET等各种不同类型的命令,混着来,你可以自己控制每次Pipeline包的大小,比如每1000个命令打包发送一次,既减少了网络往返次数,又避免了一个超大请求阻塞服务器太久。

一般的原则是:如果都是同类型的简单操作(比如全是GET),并且key的数量不是特别离谱(比如几千以内),用MGET最简单直接,如果操作类型复杂,或者key的数量巨大,或者需要同时做读写操作,那用Pipeline是更优的选择。

(引用来源:上述“码农老张”分享帖下的讨论)

最后还得提个醒儿,“批量”虽好,但不能无脑用,你不能因为追求批量,就把所有无关的数据都塞到一个请求里,设计好你的key,让一次批量查询的数据确实是逻辑上相关、同时需要的数据,这才是最优解,查询一个用户和他的所有好友信息,这很合理;但把今天所有登录的用户和最新的商品列表混在一起查,那就有点莫名其妙了。

Redis批量查数据,用对了方法,性能体验绝对是“炸裂”级的提升,从慢如蜗牛的循环请求变成秒级响应的批量操作,核心就是避开频繁的网络往返,利用好Pipeline和MGET这些工具,下次当你需要从Redis里捞一大批数据的时候,别再for循环了,试试批量操作,你会回来感谢我的。

Redis批量查数据那点事儿,性能到底能不能炸裂体验一下