Redis批量操作详解及性能分析

在之前的文章中,我们对redis批量处理指令mget进行了压测并分析了性能瓶颈,显然通过mget批量执行指令可以节约网络连接和数据传输开销,在高并发场景下可以节约大量系统资源。本文中,我们更进一步,比较一下redis提供的几种批量执行指令的性能。

1.为什么需要批量执行redis指令

众所周知,Redis协议采取的是客户端-服务器方式,即在一次round trip中,客户端发送一条指令,服务端解析指令并执行,然后向客户端返回结果。这是一种典型的tcp交互方式。

粗略的分,客户端发起一次Redis请求主要有如下开销:

  • socket IO导致的上下文切换开销

    • 熟悉OS/Linux的童鞋都知道,一次redis请求在客户端和服务端分别至少会存在一次read()和一次write(),作为系统调用,read/write的成本高于普通的函数调用,因此,在单个命令重复调用场景下,大量的read/write系统调用会产生明显的系统开销。
  • 指令执行开销

    • Redis采用C实现,使用了轻量级的hash表、skipList跳表等数据结构实现了高效的缓存。因此,单条执行大多数指令的成本非常低。因此,相对而言,IO的开销显得更加无法忽略。
  • (高并发下)资源竞争和系统调度调度开销

    • 一般来说,这一开销在客户端的影响更为明显,在高压力下,如果采用循环(loop)方式调用多次指令来完成某个服务请求,那么在高并发下,多个请求会在多个线程中同时竞争redis连接资源多次,导致连接池压力增加,线程上下文切换更加频发,最终会导致请求RTT(round-trip time)急剧恶化。如果每个请求只抢占一次redis连接并通过批量执行的方式一次处理多个请求,则单次请求的RTT会有显著提升。

    • 在服务端,因为我们通常将redis绑定到CPU(不管是通过物理机还是通过docker),因此一般而言不存在系统调度/资源竞争的开销。但是由于redis对qps敏感,如果因为客户端使用不合理而造成qps放大效应,则redis可能更早触及性能瓶颈而导致系统响应严重下降。

笔者曾经在一次性能调优中发现,每次服务请求访问redis次数高达数十次,使得redis请求次数达到服务qps的数十倍,触发了redis服务器的极限(大概5~10万qps)而导致服务性能低下,多个请求对redis连接池进行了激烈竞争,并且由于redis响应速度的下降导致大量线程在获取连接处阻塞并频繁进行线程切换。在改进实现采用了批量指令处理后,服务性能瞬间达到了数十倍的提升。

因此,如果每次服务掉用需要触发多次redis请求,合理地适用批量执行技术,可以使系统运行更加有效,数据吞吐得到明显提升。

2.redis批量指令介绍

Redis主要提供了以下几种批量操作方式:

  • 批量get/set(multi get/set)
  • 管道(pipelining)
  • 事务(transaction)
  • 基于事务的管道(transaction in pipelining)

2.1 批量命令

批量命令即redis对应的命令:

严格来说上述命令不属于批量操作,而是在一个指令中处理多个key。

优势:

  • 性能优异,因为是单条指令操作,因此性能略优于其他批量操作指令。

缺点:

  • 批量命令不保证原子性,存在部分成功部分失败的情况,需要应用程序解析返回的结果并做相应处理。
  • 批量命令在key数目巨大时存在RRT与key数目成比例放大的性能衰减,会导致单实例响应性能(RRT)严重下降,更多分析请参考之前的文章。

集群行为

  • 客户端分片场景下,Jedis不支持客户端mget拆分,需要在业务代码中根据分片规
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值