设为首页 收藏本站
查看: 1069|回复: 0

[经验分享] redis大幅性能提升之使用管道(PipeLine)和批量(Batch)操作

[复制链接]

尚未签到

发表于 2017-12-20 14:56:07 | 显示全部楼层 |阅读模式
  前段时间在做用户画像的时候,遇到了这样的一个问题,记录某一个商品的用户购买群,刚好这种需求就可以用到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监视一下:
DSC0000.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<int>();
  
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         }
  

DSC0001.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<int>();
  
12
  
13             for (int i = 0; i < 10; i++)
  
14             {
  
15                 customerIDList.Add(i);
  
16             }
  
17
  
18             //foreach更新每个redis 的set集合
  
19             foreach (var item in customerIDList)
  
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<int>();
  
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 in customerIDList)
  
21             {
  
22                 var customerID = string.Format("customerid_{0}", item);
  
23
  
24                 batch.SetAddAsync(customerID, orderTotalPrice);
  
25             }
  
26
  
27             batch.Execute();
  
28         }
  

  然后,我们再看下面的wireshark截图,可以看到有很多的SADD这样的小命令,这就说明有很多命令是一起过去的,大大的提升了性能。
DSC0002.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"
  

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

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-426078-1-1.html 上篇帖子: Spring 极速集成注解 redis 实践 下篇帖子: 超好用的Redis管理及监控工具,使用后可大大提高你的工作效率!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表