java redis批处理_redis大幅性能提升之使用管道(PipeLine)和批量(Batch)操作

前段时间在做用户画像的时候,遇到了这样的一个问题,记录某一个商品的用户购买群,刚好这种需求就可以用到Redis中的Set,key作为productID,value

就是具体的customerid集合,后续的话,我就可以通过productid来查看该customerid是否买了此商品,如果购买了,就可以有相关的关联推荐,当然这只是系统中

的一个小业务条件,这时候我就可以用到SADD操作方法,代码如下:

static void Main(string[] args)

{

ConnectionMultiplexer redis= ConnectionMultiplexer.Connect("192.168.23.151:6379");var db =redis.GetDatabase();var productID = string.Format("productID_{0}", 1);for (int i = 0; i < 10; i++)

{var customerID =i;

db.SetAdd(productID, customerID);

}

}

一:问题

但是上面的这段代码很明显存在一个大问题,Redis本身就是基于tcp的一个Request/Response protocol模式,不信的话,可以用wireshark监视一下:

48d4265bd69455857ea038287e952bf7.png

从图中可以看到,有很多次的192.168.23.1 => 192.168.23.151 之间的数据往返,从传输内容中大概也可以看到有一个叫做productid_xxx的前缀,

那如果有百万次局域网这样的round trip,那这个延迟性可想而知,肯定达不到我们预想的高性能。

二:解决方案【Batch】

刚好基于我们现有的业务,我可以定时的将批量的productid和customerid进行分组整合,然后用batch的形式插入到某一个具体的product的set中去,

接下来我可以把上面的代码改成类似下面这样:

1 static void Main(string[] args)2 {3 ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("192.168.23.151:6379");4

5 var db =redis.GetDatabase();6

7 var productID = string.Format("productID_{0}", 1);8

9 var list = new List();10

11

12 for (int i = 0; i < 10; i++)13 {14 list.Add(i);15 }16

17 db.SetAdd(productID, list.Select(i => (RedisValue)i).ToArray());18 }

bb556424e4960a5ed39f5e7c40f26a87.png

从截图中传输的request,response可以看到,这次我们一次性提交过去,极大的较少了在网络传输方面带来的尴尬性。。

三:再次提出问题

product维度的画像我们可以解决了,但是我们还有一个customerid的维度,也就是说我需要维护一个customerid为key的set集合,其中value的值为

该customerid的各种平均值,比如说“总交易次数”,“总交易金额”。。。等等这样的聚合信息,然后推送过来的是批量的customerid,也就是说你需要定时

维护一小嘬set集合,在这种情况下某一个set的批量操作就搞不定了。。。原始代码如下:

1 static void Main(string[] args)2 {3 ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("192.168.23.151:6379");4

5 var db =redis.GetDatabase();6

7

8 //批量过来的数据: customeridlist, ordertotalprice,具体业务逻辑省略

9 var orderTotalPrice = 100;10

11 var customerIDList = new List();12

13 for (int i = 0; i < 10; i++)14 {15 customerIDList.Add(i);16 }17

18 //foreach更新每个redis 的set集合

19 foreach (var item incustomerIDList)20 {21 var customerID = string.Format("customerid_{0}", item);22

23 db.SetAdd(customerID, orderTotalPrice);24 }25 }

四:解决方案【PipeLine】

上面这种代码在生产上当然是行不通的,不过针对这种问题,redis早已经提出了相关的解决方案,那就是pipeline机制,原理还是一样,将命令集整合起来通过

一条request请求一起送过去,由redis内部fake出一个client做批量执行操作,代码如下:

1 static void Main(string[] args)2 {3 ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("192.168.23.151:6379");4

5 var db =redis.GetDatabase();6

7

8 //批量过来的数据: customeridlist, ordertotalprice,具体业务逻辑省略

9 var orderTotalPrice = 100;10

11 var customerIDList = new List();12

13 for (int i = 0; i < 10; i++)14 {15 customerIDList.Add(i);16 }17

18 var batch =db.CreateBatch();19

20 foreach (var item incustomerIDList)21 {22 var customerID = string.Format("customerid_{0}", item);23

24 batch.SetAddAsync(customerID, orderTotalPrice);25 }26

27 batch.Execute();28 }

然后,我们再看下面的wireshark截图,可以看到有很多的SADD这样的小命令,这就说明有很多命令是一起过去的,大大的提升了性能。

a7d22a7ce4571d568f8642b8a1ef1b88.png

最后可以再看一下redis,数据也是有的,是不是很爽~~~

192.168.23.151:6379> keys *

1) "customerid_0"

2) "customerid_9"

3) "customerid_1"

4) "customerid_3"

5) "customerid_8"

6) "customerid_2"

7) "customerid_7"

8) "customerid_5"

9) "customerid_6"

10) "customerid_4"

好了,先就说到这里了,希望本篇对你有帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值