redis学习笔记之pipeline
redis是一个cs模式的tcp server,使用和http类似的请求响应协议。一个client可以通过一个socket连接发起多个请求命令。每个请求命令发出后client通常 会阻塞并等待redis服务处理,redis处理完后请求命令后会将结果通过响应报文返回给client。基本的通信过程如下
Client: INCR X
Server: 1
Client: INCR X
Server: 2
Client: INCR X
Server: 3
Client: INCR X
Server: 4
基 本上四个命令需要8个tcp报文才能完成。由于通信会有网络延迟,假如从client和server之间的包传输时间需要0.125秒。那么上面的四个命 令8个报文至少会需要1秒才能完成。这样即使redis每秒能处理100个命令,而我们的client也只能一秒钟发出四个命令。这显示没有充分利用 redis的处理能力。除了可以利用mget,mset 之类的单条命令处理多个key的命令外
我们还可以利用pipeline的方式从client打包多条命令一起发出,不需要等待单条命令的响应返回,而redis服务端会处理完多条命令后会将多条命令的处理结果打包到一起返回给客户端。通信过程如下
Client: INCR X
Client: INCR X
Client: INCR X
Client: INCR X
Server: 1
Server: 2
Server: 3
Server: 4
假 设不会因为tcp 报文过长而被拆分。可能两个tcp报文就能完成四条命令,client可以将四个incr命令放到一个tcp报文一起发送,server则可以将四条命令 的处理结果放到一个tcp报文返回。通过pipeline方式当有大批量的操作时候。我们可以节省很多原来浪费在网络延迟的时间。需要注意到是用 pipeline方式打包命令发送,redis必须在处理完所有命令前先缓存起所有命令的处理结果。打包的命令越多,缓存消耗内存也越多。所以并是不是打 包的命令越多越好。具体多少合适需要根据具体情况测试。下面是个jredis客户端使用pipeline的测试
package jredisStudy;
import org.jredis.JRedis;
import org.jredis.connector.ConnectionSpec;
import org.jredis.ri.alphazero.JRedisClient;
import org.jredis.ri.alphazero.JRedisPipelineService;
import org.jredis.ri.alphazero.connection.DefaultConnectionSpec;
public class PipeLineTest {
public static void main(String[] args) {
long start = System.currentTimeMillis();
usePipeline();
long end = System.currentTimeMillis();
System.out.println(end-start);
start = System.currentTimeMillis();
withoutPipeline();
end = System.currentTimeMillis();
System.out.println(end-start);
}
private static void withoutPipeline()
{
try {
JRedis jredis = new JRedisClient("192.168.56.55",6379);
for(int i =0 ; i < 100000 ; i++)
{
jredis.incr("test2");
}
jredis.quit();
} catch (Exception e) {
}
}
private static void usePipeline() {
try {
ConnectionSpec spec = DefaultConnectionSpec.newSpec("192.168.56.55", 6379, 0, null);
JRedis jredis = new JRedisPipelineService(spec);
for(int i =0 ; i < 100000 ; i++)
{
jredis.incr("test2");
}
jredis.quit();
} catch (Exception e) {
}
}
}
输出
103408 //使用了pipeline
104598 //没有使用
测试结果不是很明显,这应该是跟我的测试环境有关。我是在自己win连接虚拟机的linux。网络延迟比较小。所以pipeline
优势不明显。如果网络延迟小的话,最好还是不用pipeline。除了增加复杂外,带来的性能提升不明显。
=================
一般情况下,Redis Client端发出一个请求后,通常会阻塞并等待Redis服务端处理,Redis服务端处理完后请求命令后会将结果通过响应报文返回给Client。
这有点类似于HBase的Scan,通常是Client端获取每一条记录都是一次RPC调用服务端。
在Redis中,有没有类似HBase Scanner Caching的东西呢,一次请求,返回多条记录呢?
有,这就是Pipline。官方介绍 http://redis.io/topics/pipelining
通过pipeline方式当有大批量的操作时候,我们可以节省很多原来浪费在网络延迟的时间,需要注意到是用pipeline方式打包命令发送,redis必须在处理完所有命令前先缓存起所有命令的处理结果。打包的命令越多,缓存消耗内存也越多。所以并不是打包的命令越多越好。
使用Pipeline在对Redis批量读写的时候,性能上有非常大的提升。
使用Java测试了一下:
- package com.lxw1234.redis;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.Set;
- import redis.clients.jedis.Jedis;
- import redis.clients.jedis.Pipeline;
- import redis.clients.jedis.Response;
- public class Test {
- public static void main(String[] args) throws Exception {
- Jedis redis = new Jedis("127.0.0.1", 6379, 400000);
- Map<String,String> data = new HashMap<String,String>();
- redis.select(8);
- redis.flushDB();
- //hmset
- long start = System.currentTimeMillis();
- //直接hmset
- for (int i=0;i<10000;i++) {
- data.clear();
- data.put("k_" + i, "v_" + i);
- redis.hmset("key_" + i, data);
- }
- long end = System.currentTimeMillis();
- System.out.println("dbsize:[" + redis.dbSize() + "] .. ");
- System.out.println("hmset without pipeline used [" + (end - start) / 1000 + "] seconds ..");
- redis.select(8);
- redis.flushDB();
- //使用pipeline hmset
- Pipeline p = redis.pipelined();
- start = System.currentTimeMillis();
- for (int i=0;i<10000;i++) {
- data.clear();
- data.put("k_" + i, "v_" + i);
- p.hmset("key_" + i, data);
- }
- p.sync();
- end = System.currentTimeMillis();
- System.out.println("dbsize:[" + redis.dbSize() + "] .. ");
- System.out.println("hmset with pipeline used [" + (end - start) / 1000 + "] seconds ..");
- //hmget
- Set keys = redis.keys("*");
- //直接使用Jedis hgetall
- start = System.currentTimeMillis();
- Map<String,Map<String,String>> result = new HashMap<String,Map<String,String>>();
- for(String key : keys) {
- result.put(key, redis.hgetAll(key));
- }
- end = System.currentTimeMillis();
- System.out.println("result size:[" + result.size() + "] ..");
- System.out.println("hgetAll without pipeline used [" + (end - start) / 1000 + "] seconds ..");
- //使用pipeline hgetall
- Map<String,Response<Map<String,String>>> responses = new HashMap<String,Response<Map<String,String>>>(keys.size());
- result.clear();
- start = System.currentTimeMillis();
- for(String key : keys) {
- responses.put(key, p.hgetAll(key));
- }
- p.sync();
- for(String k : responses.keySet()) {
- result.put(k, responses.get(k).get());
- }
- end = System.currentTimeMillis();
- System.out.println("result size:[" + result.size() + "] ..");
- System.out.println("hgetAll with pipeline used [" + (end - start) / 1000 + "] seconds ..");
- redis.disconnect();
- }
- }
- dbsize:[10000] ..
- hmset without pipeline used [243] seconds ..
- dbsize:[10000] ..
- hmset with pipeline used [0] seconds ..
- result size:[10000] ..
- hgetAll without pipeline used [243] seconds ..
- result size:[10000] ..
- hgetAll with pipeline used [0] seconds ..
使用pipeline来批量读写10000条记录,就是小菜一碟,秒完。
redis学习笔记之pipeline的更多相关文章
- Redis学习笔记7--Redis管道(pipeline)
redis是一个cs模式的tcp server,使用和http类似的请求响应协议.一个client可以通过一个socket连接发起多个请求命令.每个请求命令发出后client通常会阻塞并等待redis ...
- redis 学习笔记(6)-cluster集群搭建
上次写redis的学习笔记还是2014年,一转眼已经快2年过去了,在段时间里,redis最大的变化之一就是cluster功能的正式发布,以前要搞redis集群,得借助一致性hash来自己搞shardi ...
- Redis 学习笔记4: Redis 3.2.1 集群搭建
在CenOS 6.7 linux环境下搭建Redis 集群环境 1.下载最新的Redis版本 本人下载的Redis版本是3.2.1版本,下载之后,解压,编译(make): 具体操作可以参考我的博文:R ...
- redis 学习笔记-cluster集群搭建
一.下载最新版redis 编译 目前最新版是3.0.7,下载地址:http://www.redis.io/download 编译很简单,一个make命令即可,不清楚的同学,可参考我之前的笔记: red ...
- Redis学习笔记~目录
回到占占推荐博客索引 百度百科 redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合). ...
- Redis学习笔记4-Redis配置详解
在Redis中直接启动redis-server服务时, 采用的是默认的配置文件.采用redis-server xxx.conf 这样的方式可以按照指定的配置文件来运行Redis服务.按照本Redi ...
- Redis学习笔记一:数据结构与对象
1. String(SDS) Redis使用自定义的一种字符串结构SDS来作为字符串的表示. 127.0.0.1:6379> set name liushijie OK 在如上操作中,name( ...
- Redis学习笔记之ABC
Redis学习笔记之ABC Redis命令速查 官方帮助文档 中文版本1 中文版本2(反应速度比较慢) 基本操作 字符串操作 set key value get key 哈希 HMSET user:1 ...
- (转)redis 学习笔记(1)-编译、启动、停止
redis 学习笔记(1)-编译.启动.停止 一.下载.编译 redis是以源码方式发行的,先下载源码,然后在linux下编译 1.1 http://www.redis.io/download 先 ...
随机推荐
- LightOj 1096 - nth Term (矩阵快速幂,简单)
题目 这道题是很简单的矩阵快速幂,可惜,在队内比赛时我不知什么时候抽风把模版中二分时判断的 ==1改成了==0 ,明明觉得自己想得没错,却一直过不了案例,唉,苦逼的比赛状态真让人抓狂!!! #incl ...
- POJ 2253 Frogger (求某两点之间所有路径中最大边的最小值)
题意:有两只青蛙,a在第一个石头,b在第二个石头,a要到b那里去,每种a到b的路径中都有最大边,求所有这些最大边的最小值.思路:将所有边长存起来,排好序后,二分枚举答案. 时间复杂度比较高,344ms ...
- 实战案例--Grunt构建Web程序
GruntJS构建Web程序.使用Gruntjs来搭建一个前端项目,然后使用grunt合并,压缩JS文件,熟练了node.js安装和grunt.js安装后,接下来来实战一个案例,案例是根据snandy ...
- cojs 简单的最近公共祖先 解题报告
我曾经自己想过每考试一次就从考试题中找找idea来出题 这次又找到了一个,先不管原来的考试题是什么 考试题中其中的一部分就是今天的这道题目啦 当时考场上自己比较傻,没有注意到有用的性质,套用了之前黑白 ...
- 欧拉工程第73题:Counting fractions in a range
题目链接:https://projecteuler.net/problem=73 n/d的真分数 ,当d<=12000时 在 1/3 and 1/2 之间的有多少个 public class P ...
- Google不做坏事吗?
说中国足球为什么冲不出亚洲,那是因为咱中国人太文气,足球是种“斗牛士”式的游戏,得玩的有点儿“野蛮”色彩.记得以前在英国的时候,遇上联赛,晚上大街小巷全民皆兵,曼切斯特队的粉丝在街道一边酒吧里,利物浦 ...
- python url编码,解码
>>> urllib.unquote('%E4%B8%BD%E6%B1%9F') >>> data '\xe4\xb8\xbd\xe6\xb1\x9f' >& ...
- 63. Unique Paths II
题目: Follow up for "Unique Paths": Now consider if some obstacles are added to the grids. H ...
- Android ActionBar中的下拉菜单
在ActionBar中添加下拉菜单,主要有一下几个关键步骤: 1. 生成一个SpinnerAdapter,设置ActionBar的下拉菜单的菜单项 2. 实现ActionBar.OnNavigatio ...
- JDBC学习总结(三)
1.ResultSet光标控制 在创建Statement或PreparedStatement时使用的是Connection的无参数createStatement()方法或preparedSta ...