当前位置: 首页 > 科技观察

说说我与流计算的故事

时间:2023-03-19 20:42:21 科技观察

让我们谈谈流计算。那次经历对我来说非常令人兴奋和有趣。我想和你分享这段经历。1背景2014年在艺龙网推广组负责红包系统。当时,促销大战如火如荼,优惠券计算服务成为艺龙促销业务中最重要的业务之一。优惠券计算服务使用了当时知名的流式计算框架Storm。流计算是一种利用分布式思想和方法实时处理海量“流”数据的系统。它源于挖掘海量数据“时效性”价值的需求。优惠券计算服务的逻辑是:每个城市和酒店的优惠券使用规则不同。当运营商修改规则时,触发优惠券计算服务。计算完成后,当用户下单并使用优惠券时,会显示最新的规则。优惠券计算服务是我们团队的明星项目。很多研发同学对Storm特别感兴趣,因为Storm的核心开发语言是clojure,比较小众。所以,在队内,我发现了一个很有趣的现象:很多同学的办公桌上都有这本书《clojure in Action 》。clojureinAction艺龙开始发力移动互联网,业务量激增,优惠券计算服务开始遇到瓶颈。比如运营商修改全量规则,整个计算过程需要一上午,所以没有实时计算。CTO多次找到组长,严厉批评他尽快优化。经过一个半月的多次优化,系统的瓶颈依然很明显。时不时会有运营同事来到我们的工位,催促我们:“系统好用吗?”我不负责计算服务。每当同事被质疑时,我就很疑惑:“优惠券计算服务真的有那么复杂吗?”同时也跃跃欲试:“暴风雨真的有那么难吗?”我暗暗下定决心,弄清楚优惠券计算服务的逻辑。2向国家图书馆学习北京有许多让我流连忘返的景点,如史铁生小说中的地坛,枫叶覆盖的香山,风景如画的颐和园,金碧辉煌的天坛。在我心中,有一个非常神圣的地方,是知识和希望的象征,那就是国家图书馆。中国国家图书馆位于北京市中关村南大街33号,毗邻海淀区白石桥高粱河和紫竹园公园。是国家总图书馆、国家书目中心、国家古籍保护中心,也是世界上规模最大、设施最先进的国家图书馆之一。每个周末,当我想静下心来专心思考时,我都会背着笔记本电脑来到国家图书馆。选择自己喜欢的书,然后打开笔记本电脑,边看书边在电脑上写一些笔记。偶尔抬起头看看正在看书的读者。心里觉得很阳光,觉得生活充满希望。解开Storm之谜并找出优惠券计算服务为何如此缓慢的愿望让我彻夜难眠。于是周六早上9点30分,我去了国家图书馆,试图让自己安静下来,思考如何解决这个问题。解决问题的乐趣是我一直追求的。当我把笔记本平放在桌子上的时候,心里很是激动,同时灵台澄清:优惠券计算服务的核心是Storm,所以我需要先了解一下Storm的整体概念。当我打开官网,浏览官网文档的时候,第一次看到Storm的逻辑流程图,作为一个程序员,第一次感受到了抽象之美:水从源头流过水龙头(Spout),再经过层层Bolt过滤器,不就是我们想要的纯净水吗?风暴逻辑图已授权。事实上,我们都是CRUD男孩。我们机械地使用这些框架。我们只能增删改查,不去思考框架背后的设计思路。但究竟什么是框架?从来没有想过。一直觉得自己学什么都笨手笨脚的,但那一刻突然意识到:框架本身把解决问题的思维抽象出来,方便开发者使用,把复杂的问题抽象成美学需要扎实的基础.了解了Storm的整体概念之后,接下来就是大家熟知的编写HelloWorld的阶段了。参考教程写了一个简单的Storm应用(简称topology)。部署后,程序运行正常。我一直有一个疑问:“是不是优惠券计算服务的storm集群配置没有优化,导致计算性能很差?”所以得弄明白storm的并发是怎么计算的。整个下午,我一直在查找相关资料,结合下图思考:Nimbus、Supervisor、Worker、Task是什么概念,它们之间是如何交互的。进一步思考:拓扑会启动多少个进程,每个进程的内部线程模型是什么?这个习惯一直保持到现在。当我看到一个系统时,我会下意识地思考:“这个系统的线程模型是什么,每个操作都有哪些线程参与,它们之间是如何交互的”。我知道还有更牛逼的高手,跑一行代码就能知道CPU会运行哪些指令。我做不到,但我认为它更深刻。反正这一天,我的思想发生了很多变化,兴奋,犹豫,放弃,阳光,激动,畏难,一直都存在。很多次想放弃,但好奇心一直鼓励着我。天黑的时候,我走出了国图的大门,脑子里全是Storm进程和线程模型,心里莫名的自信。感觉就像仙剑奇侠传里的酒剑仙子,伴随着激昂的BGM,拔剑四顾,斩妖除魔。御剑乘风辟邪。人间有酒有乐,无酒我亦痴。饮尽江河,再吞日月,千杯不醉,吾乃剑仙。3找到瓶颈当我理解了Storm的整体概念后,我需要找到优惠券计算服务的性能瓶颈。这时候梳理计算服务的整体流程就非常关键了。优惠券流计算拓扑计算服务的整体流程分为三个步骤:数据抽取:酒店信息拉取服务拉取酒店信息存储在水源(RedisA/B集群);计算过程:Storm拓扑从水源获取酒店数据,通过操作配置规则清洗数据,计算后的数据存储在水存储池(RedisC集群);存储阶段:存储服务从蓄水池中获取数据,并将计算结果存入数据库。当我们将整个计算过程拆分为提取-->计算-->存储三个阶段时,计算服务的架构就变得异常清晰。哪个阶段最耗时也成了我考察的对象。.CouponCalculationService当时没有详细的性能监控系统,只能从日志入手。运维同事触发全量计算后,观察三个阶段对应服务的日志:数据提取:酒店信息拉取服务计算过程:Storm拓扑存储阶段:存储服务惊奇现象:一次全量计算耗时超过4个小时,但是提取数据的任务居然跑了2个多小时,和我预想的完全不一样。如果把酒店信息拉取服务比作水泵,那么整个系统最大的问题就是水泵的马力不足。4推进改造为什么泵力不足?通过阅读源码发现,由于线程模型不够好,应用部署到多个节点后,每个节点只能有两个线程执行拉取酒店信息。如何处理?在原始代码上优化是否可行?看来不容易,因为老代码原来是一个C#研发的同事写的,他当时对JAVA还不熟悉。从设计层面来说,冗余和不合理的代码很多,而且经过3年左右的维护,代码老化严重,只能想到重构。当我把我的想法传达给组长时,他有点半信半疑。他认为我的判断是正确的,但他不确定我能否很好地重构系统。当时我信心满满,主动提出来,确信不会有问题。大概是因为CTO手头太紧,他同意了。在重构之前,梳理一下系统的整体逻辑。酒店拉取服务逻辑图重构有两个关键原则:拉取服务可以横向扩展,如果性能不足,增加服务节点可以提升性能;配置文件可以配置工作线程的数量。思想层面我准备好了,但是硬实力层面我准备好了吗?很自信的说,准备好了,因为遇到了RocketMQ。我在这篇文章中写道《我与消息队列的8年情缘》:2014年,收集了很多关于淘宝消息队列的资料。我知道MetaQ的版本已经升级到MetaQ3.0,但是开源版本还没有发布。大约在秋天,我加入了RocketMQ技术组。石佳(RocketMQ创始人)在群里说:“最近开源要发布了,发布了大家抓紧fork一下。”他这句话发到群里后,群里炸开了锅。心里更加高兴了,期待早日看到阿里自己的内部消息中间件。最后,RocketMQ终于开源了。我迫不及待地想看他一眼。因为想学网络编程,而RocketMQ的通讯模块remoting底层也是Netty写的。因此,RocketMQ的通信层是我学习的起点。我模仿了RocketMQ的remoting,写了一个玩具rpc,大大提升了自信心。巧合的是,艺龙举办了科技创新活动。我想了想,不如试试用Netty重写Cobar的通信模块。于是参考Cobar的源码,花了两周的时间写了一个netty版的proxy,其实很粗糙,很多功能还不完善。后来这次活动给了我一个鼓励奖,现在想想都觉得有趣。在重构酒店信息拉取服务时,我只是利用了RocketMQ创建线程的知识,学习了如何更合理的拆分模块。同时,在重构过程中,我们不断审查新旧代码的差异,确保核心逻辑正确。很幸运,大约一周的时间,我完成了重构。重构完成不代表结束,如何验证呢?我当时采取了两种方式:Codereview我拉着couponcalculationservice的同事一起review代码。整个过程中,大家没有提出异议,对我的发帖技巧非常好奇。我心中一喜:“那是为了学习RocketMQ”。测试环境数据验证我们会同时触发新旧版本的服务,比较两个版本数据的异同,将比较结果输出到日志文件,然后从中找出不同点,并修复重构版本的BUG。然后将重构后的版本部署到测试环境中,观察一段时间,确保没有异常。从写完第一行代码到三周后,重构版本终于上线了。我替换掉原来的老服务后,部署了3个节点,每个节点有8个worker并行拉取酒店信息。令人高兴和兴奋的是,重构非常成功。因为业务给我们的时间需求也是1小时左右。一个完整的计算从原来的4小时迅速减少到1小时15分钟,整个酒店拉取服务大约需要40分钟。我松了口气,心里默念着李白的诗句:“十步杀人,千里不留。事后拂衣隐身名。”“5大步向前,FacebookCOOCherylSanderBerg写了一本书《向前一步》,我特别喜欢这本书的书名。在优化优惠券计算服务的前期,团队经历了一个多月,但没有任何效果。我也犹豫过:“我能解决这个问题吗?”,但最终我还是向前迈出了一步,帮助团队大大提高了服务的性能。负责人也有了底气,敢于投入资源优化Storm拓扑和入库流程。在阅读优惠券计算服务的代码时,发现了两个问题:流量计算逻辑中有大量的网络IO请求,主要是查询具体的酒店数据进行后续计算;每次计算都需要查询基本的配置数据,都是从数据库中取出来的。对于Storm拓扑优化,我有两个建议:流计算拓扑和酒店拉取服务各司其职,将流计算中的网络IO请求移至酒店拉取服务,提前准备数据;配置缓存,引入读写锁(也是RocketMQ名称服务的一种技术)。入库流程,研发同学将原来的单一数据入库修改为批量入库。经过大家的共同努力,优惠券计算服务的整体性能有了很大的提升,全量计算的耗时变成了40分钟,再也没有运营同事会在我们工作站附近抱怨系统慢了。6写到最后2014年,我将公司流计算服务的优化向前推进了一步,取得了一点进展。时光荏苒,人到中年,人生遇到的挫折越来越多,有时会让人心情低落,但每当想起这个故事,都会为当时不屈不挠的进步而深深感动.当再次面临选择的时候,我希望自己也能更进一步,思考如何帮助读者成长,或者实现一个产品来帮助更多的人。