深入理解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延迟队列和分布式延迟队列的简答实现
May 13 Redis
redis实现共同好友的思路详解
May 26 Redis
Redis Cluster 字段模糊匹配及删除
May 27 Redis
浅谈Redis主从复制以及主从复制原理
May 29 Redis
深入理解redis中multi与pipeline
Jun 02 Redis
你真的了解redis为什么要提供pipeline功能
Jun 22 Redis
Redis主从配置和底层实现原理解析(实战记录)
Jun 30 Redis
Redis高可用集群redis-cluster详解
Mar 20 Redis
Redis实战高并发之扣减库存项目
Apr 14 Redis
Redis实现一个账号只能登录一个设备
Apr 19 Redis
Redis唯一ID生成器的实现
Jul 07 Redis
redis protocol通信协议及使用详解
Jul 15 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
PHP 错误之引号中使用变量
2009/05/04 PHP
PHP 简易输出CSV表格文件的方法详解
2013/06/20 PHP
PHP的preg_match匹配字符串长度问题解决方法
2014/05/03 PHP
Joomla使用Apache重写模式的方法
2016/05/04 PHP
Laravel下生成验证码的类
2017/11/15 PHP
ext 同步和异步示例代码
2009/09/18 Javascript
javascript在myeclipse中报错的解决方法
2013/10/29 Javascript
jQuery基于ajax()使用serialize()提交form数据的方法
2015/12/08 Javascript
js实现的奥运倒计时时钟效果代码
2015/12/09 Javascript
JavaScript缓冲运动实现方法(2则示例)
2016/01/08 Javascript
AngularJS模板加载用法详解
2016/11/04 Javascript
基于jQuery实现简单人工智能聊天室
2017/02/10 Javascript
sublime text配置node.js调试(图文教程)
2017/11/23 Javascript
使用D3.js创建物流地图的示例代码
2018/01/27 Javascript
详解Vue中的MVVM原理和实现方法
2020/07/15 Javascript
详解ES6中class的实现原理
2020/10/03 Javascript
python映射列表实例分析
2015/01/26 Python
python BeautifulSoup设置页面编码的方法
2015/04/03 Python
Python中文竖排显示的方法
2015/07/28 Python
Python之str操作方法(详解)
2017/06/19 Python
用Python写一个模拟qq聊天小程序的代码实例
2019/03/06 Python
使用pyqt 实现重复打开多个相同界面
2019/12/13 Python
Python调用scp向服务器上传文件示例
2019/12/22 Python
python 实现字符串下标的输出功能
2020/02/13 Python
查看keras的默认backend实现方式
2020/06/19 Python
CSS实现限制字数功能当对象内文本溢出时显示省略标记
2014/08/20 HTML / CSS
草莓网化妆品加拿大网站:Strawberrynet Canada
2016/09/20 全球购物
ABOUT YOU匈牙利:500个最受欢迎的时尚品牌
2019/07/19 全球购物
美国在线面料商店:Fashion Fabrics Club
2020/01/31 全球购物
当文件系统受到破坏时,如何检查和修复系统?
2012/03/09 面试题
面包店的创业计划书范文
2014/01/16 职场文书
市场专员岗位职责
2014/02/14 职场文书
百日安全活动总结
2014/05/04 职场文书
2015年社区重阳节活动总结
2015/07/30 职场文书
关于ObjectUtils.isEmpty() 和 null 的区别
2022/02/28 Java/Android
Python加密与解密模块hashlib与hmac
2022/06/05 Python