本文主要介绍使用hiredis接口(Synchronous API)编写redis流水线(pipelining)客户端的方法。

1. 流水线(pipelining)介绍

流水线(pipelining)允许redis客户端一次性向redis服务器发送多个命令,Redis服务器在接收到这些命令后,按顺序处理这些命令,然后将(这些命令的)处理结果一次性返回给redis客户端。

通过使用流水线,可以减少redis客户端与redis服务器之间的网络通信次数,以此提升redis客户端在发送多个命令时的性能。

为了解释hiredis如何在阻塞连接中支持流水线,我们通过分析redisCommand函数的执行步骤,了解hiredis流水线的内部原理。

当redisCommand函数(或其同族函数)被调用时,hiredis首先根据redis协议,将需要执行的命令进行格式化,然后,将格式化后的命令放入到redis连接的output buffer中(这个output buffer是动态的,所以它可以容纳任何数量的命令)。当命令被放入output buffer后,此时redisGetReply被调用了,这个函数会进行下面两种操作:

1. 如果input buffer不为空:则从input buffer中解析一条来自redis服务器的相应消息,并返回该消息;

2. 如果input buffer为空:则将output buffer中的全部内容写入socket中,然后等待socket中redis服务器返回的响应消息,读取并解析该消息。

函数redisGetReply作为hiredis API,可以在socket中有(redis服务器的)响应消息时使用。而对于流水线命令来说,只需要把想要执行的命令放入到output buffer中即可,通常我们使用如下函数(或其同族函数)来实现此目的:

void redisAppendCommand(redisContext *c, const char *format, ...);

上面的redisAppendCommand函数与redisCommand函数的区别在于,redisAppendCommand函数不返回redis服务器的响应消息(实际上它只将命令放入到output buffer中),而redisCommand函数实际上包括了“redisAppendCommand函数”和“redisGetReply函数”两个步骤,所以redisCommand函数是阻塞的(使用了阻塞的redisContext对象),每次调用redisCommand函数时,都要等待redis服务端的返回结果,然后才能继续执行程序后面的逻辑。

redisCommand函数的使用示例如下:

redisReply *reply;reply = redisCommand(conn, "SET %s %s", "foo", "bar");
freeReplyObject(reply);reply = redisCommand(conn, "GET %s", "foo");
printf("%s\n", reply->str);
freeReplyObject(reply);

如果我们需要向redis服务端发送多条命令,如果使用redisCommand函数来发送,那么每次发送后都需要等待返回结果后才能继续下一次发送,这很显然会影响redis客户端的处理性能。

因此,hiredis提供了redisAppendCommand函数,来实现流水线命令发送方案:当我们需要向redis服务端发送多条命令时,可以先调用若干次redisAppendCommand函数,之后,再调用redisGetReply函数来接收(并解析)redis服务器返回的响应消息。

redisAppendCommand函数实现流水线命令方案的示例如下:

redisReply *reply;redisAppendCommand(context,"SET foo bar");
redisAppendCommand(context,"GET foo");redisGetReply(context,&reply); // SET命令的返回
freeReplyObject(reply);
redisGetReply(context,&reply); // GET命令的返回
freeReplyObject(reply);

注意:redisAppendCommand函数的调用次数必须与redisGetReply函数的调用次数一致,否则会出现获取到的redis服务端返回的处理结果跟预期不一致的情况。示例如下:

// 测试redisGetReply与redisAppendCommand 调用次数不一致的情况
redisAppendCommand(conn, "get foo");reply = redisCommand(conn, "set fooo barr");
// 此处本想获取set fooo barr的返回信息,却获取了get foo的返回信息
printf("set info: %s\n", reply->str);

上述代码的printf函数打印出来的返回值是“get foo”命令的返回值,因为调用redisAppendCommand函数后,没有与之对应的redisGetReply函数函数调用,后面调用“redisCommand(conn, "set fooo barr");”时,该函数的子步骤redisGetReply函数会获取input buffer中第一个返回值,即“redisAppendCommand(conn, "get foo");”的返回值。

2. 流水线客户端示例

2.1 示例代码

redis流水线客户端的示例代码如下:

#include <iostream>
#include "hiredis/hiredis.h"using namespace std;int main()
{// 建立redis连接redisContext *c = redisConnect("192.168.213.128", 6379);if ((c == NULL) || (c->err)){if (c){cout << "Error: " << c->errstr << endl;// 释放redis连接redisFree(c);return -1;}else{cout << "Can't allocate redis context." << endl;return -1;}}else{cout << "Connected to Redis." << endl;}redisReply *reply;// 发送添加数据命令、查询数据命令redisAppendCommand(c, "SET foo bar");redisAppendCommand(c, "GET foo");// 获取添加数据命令的返回结果redisGetReply(c, (void**)&reply);cout << "SET reply is: " << reply->str << endl;freeReplyObject(reply);// 获取查询数据命令的返回结果redisGetReply(c, (void**)&reply);cout << "GET reply is: " << reply->str << endl;freeReplyObject(reply);// 释放redis连接redisFree(c);return 0;
}

2.2 编译redis流水线客户端

执行下面的命令编译上述代码,生成redis客户端:

g++ -o hiredis_syncAPI_pipelining hiredis_syncAPI_pipelining.cpp -lhiredis

2.3 测试redis流水线客户端

2.3.1 启动redis服务器

我们在主机(IP地址为192.168.213.133)上打开redis服务器,该redis服务器监听对于192.168.213.133的连接,如下:

[root@node1 /opt/liitdar/hiredis]# redis-server /etc/redis.conf

查看redis-server是否在监听192.168.213.133:

[root@node1 /opt/liitdar/hiredis_for_demo]# netstat -anpot |grep 192.168.213.128
tcp        0      0 192.168.213.128:6379    0.0.0.0:*               LISTEN      11606/redis-server   off (0.00/0/0)

上面的结果显示redis-server已经在监听192.168.213.133地址了。

2.3.2 启动redis流水线客户端

在另外一台主机(IP地址为192.168.213.131)上运行前面编译生成的redis流水线客户端“hiredis_syncAPI_pipelining”,如下:

./hiredis_syncAPI_pipelining

2.3.3 观察测试结果

正常情况下,我们编写的redis流水线客户端能够连接到redis服务器,并执行指定的redis流水线命令,如下:

如果运行redis流水线客户端的终端中出现上述信息,说明我们的编写的redis流水线客户端正常运行了。

使用hiredis接口(Synchronous API)编写redis流水线客户端相关推荐

  1. hiredis(Synchronous API)

    hiredis是一个小型的client端的c库.它只增加了最小对协议的支持,同时它用一个高级别的printf-alike API为了绑定各种redis命令.除了支持发送和接收命令,它还支持对流的解析. ...

  2. [编写高质量iOS代码的52个有效方法](五)接口与API设计(下)

    [编写高质量iOS代码的52个有效方法](五)接口与API设计(下) 参考书籍:<Effective Objective-C 2.0> [英] Matt Galloway 先睹为快 19. ...

  3. 一文彻底理解Redis序列化协议,你也可以编写Redis客户端

    前提 最近学习Netty的时候想做一个基于Redis服务协议的编码解码模块,过程中顺便阅读了Redis服务序列化协议RESP,结合自己的理解对文档进行了翻译并且简单实现了RESP基于Java语言的解析 ...

  4. java redis 命令_命令界面:使用Java中的动态API处理Redis

    java redis 命令 Redis是一个数据存储,支持190多个文档化命令和450多个命令排列. 社区积极支持Redis开发: 每个主要的Redis版本都附带新命令. 今年,Redis向第三方供应 ...

  5. 命令界面:使用Java中的动态API处理Redis

    Redis是一个数据存储,支持190多个已记录命令和450多个命令排列. 社区积极支持Redis开发: 每个主要的Redis版本都附带新命令. 今年,Redis向第三方供应商开放,以开发可扩展Redi ...

  6. 服务端朋友圈接口代码的编写和理解

    前期准备...... 1.通常我们在IDEA中建立两个包  2. 我们主要用Postman对朋友圈各种接口调用的实现做接口测试      3. 测试接口我们主要用下面几种请求方式: > GET ...

  7. 转载-- http接口、api接口、RPC接口、RMI、webservice、Restful等概念

    http接口.api接口.RPC接口.RMI.webservice.Restful等概念 收藏 Linux一叶 https://my.oschina.net/heavenly/blog/499661 ...

  8. mysql标准化存储结构_Atitit.自定义存储引擎的接口设计 api 标准化 attilax 总结  mysql...

    Atitit.自定义存储引擎的接口设计api标准化attilax总结mysql 1.图16.1:MySQL体系结构 存储引擎负责管理数据存储,以及MySQL的索引管理.通过定义的API,MySQL服务 ...

  9. RESTful API 编写规范

    基于一些不错的RESTful开发组件,可以快速的开发出不错的RESTful API,但如果不了解开发规范的.健壮的RESTful API的基本面,即便优秀的RESTful开发组件摆在面前,也无法很好的 ...

  10. java redis 流水线,Redis系列(1) —— 流水线

    写在前面 去年下半年,出于学习Redis的目的,在看完<Redis in Action>一书后,开始尝试翻译Redis官方文档.尽管Redis中文官方网站有了译本,但是看别人翻译好的和自己 ...

最新文章

  1. visualvm远程监控jvm_8款JVM性能调优监控工具(提高开发效率)
  2. PyTorch中AdaptiveAvgPool函数总结
  3. GDB调试程序系列 (3)
  4. java求最后一位不为0的数字_【Java】 剑指offer(62) 圆圈中最后剩下的数字
  5. 10个给程序员的建议
  6. 【CSS3】---last-of-type选择器+nth-last-of-type(n)选择器
  7. Go语言 -- PostgreSQL数据库
  8. 外贸人写开发信会犯的错误,你中了哪几个
  9. mac 上安装selenium, phantomjs 和 chromedriver
  10. 浅谈当下火热的ChatGPT
  11. SQL语句查询拼音码
  12. 【Python实战】听书就用它了:海量资源随便听,内含几w书源,绝对精品哦~(好消息好消息)
  13. 海量向量搜索引擎 Milvus 开源啦
  14. 个人收藏系列之360个人图书馆 轻松解除网页防复制难题
  15. Python语音机器人控制STM32开发流程
  16. 计算机网络体系结构i层,计算机网络体系结构及协议之网际互连IBEBEE
  17. 谭谭黄金面具后面法老的诅咒
  18. 曲线分类-特征提取(二)
  19. 2018年语音识别行业测评
  20. 如何制作相册?Mac电脑如何对照片进行管理分类?

热门文章

  1. Zookeeper Client简介
  2. 博客链接—Python
  3. HOOK使用:全局键盘钩子
  4. suse linux操作系统安全加固(服务关闭)
  5. PHP设计模式——模板模式
  6. 20一个自定义集合的自述
  7. CentOS7下让Asp.Net Core的网站自动运行
  8. HAOI2008 硬币购物
  9. 【做题】TCSRM592 Div1 500 LittleElephantAndPermutationDiv1——计数dp
  10. [20180819]四校联考