深入理解redis中multi与pipeline


Posted in Redis onJune 02, 2021

背景

由于对redis缓存中数据有批量操作,例如预热缓存数据,或者在列表页批量去获取缓存数据,在使用了multi批量提交事务后,发现redis压力高居不下,而使用了pipeline之后压力回落了平常,也因为这个案例,特在此写个分析与笔记。

multi

简介

标记一个事务块的开始。
事务块内的多条命令会按照先后顺序被放进一个队列当中,最后由 EXEC 命令原子性(atomic)地执行。

实现原理

我用php扩展调起redis服务,执行,代码如下:

$redis = new redis();
$redis->connect('127.0.0.1',6379);
$handle = $redis->multi();
$handle->incr('a');
$handle->incr('b');
$handle->exec();

为了查看这期间具体的连接过程,用wireshark监听回环地址端口6379,抓包请求如下图所示:

深入理解redis中multi与pipeline

redis客户端与服务端建立连接后,multi标记事务开始,之后每次执行,服务端返回queued队列标志。查看redis源码src/multi.c文件:

void queueMultiCommand(client *c) {
    multiCmd *mc;
    int j;

    c->mstate.commands = zrealloc(c->mstate.commands,
            sizeof(multiCmd)*(c->mstate.count+1));
    mc = c->mstate.commands+c->mstate.count;
    mc->cmd = c->cmd;
    mc->argc = c->argc;
    mc->argv = zmalloc(sizeof(robj*)*c->argc);
    memcpy(mc->argv,c->argv,sizeof(robj*)*c->argc);
    for (j = 0; j < c->argc; j++)
        incrRefCount(mc->argv[j]);
    c->mstate.count++;
}

在上述源码中可以看到redis服务端每次会把事务块中的命令保存到内存中,上述简介已经解释过最后通过exec命令执行,再看下面示例图的返回结果可以了解到redis服务端一次性返回所有命令执行返回结果。

深入理解redis中multi与pipeline

pipeline

简介

客户端将执行的命令写入到缓冲中,最后由exec命令一次性发送给redis执行返回。

实现原理

同样,用相关代码调用redis抓包;

$redis = new redis();
$redis->connect('127.0.0.1',6379);
$handle = $redis->pipeline();
$handle->incr('a');
$handle->incr('b');
$handle->exec();

继续用wireshark抓包,如下图所示

深入理解redis中multi与pipeline

pipeline 客户端请求包示例图

深入理解redis中multi与pipeline

这上面的图片简要分析一下,pipeline管道操作是需要客户端与服务端的支持,客户端将命令写入缓冲,最后再通过exec命令发送给服务端,服务端通过命令拆分,逐个执行返回结果。

两者的区别

由上面的请求也可以看出了两者最明显的区别是客户端发送请求的方式不一样,具体相关区别如下:

  • pipeline选择客户端缓冲,multi选择服务端缓冲;
  • 请求次数的不一致,multi需要每个命令都发送一次给服务端,pipeline最后一次性发送给服务端,请求次数相对于multi减少
  • multi/exec可以保证原子性,而pipeline不保证原子性

到此这篇关于深入理解redis中multi与pipeline 的文章就介绍到这了,更多相关redis multi与pipeline 内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Redis 相关文章推荐
redis连接被拒绝的解决方案
Apr 12 Redis
了解Redis常见应用场景
Jun 23 Redis
redis cluster支持pipeline的实现思路
Jun 23 Redis
Redis 彻底禁用RDB持久化操作
Jul 09 Redis
浅谈Redis位图(Bitmap)及Redis二进制中的问题
Jul 15 Redis
缓存替换策略及应用(以Redis、InnoDB为例)
Jul 25 Redis
解决linux下redis数据库overcommit_memory问题
Feb 24 Redis
Redis 中使用 list,streams,pub/sub 几种方式实现消息队列的问题
Mar 16 Redis
redis复制有可能碰到的问题汇总
Apr 03 Redis
Redis 限流器
May 15 Redis
解决 redis 无法远程连接
May 15 Redis
一文教你快速生成MySQL数据库关系图
Jun 28 Redis
SpringBoot 集成Redis 过程
Jun 02 #Redis
详解Redis基本命令与使用场景
Django使用redis配置缓存的方法
Jun 01 #Redis
详解Redis集群搭建的三种方式
May 31 #Redis
浅谈Redis主从复制以及主从复制原理
5分钟教你docker安装启动redis全教程(全新方式)
May 29 #Redis
详解缓存穿透击穿雪崩解决方案
You might like
对squid中refresh_pattern的一些理解和建议
2009/04/17 PHP
PHP动态创建Web站点的方法
2011/08/14 PHP
zend optimizer在wamp的基础上安装图文教程
2013/10/26 PHP
将酷狗krc歌词解析并转换为lrc歌词php源码
2014/06/20 PHP
destoon数据库表说明汇总
2014/07/15 PHP
PHP保存带BOM文件的方法
2015/02/12 PHP
Laravel 5框架学习之Blade 简介
2015/04/08 PHP
PHP判断字符串长度的两种方法很实用
2015/09/22 PHP
Ubuntu中支持PHP5与PHP7双版本的简单实现
2018/08/19 PHP
Laravel框架控制器的request与response用法示例
2019/09/30 PHP
在thinkphp5.0路径中实现去除index.php的方式
2019/10/16 PHP
utf-8编码引起js输出中文乱码的解决办法
2010/06/23 Javascript
一些实用的jQuery代码片段收集
2011/07/12 Javascript
详解js中class的多种函数封装方法
2016/01/03 Javascript
判断输入的字符串是否是日期格式的简单方法
2016/07/11 Javascript
详解jQuery中的DOM操作
2016/12/23 Javascript
详解用vue编写弹出框组件
2017/07/04 Javascript
JavaScript分步实现一个出生日期的正则表达式
2018/03/22 Javascript
JavaScript中set与get方法用法示例
2018/08/15 Javascript
node app 打包工具pkg的具体使用
2019/01/17 Javascript
使用 webpack 插件自动生成 vue 路由文件的方法
2019/08/20 Javascript
解决antd 表单设置默认值initialValue后验证失效的问题
2020/11/02 Javascript
python3 与python2 异常处理的区别与联系
2016/06/19 Python
基于Linux系统中python matplotlib画图的中文显示问题的解决方法
2017/06/15 Python
python实现识别手写数字 python图像识别算法
2020/03/23 Python
Python科学计算包numpy用法实例详解
2018/02/08 Python
Python3中内置类型bytes和str用法及byte和string之间各种编码转换 问题
2018/09/27 Python
python直接获取API传递回来的参数方法
2018/12/17 Python
python 在threading中如何处理主进程和子线程的关系
2020/04/25 Python
意大利奢华内衣制造商:Cosabella
2017/08/29 全球购物
领导视察欢迎词
2014/01/15 职场文书
园艺师求职信
2014/04/27 职场文书
教师继续教育反思周记
2015/06/25 职场文书
《失物招领》教学反思
2016/02/20 职场文书
python opencv将多个图放在一个窗口的实例详解
2022/02/28 Python
Python进程池与进程锁之语法学习
2022/04/11 Python