背景:
1、数据量大。 项目的缓存数据非常大,光 产品模块 有600M以上的数据。
2、单个请求是 request---response 模式。 一般情况下,Redis Client端发出一个请求后,通常会阻塞并等待Redis服务端处理,Redis服务端处理完后请求命令后会将结果通过响应报文返回给Client。
下面是官方文档( http://www.redis.io/documentation ) 对 Redis Mass Insertion 的讲述:
意思是 :
1、 你必须为每个redis client 命令执行支付往返时间,这对大批量插入是不明智的
2、 只有客户端的一小部分支持非阻塞I / O
因此在数量大的情况下,就算多弄几个redis实例来插入,也要承受这个往返时间的代价,很难有效提高。所以势必寻求一种减少这个往返时间的方法。幸好,redis的作者也想到了, 在2.6版本推出了一个新的功能-pipe mode,即将支持Redis协议的文本文件直接通过pipe导入到服务端。
管道
管道模式( pipe mode ):
redis是一个cs模式的tcp server,使用和HTTP类似的请求响应协议。通过ip+port的形式构建连接,发起请求命令。每个请求发出后client通常会阻塞并等待redis服务处理完毕返回响应。
而利用pipeline的方式从client打包多条命令一起发出,不需要等待单条命令的响应返回,而redis服务器会处理完多条命令后将多条命令的处理结果打包一起返回给客户端。
示例
一、redis 命令
redis的pipeline(管道)功能在命令行中没有,但redis是支持pipeline的,而且在各个语言版的client中都有相应的实现。
二、jedis pipeline
测试结果:
可以看到速度明显提升了
三、shard jedis
四、sentinel shard jedis
我给项目使用的就是这种方式,使用sentinel来查找master的相关信息,进而查找slaves。
这种方式想用pipeline需要对原有的代码( ShardedJedisPipeline.java )进行重写。
五、jedis cluster
并不支持pipeline,原因是
1、 cluster是服务器端的集群,节点变化对客户端来说是不能马上感知的。
2、pipeline模式下命令将被缓存到对应的连接(OutputStream)上,而在真正向服务端发送数据时,节点可能发生了改变,数据就可能发向了错误的节点,这导致批量操作失败,而要处理这种失败是非常复杂的。
因此想法是:
1、如果想用pipeline,那么集群环境的节点是比较稳定的情况下
真正向服务端发送数据时, 需要先取检验下节点是否存在
3、这些数据是要能承受,可以重试,最好是后台任务跑
4、这个动作不常用,如全量同步(这类只在第一次的时候需要)