redis3.0管道pipeline支持及遇到的问题
无关紧要的屁话
hello,我又回来啦,消失的这一年时间发生了好多事呀,换了工作,当了房奴,在这里祝天下太平,苍生幸福~
前言
最近项目当中遇到需要对数据落地到redis,并且集群使用了最新的redis3.0,满心欢喜的使用新功能,压测的时候却发现吞吐只有几万,达不到要求怎么办,嘿,多次相同操作pipeline有巨大优势,于是,管道加上,什么?redis3.0不支持管道,没办法,只有自己造轮子了。。。
整体思路是:
首先我们要知道为什么现在redis3.0不支持管道,现redis-cluster是采用slot方式写入数据(查找这个数据对应的槽位的方法就是对数据的key取模,即 CRC16(key) mod 16384,得到的结果就是写入数据存放的slot位置 ),导致想批量进行操作得数据位于不同slot上,从而操作失败。
而由于key是我们设置的,所以我们可以通过预先计算key所对应的slot(写了半天crc发现jedis自带计算方法。。。),然后再将数据进行一个归纳,将属于相同redis分片上的key放入相同的一个pipeline当中,然后在整体对所有pipeline进行一个sync同步即可。
1、对redis-cluster进行预加载,将每个分片对应的slot-jedisPool关系保存到本地缓存当中
2、从一批数据当中依次获得相应的key
3、通过key计算出对应的slot值
4、通过slot值获得相应的pipeline,并缓存产生的pipeline
5、将redis操作放入相应的pipeline
6、对缓存当中的所有pipeline依次进行一个sync
7、关闭对应的pipeline和jedis
8、新一批数据来了之后重复以上2~7过程
注意,这里有一个小坑:
因为pipeline不支持多线程操作,并且在进行sync之后,管道并没有消失,仍然持有jedis的client对象,如果对象池归还了jedis,但是这个jedis对象的client被pipeline持有,会导致线程不安全报错。所以我这里在每次使用完一个pipeline之后都会进行一个close,保证了每次操作的client和pipeline都是新的对象。
正文
由于项目需要,我的代码做了相应的改动,这里只列出相关核心代码,读者需要的话可以自行调试改动:
找出host和jedisPool的映射关系
JedisPoolConfig config = new JedisPoolConfig();
config