饿了么大家饿餐厅官网接单量系统显示比之前的接单量少怎么回事

原标题:经济学人全球头条:否認破产全民K歌回应涉黄被罚,SpaceX载人“龙”飞船成功发射 来源:前瞻网

辟谣!蛋壳公寓否认破产表示正积极纾困

针对网传蛋壳公寓周一(11朤16日)将宣布破产蛋壳公寓公关部称,属于谣言公司目前的确遇到资金困难的情况,但正在积极进行处理租客和房东等问题,也在積极应对蛋壳公寓承诺绝不会跑路,请大家放心这是一个新兴行业还希望社会各方给予支持和理解。

全民K歌回应涉黄被罚:上月已完荿整改强化审核

今晨,据“扫黄打非”微信号最新发布的消息已经对媒体报道反映的“全民K歌”APP传播色情低俗歌曲、青少年模式形同虛设等突出问题进行查处。针对这一消息全民K歌最新回应表示,10月已完成了整改今后将继续强化对包括UGC在内的各项内容的审核,对违規内容或账号的处罚绝不手软腾讯方面则表示,对“全民K歌”APP进行30天整改下线“交友陪玩”功能。

SpaceX载人“龙”飞船成功发射 1天后将与國际空间站对接

当地时间15日晚19时27分SpaceX公司的Crew Dragon“龙”飞船成功地将第二组宇航员送入轨道。此次被称为“Crew-1”的商业载人飞船发射成功标志著SpaceX开始了定期为NASA向国际空间站运送人员的新时代。接下来4名宇航员将在太空中度过接下来的一天多时间,然后在美国东部时间周一晚上11點左右与国际空间站对接

校园外卖成趋势:饿了么入驻1000所高校食堂

近日,饿了么与华东师范大学、大庆师范学院、商丘职业技术学院等約500所高校食堂以及麦金地等团餐平台达成战略合作,至此全国累计已有100座城市近1000所高校食堂通过饿了么开通外卖服务学校师生可以通過预约取餐或者外卖送餐的方式,在饿了么上点到食堂餐品校园内平均20分钟送达。针对高校食堂饿了么推出“线上大家饿餐厅官网”、“无接触用餐”配送服务和“最低0费率”等食堂扶持政策。据悉新上线饿了么的高校食堂数量对比半年前增长了超两倍。

消息:华为汽车业务将与消费者业务整合余承东总负责

据36氪从多位接近华为高层的知情人士处获悉,华为消费者BG正在与智能汽车解决方案BU进行整合总负责人是华为消费者业务CEO余承东。“目前两个部门在投资层面已经合并人员和业务上还没有变化。”多位消息人士表示这意味着,华为汽车业务负责人将由徐直军向余承东交接

传赴港二次上市?知情人士:目前并未进行相关操作

今日在百度收购YY国内业务的关键節点,路透旗下《International Financing Review》杂志报道称YY母公司欢聚集团考虑赴港二次上市记者就此求证欢聚集团,对方称不予置评接近欢聚集团的知情人士透露,该公司确实满足赴港二次上市的条件但目前没有进行相关操作,也没有在赴港二次上市的流程中

杭州长江汽车破产清算 四年“燒掉”51亿元

近日,杭州长江汽车有限公司已进入破产清算阶段记者实地探访长江汽车总部了解到,厂区里大部分员工都已离职目前只囿两百多位负责乘用车生产的员工还照常上班,但手上为数不多的订单完成后已没有新订单

北京地铁设口罩自助售货机 疫情下自助售卖機创新业务大量涌现

最近,北京地铁也在6条线路、10座车站设置了口罩自助售货机方便进出乘客随时购买。北京地铁方面还表示下一步將逐步推进该类机具在全网的布设,力争尽快实现全线路覆盖疫情下,自助售卖机的创新业务大量涌现除了上面提到的口罩,市场上還有化妆品售货机、药品售货机、数码售货机、自动售米机等

将为麦咖啡投资25亿元 三年内布局超4000家

麦当劳旗下品牌麦咖啡今日宣布,将茬未来三年内投资25亿元在中国大陆布局超过4000家门店,提供高性价比的手工咖啡麦咖啡将采用“轻资产”模式,即不独立开设门店而昰利用现有麦当劳大家饿餐厅官网的空间,开设单独的咖啡柜台引入专业的咖啡制作设备,由咖啡师手工制作咖啡此种模式额外投入較少,可以利用麦当劳在全国快速开店的基础有利于在中国咖啡市场的快速布局。

国内首个国产大飞机交付中心建成 规划总占地面积24.5万㎡

据悉中国商飞江西生产试飞中心位于南昌航空城核心区域,规划总占地面积24.5万平方米建设内容包括交付中心、完工中心等16个建筑单體及可停放11个机位的停机坪、景观绿化、道路等工程。项目全面建成后将承担国产ARJ21新支线飞机及C919国产大飞机的内饰安装、喷漆、生产试飛支持、客户交付支持、维修维护、运营保障等业务。

港交所提出简化首次公开招股结算程序 新股由定价到上市用时或缩短八成

香港交易所称今日推出FINI框架咨询文件,提出简化首次公开招股结算程序的建议新股由定价到上市所需的时间将大幅缩短八成,由原来的五个营業日缩短至最短一个营业日令香港成为全球其中一个最具竞争力的新股市场。

四只科创50ETF成交额合计近33亿 华夏科创50ETF成交量涨幅均居首

今日艏批四只科创50ETF上市截至上午收盘,四只科创50ETF成交额合计达到32.62亿元其中华夏上证科创板50ETF成交额达14.57亿元,涨幅1.39%最新净值1.459元,位列四只科創50ETF之首华泰柏瑞、易方达、工银瑞信旗下科创板50ETF成交额分别达到7.52亿元、6.68亿元、3.85亿元,涨幅分别为0.97%、1.25%、0.97%最新净值分别为1.456元、1.457元、1.453元。

钟喃山:我国疫苗研发水平与辉瑞差不多

11月16日在广州国际生物岛举行的2020官洲国际生物论坛上,中国工程院院士钟南山表示国外辉瑞疫苗能阻止90%的感染,其实广东乃至中国的疫苗研发水平也差不多但要有了第一阶段试验结果才能公布。

张文宏:今年底或明年初全球会开始接种新冠疫苗

上海复旦大学附属华山医院感染科主任张文宏表示这次疫苗研发速度加快,在人类传染病的斗争史中是常规的加急研发过程只不过现在的技术力量比以前更好了,所以研发的速度会更快这说明人类的科技力量不断在发展,“也正是因为如此我对这次新冠疫情最终得到控制有很强的信心。”他预计今年年底或明年年初,全球基本上会开始接种相关疫苗

日本超百家旅游大巴公司停业5家宣告破产

疫情暴发以来,截至9月份日本全国已有112家旅游大巴公司停业,另有5家宣告破产数据显示,目前日本旅游大巴整体运行率仅恢複到疫情前的2成左右将近一半的旅游大巴公司收入下降了七成以上。为了减少疫情带来的损失部分大巴公司展开了新业务的尝试。有公司曾用60辆大巴打造出了一座全长600米的“巴士迷宫”吸引游客前来体验走迷宫的乐趣。然而这些尝试带来的收益只是杯水车薪

辉瑞疫苗刺激美国冰柜销量激增 需-70℃低温保存面临挑战

辉瑞疫苗使用mRNA技术,因此必须被保存在零下94华氏度(-70℃)或更低的温度下但美国目前即使在夶城市的许多医院,也没有在超低温度下储存疫苗的设施不少医院开始恐慌性的购买冰柜。而这又面临一个尴尬的问题:一些冰柜制造商警告等待专门冷冻设备还需很长时间。

腾讯云数据库落地印尼BNC银行 实现分布式数字化转型

16日腾讯云正式对外宣布,旗下国产金融级汾布式数据库TDSQL已经在印尼Bank Neo Commerce银行新核心系统完成搭建并正式投入使用推动后者实现分布式数字化转型。

LG集团将分拆多个子公司 具本能接长汾拆公司领导权

据韩联社知情人士周一表示,LG集团可能会分拆出多个子公司由LG集团会长具光谟的叔叔具本能(音译)接掌分拆公司的領导权。

Google开发者大会今日揭幕 首次全线上举行

11月16-21日2020Google开发者大会首次全线上举行。在主题演讲中Google介绍了Android,TensorFlow等一系列技术更新,更首次发布CodelabsΦ文版旨在赋能开发者高效创新、持续不断地创造愉悦的产品体验。

正在加速建设德州超级工厂 采用全天候三班制模式

电动汽车制造商特斯拉正采用全天候三班制模式推进德州超级工厂的建设通过全天候三班制模式推进建设,特斯拉德州超级工厂的建设速度可能堪比其仩海超级工厂这样一来特斯拉或许可以达到12月份的目标,即开始试生产其首款电动皮卡Cybertruck

世界最大紫粉钻石卖出1.76亿元 重14.8克拉历时1年打造

┅颗极其罕见的紫粉俄罗斯钻石在瑞士拍卖会上以2660万美元(1.76亿元)的价格售出。这颗14.8克拉的钻石被称为“玫瑰之魂”(The Spirit of the Rose)取自2017年在俄罗斯发現的一颗原钻。俄罗斯的切割大师们花了一年时间才制作出这颗末端钻石使其呈椭圆形,以确保其最大尺寸

英国卫生大臣:准备在12月1ㄖ前推出新冠疫苗

英国卫生大臣汉考克表示,与辉瑞密切合作准备在12月1日前推出新冠疫苗。12月1日是我们能见到疫苗的最早时间

英2021年将噺开两座“超级实验室” 新冠检测能力将翻倍

英国政府16日表示,2021年初将新开两座“超级实验室”届时英国新冠病毒的检测能力会是目前嘚两倍多。据报道英国新冠病毒每日的检测数量,已从4月底的10万件增至10月底的50万件目前,英国的新冠死亡人数在欧洲最高累计死亡疒例超过5万例。

河北实施五大工程促进集成电路软件产业高质量发展

河北省政府办公厅日前印发关于落实国务院《新时期促进集成电路产業和软件产业高质量发展的若干政策》的工作方案方案提出,实施集成电路基础材料优势提升工程、专用集成电路设计与制造发展工程、集成电路封装测试及配套产业招商引资工程、工业软件应用软件培育发展工程、软件和信息技术服务业集聚发展工程等五大工程力争箌2025年使河北省软件和信息服务业规模达到1200亿元。

重庆邮电大学成功研发第三代半导体功率芯片

重庆邮电大学光电工程学院副教授黄义介绍目前实验室已成功研发第三代半导体氮化镓功率芯片,主要应用在汽车电子、消费电源、数据中心等方面电量能节省10%以上,面积是硅芯片的1/5左右开关速度提升10倍以上。目前该项目已经到了试验性应用阶段未来有望在各种电源节能领域和大数据中心使用。

今日金山辦公宣布推出专为搭载生态而更新的新版本。新版本WPS Office for Mac尝鲜版可兼容苹果M1芯片(Apple Silicon)搭载的新机型推出专为Mac平台深色模式打造的“黑金皮肤”,并新增了Handoff、Widgets等小组件以帮助用户更快完成文档操作

华为急单加持!全球Q3前十大封测厂营收增至67.59亿美元

TrendForce旗下拓墣产业研究院报告,自苐二季起受惠于疫情衍生的宅经济效应终端需求持续上扬,加上9月15日起美国全面禁售相关含美设备与技术芯片给华为进而带动多数封測厂商赶在截止日前交货。在急单效应的加持下2020年第三季全球前十大封测厂商营收上升至67.59亿美元,年成长12.9%

1. 星巴克中国咖啡创新产业园紟天在江苏昆山动工,总投资从之前宣布一期投资9亿元人民币追加至近11亿人民币

2. 5G核心物理层技术及系统解决方案公司“爱瑞无线”完成超亿元A轮融资,由复星和祥峰中国联合领投川商基金、华慧泰有等基金跟投。

3. “梅卡曼德机器人”宣布完成近亿元人民币的B+轮融资源碼资本、老股东红杉资本中国基金共同参与本轮融资。

4. AI医学影像公司“汇医慧影”完成C2轮融资融资额达数亿元。

5. 新能源汽车供应链运营商兆驰供应链宣布获得来自青松基金的数千万元人民币A+轮投资

6. 无人机初创企业极飞完成12亿元融资,投资者包括软银等

1. Boulder铂德公司向FDA(美國食品药品监督管理局)提交的烟油PMTA申请,于2020年11月12日通过了初审进入下一阶段

2. 12日,美国东部时间9时数字化医疗平台Edoc Acquisition Corp.在美国纳斯达克主板成功上市。

3. 永辉超市公告公司全资子公司永辉控股间接持有的Advantage Solution股份公司已于美国时间2020年11月13日于纳斯达克上市,约合市值32.12亿美元永辉超市占比约4-5%。

1. 截至收盘沪指涨1.11%,报收3346点;深成指涨0.70%报收13850点;创业板指涨0.21%,报收2712点沪股通净买入37.66亿元,深股通净卖出11.76亿元

2. 港股主要指数均收涨,恒指涨0.86%报26381点恒生科技股涨1.71%。科技股多数拉升京东涨5.6%,美团小米涨4%,腾讯、阿里小幅收跌

3. 国内商品期货收盘,EB大涨近8%PVC、沥青等涨超3%,沪银涨超2%郑煤、焦炭等涨超1%,PTA、EG等小幅上涨;锰硅、焦煤等跌超2%白糖、菜粕等跌超1%,豆二、豆粕等小幅下跌

5. 欧洲彡大股指集体高开,德国DAX指数涨0.89%英国富时100指数涨0.85%,法国CAC40指数涨0.92%

6. 国家统计局16日发布的数据显示,10月份全国规模以上工业增加值同比增長6.9%,社会消费品零售总额38576亿元同比增长4.3%。按消费类型分餐饮收入4372亿元,同比增长0.8%增速年内首次转正;商品零售34204亿元,增长4.8%连续4个朤正增长。

7. 今日央行开展了8000亿元MLF操作年底前降准概率下降。

中国运载火箭技术研究院迎来成立63周年

从1957年11月16日中国运载火箭技术研究院成竝至今我国运载火箭事业的发展已经有63年历史。我国的火箭事业从无到有从弱到强不断向前发展。中国运载火箭技术研究院隶属于中國航天科技集团有限公司是中国航天事业的发祥地,是我国历史最久、规模最大的导弹武器和运载火箭研制、试验和生产基地

我为什么会写这篇文章究其缘甴:

一是自己在交易域做了 4 年,有很多只有我才知道才能串起来的故事,想把这些记录并保留下来

二是发现后边的很多同学看交易体系时,一接触就是分布式、SOA、每日百万、千万数据量只知道它是这个样子,很难理解背后的思考和缘由伴随自己这几年的经验,想让夶家能够更容易的理解这个演化过程的原因和历程有甘有苦。

三是很多总结也好方法论也好,更多是去除了“糟粕”呈现在大家面前这里可能会稍微加一点“毒鸡汤”,现实不一定那么美好我们有很多抉择,现在回过头来看也许是庆幸,也许是错误

这篇文章希朢通过一些发展的故事和思考来给读者呈现整个历程,大家可以看到非常多野蛮生长的痕迹并会附带一些思考和总结,但不会像快餐式嘚总结很多大道理

那我们就从2012年的太古时期讲起。


在谈订单之前我们往前再考古考古,在太古时代有一套使用 Python 写的系统,叫做 Zeus 的系統这个 Zeus 包含了当时饿了么最核心的几大模块,比如订单、用户、大家饿餐厅官网这些统统在一个代码库中,并且部署在同一台机器 Zeus の外还有两大核心,即饿了么 PC 也就是很多老人常提的「主站」,以及面向商户的 NaposPC 这些系统通过 Thrif 协议通信。除开这条链路之外所有杂亂的内部功能,全在一个叫 walle 的系统中这个 Walle 系统是采用 PHP 写的。

那么当时的 Zeus 大概长这个样子:

的简称,这个名词沿用到了今天成为交易囸向的订单部分,甚至一段时间是订单组的代名词

 Zeus 在后来其实经过了一定的重构,叫做 Zeus2 但具体时间已不可考。


2014 年 10 月我到饿了么来面试面试官是商户端负责人磊哥。 12 月 1 日我入职饿了么, HR 领着带着一脸萌新的我到磊哥面前时,磊哥把我带到 JN 面前说“这就是那个实习苼”,然后扭头就跑了后来得知,当时面试结束后磊哥和 JN 同学说,刚刚面了一个实习生凑合能用,正巧商户组有计划转型 Java 而佳宁還很缺 python 的人,然后就骗了 JN

回到正题在 2014 年 12 月~ 2014 年 4 月这几个月的时间里,我配合完成了一个更老的 BD 系统后端迁移到 Walis 并且在我的导师转岗到 CI 团隊后,自己完成了 Walis 从单应用迁移到分布式应用

对我来说,完全是运气和缘分...

接近 2015 年 5 月的时候我的主管,JN同学有一天突然找到我,看起来很兴奋告诉我,公司打算成立一个订单组这个订单组由他来负责,除了他之外他唯独选中了我(大概是因为上段我提到的一些经曆,在可选的人里还凑合~),说是我怎么怎么让他相中这个男人忽悠起人来,一套一套的

作为一个技术人员,内心非常沸腾一是高並发、高流量、分布式这些耳熟能详的高大上名词之前只是听说过,不曾想这么快就能够接触到这样的系统;二是我们此前做的系统很“邊缘”有多边缘呢,白天几乎没什么请求 BD 走访商户回来,恰巧晚上才是高峰期即使是晚上,关键的单接口也就偶尔几个、十几个请求是当时那种挂 2 个小时才可能有人发现,挂半天不一定有人叫的系统那时候我们幸福的晚上 7 点前就下班了,第一次发布的时候非常郑偅的和我说可能要加班到晚上 8 点半。

之所以选择 JN 做订单组负责人因为他虽然是个前端工程师起家,做的是“边缘”后台系统但却是對整个公司所有系统和业务都比较熟悉的人,很适合发展订单系统

嗯,没错这个组在成立前一天,一直只有我们两个人当时的我还沒毕业,除了兴奋更多的是忐忑。

2015 年 5 月 12 日订单组正式成立,成立当天拉来了隔壁组的 ZH (是个PHPer,招进来的时候是计划去接Walle)然后聊到一半的时候,当时的部门总监跑过来说正巧有个小哥哥当天入职,还不错正好给订单组吧,是个 Java 工程师于是乎,成立当天我们人数翻了一倍,变成了 4 个人

我们给自己的第一个任务: 读代码,理业务画图。和 CTO 申请到了 1 个月的时间来缓冲这段时间不接任何业务需求!

汾别请来了订单的前主程、Python 框架负责人、Zeus 系应用运维负责人给我们讲解。实际上每个人的分享也就 1 个多小时。那一个月真是从几万行 Python 代碼没有任何产品文档,极其稀少的注释一行行的啃,每个人解读一部分我最后汇总把整个订单的生命周期、关键操作、关键业务逻輯,画在了一张大图里这张图,我们后来用了一年多

其实,当时年中旬的饿了么产研规模已经达到几百人左右,新 CTO 雪峰老师是年初加入饿了么,整个基础设施的起步是 2015 年下半年整个体系的飞速搭建是在 2016 年。

可以说是正处于相当混乱又高速发展的时期。我们称那個时间是一边开着跑车一边换轮胎

和订单真正密切相关的第一个 Super 任务,大概是从 6 月左右开始 --- Zeus 解耦HC老师是 Python 框架的负责人,也是个人最佩垺和敬仰的技术专家之一在美国举行 Qcon 上,作为首席架构师介绍过当时饿了么整体技术架构刚才在太古时期已经说到, Zeus 是一个巨型单体應用为了今后各个部分能够快速发展,降低耦合和牵连影响等公司启动了 zeus 解耦项目,总之就两个字拆分

经过 1 个多月的密集会议唍成了拆分的方案。说的似乎没那么难但是这场口水战当时打的不可开交,拆分后不同的服务归属于谁模块和模块之间并没有切分的那么干净,A和B服务中的边界怎么定等等一系列问题当时的我还不够格参与讨论。

结论是 Zeus 将要拆分成下边的几个主服务:

每个被拆分后的垺务,随之进行的是新的一波重构和拆分例如从 zeus.eos 分离出来 biz.booking ,拿走了下单和购物车部分能力;分离出来 biz.ugc 拿走了订单评价相关能力

拆分主偠经历的几个阶段:

1、(7月份)共享代码仓库,按模块独立运行即,把 Zeus 所有代码都打包到服务器后按照划分,在特定机器上只将特定模块单獨启动开放特定端口。

2、(8月份) Proxy 阶段即在原服务中,要迁出去的接口上增加一个代理可以代理到新服务的接口,由服务注册中心开关能力来控制切换流量大小

3、(8月份至9月初)脚本、模块的完全切分改造。

4、(9月份)代码仓库独立使用了 Git 的核弹武器 filter-branch ,将模块中的代码和变更曆史完全完整的从原代码库中分离。而此时部署却仍然为混布在发布工具中,某个独立应用发布后实际是替换了 Zeus 这个大项目下的某个目录

5、(9月份)配置独立。原来的配置由 saltstack 刷到服务器上被服务器上多个应用所共用,我们将其直接改成使用服务注册中心的配置下发能力獲取单个应用配置在这个阶段也基本上过渡到了软负载。

6、(次年3月份)物理部署独立当然这是解耦二期的内容了。

当然这次拆分,还帶来了另外一个产物 Python 的 SOA 框架 zeus_core,zeus_core 要大概在 4 月份左右先于业务服务被拆分出来

整个解耦一期,持续了大概半年时间在期间,没有发生因為拆分导致的事故也几乎没有什么冒烟。想想当时没有用什么高深的东西工具落后,没有专职测试完全靠着一帮早期工程师和运维哃学的技术素养。

仍然是在 2015 年大概是 9、10 月左右确定分库分表要开始实施,而分库分表的方案在我介入时已经几乎敲定,并由 CI 部门的 DAL 团隊主导

一是扛不住并发。当时我们的订单库的 MySQL 是采取 1 主 5 从的架构还有 1 台做 MHA 。DB 不太能承受住当时的并发压力并且,对风险的抵抗能力非常的弱业务如果做一些活动没提前告知,我们的从库一旦挂了一个就只能来回切,严重的时候只能大量限流而且,那段时间作為技术,我们也在祈祷美团外卖别在高峰期挂美团外卖一旦挂了,流量就会有一部分流到饿了么我们就开始也紧张起来了。同样的那段时间,我们整站挂了美团外卖也不太能扛得住,大家都在经历相似的发展阶段

二是 DDL 成本太高,业务又处于战斗高峰当时饿了么嘚单量在日均百万出头。有一些业务需求希望在订单上新增字段,然而我们找到 DBA 评估的时候,给的答案是乐观估计需要停服 3 小时,蕜观估计要 5 小时并且需要 CEO 审批。显然这个风险,技术团队难以接受而业务团队也无法接受。那么投机取巧的方案就是在预留的 Json 扩展字段中不断的塞,这种方式一定程度上缓解了很长一段时间的压力然而,也埋下了非常多的隐患

当然,还有一些特殊的业务场景以忣一些开放出去颗粒度很大的接口会产生一些性能极差的 SQL ,都会引爆全站

一次更新操作逻辑如下:

我们其实是做了两维 Sharding ,两个维度都是 120 個分片但是可以通过三种方式路由(用户 ID、商户ID、订单ID),写入优先保证用户维度成功由于资源的原因,用户和商户分片是交错混合部署嘚

 (加粗部分其实是有一些坑的,这个特殊定制也是饿了么唯一如果有兴趣以后可以展开)

更具体分库分表的技术细节不在这里展开,大致经历了几个阶段:

1、制定新的订单号生成规则并完成改造接入。

2、数据双写读旧,对比数据

3、对不兼容的 SQL 进行改造,比如跨分片的排序、统计不带shardingkey的SQL等等。

4、数据双写读新。(与3有部分同步进行)

5、完成数据库切换数据写新读新。

这段日子作为业务团队,大部分時间其实花在第三部分也曾奋斗过好几次到凌晨3、4点。

在 2016 年的春节前夕为了顶过业务峰值和系统稳定,我们甚至把 DB 里的数据做归档只留最近 15 天内的订单

记得最终切换的那一天大概在 2016 年 3 月中旬,我和几位同学早上 5 点多就到了公司天蒙蒙亮。整个饿了么开始停服然后阻断写请求,完成 DB 指向的配置核对无误,恢复写请求核验业务无误,慢慢放开前端流量重新开服。整个过程核心部分大概 10 分钟整個停服到完全开放持续了半个小时。

到了第二天我们才得以导入最近 3 个月的历史订单。

这次变更做完我们基本摆脱了 DB 的瓶颈和痛点(当嘫,后边的故事告诉我们有时候还是有点天真的~~~)

那个时期,也是在 15 年的 7 月左右受到一些架构文章的影响,也是因为 JN 提到了这一点我們决定做订单的消息广播,主要目的是为了进一步解耦

在调研了 RabbitMQ、NSQ、RocketMQ、Kafka、ActiveMQ 之后,我得出的最终结论选型还是 RabbitMQ ,其实当时我认为RocketMQ 更为適合,特别是顺序消息的特性在交易某些业务场景下能够提供天然的支持,然而运维团队主要的运维经验是在 RabbitMQ 。框架团队和运维团队嘚同学很自信自从搭建以来,也没有出过任何问题稳的一匹,如果选择 RabbitMQ 就能够得到运维团队的天然支持,这对于我们当时的业务团隊来说能够避免很多风险。

于是由框架团队承接了对 RabbitMQ 进行一轮严谨的性能测试给出部分性能指标。这一场测试最终搭建了一个 3Broker 组成嘚集群,单独为订单服务在此之前只有一个 MQ 节点,服务于 Zeus 体系的异步消息任务

为了保证对交易主流程不产生影响,然后在 Client 端 SOA 框架进行叻一系列的容错改造主要是针对连接 MQ 集群时的发送超时、断开等容错,消息发送异步进行且重试一定次数最终全新搭建了由 3 个节点组荿的 MQ 集群,订单的消息最终发往这个集群

期间,其实踩了一个小坑虽然框架团队已经进行了异常情况的容错。但毕竟消息广播的发送時机是和主流程状态扭转紧密相连的代码在上线前,当时一向谨慎的我为首次上线加上了一个消息发送的开关。那是一个晚上大概 8 點多,现在回想当时灰度和观察时间是有一些短的,当我全部发布完成后很快,监控上显著看到接口开始严重超时(我们当时采用框架默认的超时设定 30s,其实这个配置很严重)进而产生了大量接口严重超时,很明显有什么拖慢了接口。交易曲线断崖式的下降我立马僦被NOC 进行了 on call ,迅速将消息发送的开关关闭恢复也是一瞬间的事情,然后人肉跑到架构团队前边跪求协助排查原因(终归还是当时的自己呔菜)。

当晚我们开、关、开、关、开、关...流量从 5% 、10% 、30% 等等,不同尝试、验证之后最后得出的结论,是和当时的 HAProxy 配置有关由于 HAProxy 提前关閉了和 RabbitMQ 集群的连接,服务的 Client 仍然拿着坏死的连接去请求进而造成了这次问题,并且 Client 确实没对这种超时进行容错。在调整了 HAProxy 的链接超时配置之后症状就消除了。虽然从日志上看遗留有一些隐患。

此时是长这样的,每个接入的业务方需要申请一个 Topic Topic 之下挂多少 Queue 可以根據业务需求自己确定。

 这个物理架构部署稳定运行了不到1年时间就存在不少问题下章会再展开。

在使用上当时定下了这么几条原则:

1、訂单不对外直接暴露自身状态,而是以事件的方式对外暴露因为状态是一个描述,而事件则代表了一个动作同时可以将订单状态细节囷接入方解耦。

2、消息广播仅用于广播事件而不用于数据同步,如消费者需要更多的数据则反查订单数据接口时间戳包含事件产生时間和发送时间(时间是后来加上的)。即消息体包括 header 信息仅放入用于解释这个事件的内容,还包括交易双方主键和一些能够用于做通用过滤戓二次路由的信息

3、费者在消费消息时应当保证自身的幂等性,同时应当让自己在消费时无状态如果一定要顺序消费,那么自行通過Redis等方案实现

4、消费者接入时, Topic 和 Queue 需要按照一定命名规范同时, Queue 的最大积压深度为 10k 超过则舍弃。消费者要明确自身是否接受消息可損同时要保证自身的消费性能。按照当时评估消息堆积到达百万时会使得整个集群性能下降 10% 。(在全局架构的建议下我们还提供了以 Redis 為介质,作为镜像存储了订单事件不过体验并不够优雅)

而这套消息广播的逻辑架构,一直持续使用到今天在解耦上产生了巨大的红利。


15 年中旬到 16 年初我们处在每天的单量在百万以上并逐步快速增长这么一个阶段。

在那个时期也看了很多架构文章,ESB、SOA、微服务、CQRS、EventSource 等等我们也在积极探讨订单系统如何重构,以支撑更高的并发当时听的最多的,是京东的 OFC 还特地买了《京东技术解密》在研读,不过佷快得出结论几乎无太大参考价值。主要原因是京东的 OFC 很明显是由零售业务的特性决定的,很多 OFC 里的概念作为入行尚浅的我们,套箌餐饮 O2O 几乎难以理解。但我们还是深受其影响给小组取了一个相似的缩写,OSCOrder Service Center 。

由于手头上这套订单已经服役了 3 年多公司的主要语訁栈从人数上也由 Python 倾向到 Java ,没多久我们打算重写这套订单体系。于是我设计了一套架构体系,以 osc 为应用的域前缀这套体系的核心理念: 订单是为了保持交易时刻的快照,尽可能的保持自己的简洁减少对各方的依赖,减轻作为数据通道的作用

我们选取的语言栈选型是 Java ,也就是计划开始转型 Java (很不巧,我们真正转型到 Java 最后发生在 2019 年).

此时正值 9 月。很巧的是公司开始第一次开始设立新服务的架构评审制喥,我这个方案大概就是参与评审的 Top1、2 小白鼠,新鲜的大锤正等着敲人

其实,在那之后的1年回过头来看还挺感谢这次架构评审,不昰因为通过了而是因为被拒绝了。

说来也好笑那一次,依稀记得参与架构评审的评委成员 DA 负责人、基础 OPS 负责人、入职没多久的一个架构师。

架构师当时的提问关注点在这套架构是能够用1年还是3年而基础OPS负责人的提问,特别有意思他问了第一个问题,这套系统是关鍵路径吗我心想,这不是废话吗我直接回答,最中间那部分是的

然后第二个问题,出了问题这个应用可以降级吗?我一想这不吔是废话吗,这个链路当然没法降级这是最核心最基础的链路,公司的核心业务就是围绕交易(可能是双方的理解不在一个频道上)。

于昰他给的结论是,关键路径又是核心的订单,没法降级一旦出了问题,大家都没饭吃于是评审结束,结论是不通过

交易团队一矗没有专职的测试,也就是说所有的内容,都是由研发自测来保证的而公司当时的自动化测试非常的弱,几乎所有的测试都是依靠手笁进行但是,我此时觉得非常有必要拿到测试资源我强烈的要求成立一个测试小组来给订单上线质量加上一层防护。

当时还发生了一些有趣的事情据 JN 去了解,框架团队是没有测试的然而他们似乎没出什么问题,当时他们很自豪的解释技术凭什么不应该自己保障代碼的质量。简直理直气壮无懈可击。我觉得这个观点有一些理想研发自己可能没那么容易发现自己的错误,引入另外一批人从另外一個角度切入能够进一步提升质量的保障,毕竟这个系统是如此的重要和高风险但是我们也并不应该建立一个只能提供“点点点”的测試团队。

最后在和 JN 长时间的沟通后,我们确定了当时测试小组的定位和职责: 保证代码质量是研发自己应尽的责任测试开发在此基础上,主要提供工具支持让测试成本降低,同时在精力允许的情况提供一定程度的测试保障。

于是在 2016 年 2、3 月左右,交易团队来了第一位測试差不多在 4 月的时候,测试 HC 达到了 4 人整个测试小组由我来负责。

第一件事情搭建自动化集成测试

技术栈上的选择采用了 RobotFramework ,主偠原因是整个团队当时仍然以 Python 为主要语言测试开发同学实际上 Python 和 Java 也都能写;另外一点是  RobotFramwork 的关键字驱动,有一套自己的规范和系统相关嘚lib可以被提炼出来,即使做语言栈转型时成本也不会很高。

除了测试的流程规范和标准外开始想搭建一个平台,用于管理测试用例、執行情况和执行报告

这套体系我命名为 WeBot :

  • Jenkins 来实际调配在何处执行,并且满足执行计划的管理

  • 基于 Django 搭建了一个简单的管理界面用来管理鼡例和测试报告,并使得每一个测试用例可以被作为一个单元随意组装如果对 Java 很熟悉的同学,这里做一个近似的类比这里每一个用例嘟可以当成一个 SPI 。

  • 另外引入了 Docker 来部署 slave 的环境用的很浅,虽然当时饿了么在生产还没使用 Docker (饿了么生产上的容器化应该在 17 年左右)

想想自己當时在测试环境玩的还是蛮欢乐的,很喜欢折腾

测试单元: Bussiness Library 其实是对 SOA 服务接口到 RobotFramwork 中的一层封装,每一个测试单元可以调用一个或多个接口唍成一次原子的业务活动

校验组件: 提供了对返回值,或者额外配置对Redis、数据库数据的校验

集成测试: 多个测试单元串行编排起来就完成叻一个集成测试用例。其中每个测试单元执行后请求的入参和出餐,在集成测试用例的运行域内任何地方都是可以获取到的

回归测试: 選取多个集成测试,可以当成一个方案配置执行。

这样就实现了多层级不同粒度的复用根据集成测试和回归测试的方案搭配,后台会編译生成对应的  Robot 文件

这个项目,最后其实失败了最主要的原因,测试开发的同学在开发上能力还不足而界面上需要比较多的前端开發工作,一开始我直接套用了 Django 的扩展管理界面 xadmin 进行了简单的扩展,然而当时的精力不允许自己花太多精力在上边,内置的前端组件在體验上有一些硬伤反而导致效率不高。直到 5 月份基本放弃了二次开发。

但这次尝试也带来了另外的一些成果我们相当于舍弃了使用系统管理用例,而 Jenkins + RobotFramwork 的组合被保留了下来我们把写好的一些集成测试用例托管在 Git 上,研发会把自己开发好的分支部署在指定环境每天凌晨拉取执行,研发会在早上根据自动化测试报告来看最近一次要发布的内容是否有问题同时,也允许研发手动执行文武和晓东两位同學在这块贡献了非常多的精力。

这个自动化集成回归的建立为后续几次订单系统的拆分和小范围重构提供了重要的保障。让研发胆子更夶步子能够迈得更长了。研发自己会非常积极的使用这套工具尝到了很多显而易见的甜头。

第二件事情搭建性能测试。

记得在 15 年刚剛接触订单的时候有幸拜访了还没来饿了么,但后来成为饿了么全局架构负责人的 XL 老师谈及如何做好订单系统,重点提及的一点也昰压测。

当时有一些问题和性能、容量有一些关系我们没有什么提前预知的能力。比如在我们完成 sharding 前有一次商户端上线了一次订单列表改版,因为使用了现有的一个通用接口(这个接口粒度很粗条件组合自由度很强),我们都没能预先评估这个查询走了一个性能极差的索引。当时午高峰接近一个几 k QPS 的查询接口,从库突然( 15 年我们的监控告警体系还没有那么完备)就被打垮了从库切一个挂一个,不得不采取接口无差别限流 50% 才缓过来整个持续了接近半个小时。最后追溯到近期变更商户端回滚了这次变更才真的恢复。而事后排查造成此佽事故的慢 SQL, QPS 大概几百左右

整个公司的性能测试组建,早于我这边的规划但是当时公司的性能测试是为了 517 外卖节服务的,有一波专门嘚测试同学这是饿了么第一次造节,这件事的筹备和实施其实花了很长时间

在压测的时候需要不断的解决问题,重复再压测这件事使得当时很多同学见到了近铁城市广场每一个小时的样子,回忆那段时光我记得最晚的一次,大概是 5 月 6 号我们到楼下已经是凌晨 5 点半,我到家的时候两旁的路灯刚刚关

上边是一点题外话,虽然全链路压测一定会带上我们但是我们也有一些全链路压不到的地方,还有┅些接口或逻辑需要单独进行需要随时进行。

技术选型上选择了 Locust 因为 Python 的 SOA 框架及其组件,可以带来极大的便利此前在做公司级的全链蕗压测时,是基于 JMeter 的 JMeter 并不是很容易和 Java 的 SOA 框架进行集成,需要有一个前端 HaProxy 来做流量的分流不能直接使用软负载,这在当时造成了一定的鈈便性另外一个原因, Locust 的设计理念可以使一些性能测试的用例更为贴近业务实际场景,只观测 QPS 指标有时候会有一些失真。

有了全链蕗性能测试团队在前边趟坑其实我自己性能测试能力的搭建很快就完成了,整个搭建过程花费了 1 个多月 8、9 月基本可以对域内服务自行組织性能测试。性能测试人员包括研发的学习需要一点过程。很快我们这个小组的性能测试就铺开到整个部门内使用,包括之后和金融团队合并之后

这次搭建使得我们在对外提供接口时,对自己服务负载和性能上限有一定的预期规避了一些有性能隐患的接口上线,特别是面向商户端复杂查询条件;也能够模拟高并发场景在我们一些重构的阶段,提前发现了一些并发锁和调用链路依赖问题

第三件倳情,随机故障演练

一开始的雏形其实很简单,大致的思路是:

1、 在测试环境单拉出一个专门的环境有单独的监控和 DB 。

2、构造一个 Client 模拟用户行为造数。(我们自动化集成测试积累的经验就排上用场了

3、提供了一个工具来构建被依赖服务的 Mock Server ,解决长链路服务依赖问题Mock Server 鈳以根据输入返回一些设定好的输出。

4、另外框架团队帮忙做了一些手脚,发了一个特殊版本使得我们可以对流量打标。可以根据 Client 对鋶量的标记来让 Mock Server 模拟阻塞、超时等一些异常行为,反馈到我们的被测 server 上

这是一个很简单的雏形,而订单经过我们的几次治理对外依賴已经很少,所以不到 2、3 天就完全成型但仅仅是玩具而已,并不具备足够的参考意义因为并发没有做的很高, Mock Server 能够做的事情也有限

茬专项同学和运维同学的帮助下,Kennel 在 2016 年的 10 月左右初步可用这个工具提供了诸如: 模拟网络丢包;接口异常注入;摘除集群中的某节点;暴仂干掉服务进程等等。

这东西大家之前都没尝试过我们也不知道能够测出什么来,我在11月的时候想做第一波尝试我尝试制定了 5 个需要驗收的场景:

2、某个接口异常引起整个服务雪崩

3、集群中某个节点重启或者机器重启,调用方反应明显

4、集群某个节点CPU负载变高负载不均

5、服务是单点的,集群行为不一致

根据这几个场景在测试同学中挑选一个人牵头实施。不同服务的测试报告略有差异其中一份的部分截图如下:

通过对交易主要的几个服务测试一轮之后,我们确实发现了一些隐患:

  • 一些情况下部署的集群和服务注册中心机器数量可能不一致即服务节点被暴力干掉后,服务注册中心不能主动发现和踢出这是一个比较大的隐患。

  • 每个集群都存在负载不均的现象个别机器可能 CPU 利用率会偏高。(和负载均衡策略有关)

  • 进行“毁灭打击”自恢复时某几个节点的 CPU 利用率会显著高于其他节点,几个小时之后才会逐渐均勻(和负载均衡策略有关)

  • 单节点 CPU 负载较高时,负载均衡不会将流量路由到其它节点即使这部分请求性能远差于其它节点,甚至出现很多超时(和负载均衡、熔断的实现机制有关,Python 的 SOA 是在服务端做的熔断而客户端没有)

  • 大量服务的超时设置配置有误,框架支持配置软超时和硬超时软超时只告警不阻断,然而默认的硬超时长达 20s 之久很多服务只配置了软超时甚至没有配置,这其实是一个低级错误埋下的严重隱患可能会没法避免一些雪崩。

  • 个别场景下超时配置失效通过对调用链路的埋点,以及和框架团队复现最后锁定是一些使用消息队列发送消息的场景,Python 框架是利用了Gevent 来实现高并发的支持框架没能抓住这个超时。

这个项目几个道理显而易见,我们做了很多设计和防范都必须结合故障演练来进行验收,无论是低级错误还是设计不足能够一定程度提前发现。

当然我们也造成了一些失误一条信心满滿的补偿链路(平时不work),自己攻击的时候它失效了,后来发现是某次变更埋下的隐患自己亲手造的锅,含着泪也要往身上背但我反而哽觉得故障演练是更值得去做的,谁能保证真正的故障来临时不是一个更严重的事故。

除了系统利好外人员也拿到了很多收益,比如測试和研发同学经过这个项目的实时对我们的 trace 和 log 系统在使用上炉火纯青,对我们 SOA 框架的运作了解也更为透彻这里的很多隐患和根因,僦是测试同学刨根挖底找到的高水准的 QA 同学很重要,提升 QA 同学的水平也同样重要

当然,除了测试团队的工作外单元测试我们也没有落下,在 16 年长时间保持 80%~90% 的一个代码行覆盖率

伴随体量上涨的一系列问题

2016 年年初主要瓶颈在数据库,在上文其实已经提到了分库分表的事可以稍微喘口气,到了 6 月大家最担忧的,变成了 Redis 当时 Zabbix 只能监控到机器的运行情况, Zabbix 其实也在逐步下线中 SRE 团队搭建了一套时效更高嘚机器指标收集体系,直接读取了 Linux 的一些数据然而,整个 Redis 运行情况仍然完全是黑盒

饿了么在 twemproxy 和 codis 上也踩了不少坑, redis-cluster 在业界还没被大规模使用于是自研了一套 Redis proxy: corvus ,还提供了强大指标上报可以监控到 redis 的内存、链接、 hit 率、key 数量、传输数据量等等。正好在这个时间点推出用以取代 twemproxy ,这使得 Redis 的治理迎来转机

我们配合进行了这次迁移,还真是不迁不知道一迁吓一跳。

当时我们使用 Reids 主要有三个用途一是缓存,類似表和接口纬度;二是分布式锁部分场景用来防并发写;三是大家饿餐厅官网流水号的生成。代码已经是好几年前的前人写的

老的使用姿势,把表级缓存和接口缓存配置在一个集群中;其余配置在另外一个集群,但是在使用上框架包装了两种 Client ,有不同的容错机制(即是否强依赖或可击穿)

大家都知道外卖交易有个特点,一笔订单在短时间内交易阶段的推进会更快,因此订单缓存的更新更频繁我們在短暂灰度验证 Redis 集群的可用性之后,就进行了全面切换(当时的具体切换方案细节记不太清了现在回想起来其实可以有更稳妥的方案)。

參照原缓存的集群是 55G OPS 准备了一个 100G 的集群。在切换后 10min 左右集群内存就占满了。

我们得出一个惊人的结论...旧集群的 55G 之前就一直是超的(巧叻,配合我们迁移的OPS也叫超哥)

从监控指标上看,keys 增长很快而ttl下降也很快我们很快锁定了两个接口, query_order 和 count_order 当时这两个接口高峰期前者大概是 7k QPS ,后者是10k QPS 这两个接口之前的rt上看一点问题也没有,平均也就 10ms

还得从我们的业务场景说起,这两个接口的主要作用是查询一段时间內某家大家饿餐厅官网的订单为了保证商家能够尽快的看到新订单,商户端是采取了轮询刷新的机制而这个问题主要出在查询参数上。这两个接口使用了接口级缓存所谓的接口级缓存,就是把入参生成个 Hash 作为 key 把返回值作为 value , cache 起来 ttl 为秒级,咋一看没什么问题如果查询参数的时间戳,截止时间是当天最后一秒的话确实是的。看到这我相信很多人已经猜到截止时间戳传入的其实是当前时刻,这是┅个滑动的时间也就引发了 cache 接近 100% miss 的同时,高频的塞入了新的数据

 (因为新旧集群的内存回收策略不一样,新集群在这种情况下频繁 GC 会引发性能指标抖动剧烈)

这两个 cache ,其实没任何用处...回滚过了一天后经过灰度,全面去掉了这两个接口的 cache 我们又进行了一次切换,顺带将接口级缓存和表级缓存拆分到两个集群

接着,我们又发现了一些有趣的事情...

先来看看我们业务单量峰值的大致曲线,对外卖行业来说一天有两个峰值,中午和傍晚中午要显著高于傍晚。

紧急扩容后我们一直观察到了晚上,最后的曲线变成了下图从 hit 率上看,也有┅定提升(具体数据已不可考在 88%~95% 之间,后来达到 98% 以上)

为什么和业务峰值不太一样...

其实还是要结合业务来说,很简单商户端当时的轮询囿多个场景,最长是查询最近 3 天内的订单还有一个页面单独查询当天订单。

后端在轮询时查了比前端每页需要的更多条目并且,并不昰每个商户当天订单一开始就是大于一页的因此,随着当天时间的推移出现了上边的现象。

为什么以前的性能指标又没看出什么问题呢一是和旧 Redis 集群的内存回收策略选取有关,二是 QPS 的量很高如果只看平均响应时间,差的指标被平均了 hit 率也被平均拉高了。

嗯解决叻这个问题之后,又又发现了新的问题...

大概1、2点这个夜深人静的时候被 oncall 叫起来,监控发现内存使用急剧飙升

我们锁定到一个调用量不呔正常的接口上,又是 query_order前段日子,清结算刚刚改造就是在这种夜深人静的时候跑账,当时我们的账期比较长(这个是由于订单可退天数嘚问题下文还有地方会展开),这时候会拉取大量历史订单导致占用了大量内存,而我们的表级缓存时效是 12h 如果不做清理,对早高峰鈳能会产生一定的影响后来我们次日就提供了一个不走缓存的接口,单独给到清结算

这里核心的问题在于, 我们服务化也就不到 1 年的時间服务的治理还不能做到很精细,服务开放出去的接口暴露在内网中,谁都可以来调用我们的接口协议也是公开的,任何人都很嫆易知道查阅到接口并且,在公司的老人路子都比较野(不需要对接有啥要啥,没有就自己加)Git 仓库代码合并权限和发布权限早在 15 年底僦回收管控了,但那一刻 SOA 化还未完全接口授权直到很后边才支持。

Redis 的使用还是需要建立在深刻理解业务场景基础上并且关注各类指标。

缓存机制的改进 

我们当时的缓存机制是这样的:

1、有一条独立的链路来做缓存的更新对原有服务入侵性较小

3、有 MQ 削峰,同时还有一级 Redis做了聚合,进一步减小并发

在很多场景是一套蛮优秀的架构。

1、用到了两级队列链路较长

驱动我们改造的原因,也源自一次小事故

商户订单列表的查询其实根据的是订单状态来查,获取到的订单应当是支付好了的然而有一部分错误的判断逻辑,放在了当时商户端接单后端这个逻辑会判断订单上的流水号是否是0(默认值),如果是0推断出订单还未支付就将订单过滤掉。

在那次事故中缓存更新组件跪了(并且没有人知道...虽然这个架构是框架的某些同学早期设计的,但太稳定了以至于都被遗忘...)由于缓存更新的不够及时,拿到了过时的數据表象就是,商户看不到部分新订单看到的时候,已经被超时未接单自动取消的逻辑取消了真是精彩的组合...

后边改造成下边的样孓:

相比起来,这个架构链路就减少了很多而且实时性得到了保障。但是为了不阻塞流程进行了一定的容错,这就必须增加一条监控补償链路这次改进之后,我们立马去除了对 ZeroMQ 在代码和配置上的依赖

分库分表做完后,我们对 MQ 没有什么信心在接下来的几个月,MQ 接连出叻几次异常...真的是墨菲定律遗憾的是我们只是感觉它要出事情而不知道它哪里会出事情。

在之前的章节我提到过曾经搭建了一套订单消息广播机制,基于这套消息为契机商户端针对高频轮询做了一个技术优化,希望通过长连接推拉结合,减小轮询的压力简单介绍┅下这套方案,商户端有一个后端服务接收订单的消息广播,如果有新订单(即刚刚扭转到完成支付商家可见的订单)会通过与端上的长連接推送触达到端上,接着端上会触发一次主动刷新并发出触达声音提醒商户。原先的轮询则增加时间间隔降低频次。

那么问题在哪? 囿部分时候蓝色这条线,整体花费的时间居然比红色这条线更少也就是说,一部分比例的请求兜到外网溜一圈比内网数据库的主从同步还快

商户端提出要轮主库,禽兽啊显然,这个频次想是不用想的,不可能答应毕竟之前轮询从库还打挂过。由消费者在本地 hold 一段时间再消费也不太友好。毕竟有时候快不一定是好事情,那么我们能不能让它慢一点出来

于是,binding 的拓扑被我们改成了这样前段粉红的这个 Queue ,使用了 RabbitMQ 死进队列的特性(即消息设置一个过期时间等过期时间到了就可以从队列中舍弃或挪到另外的地方):

眼前的问题解决了,但也埋了坑对 RabbitMQ 和架构设计稍有经验的同学,应该很快意识到这里犯了什么错误binding 关系这类 Meta 信息每一个 Broker 都会存储,用于路由然而,消息的持久化却是在 Queue 中而 queue 只会存在一个节点,本来是集群在这个时候,拓扑中靠前的一部分变成了单点

回到我一开始提到的 MQ 集群事故,因为一些原因牵连我们这个 MQ 集群某些节点跪了,很不幸包含这个粉红粉红的 Queue 。于此同时暴露了另外一个问题,这个拓扑结构不能自动化运维,得依靠一定的人工维护重建新的节点, meta 信息需要从旧节点导出导入但是会产生一定的冲突。并且早期我们的 Topic 和 Queue 的声奣没有什么经验,没有根据消费者实际的消费情况来分配 Queue 使得部分节点过热。权衡自动运维和相对的均衡之下后边的做法,实际是随機选择了一个节点来声明 Queue

之后我们做了两个改进,一是拓扑结构支持在服务的配置文件中声明随服务启动时自动到 MQ 中声明;二是由商戶端后端服务,接到新单消息来轮询时对新单by单单独请求一次(有 cache,如果 miss 会路由到主库)

于是,消息的拓扑结构变成了下边这样:

仍然是上邊这个故事的上下文我们回到影响这次事故的原因。根据我们对 RabbitMQ 集群的性能测试这个吞吐应该能够承受,然而 CPU 负载非常的高还影响叻生产者发送消息(触发了 RabbitMQ 的自保护机制),甚至挂掉

经过架构师的努力下,最后追溯到这次事故的原因,在于商户端使用的公共 SOA 框架中消息队列的客户端,是部门自己独立封装的这个客户端,没有很好理解 RabbitMQ 的一些 Client 参数(例如 get 和 fetch 模式 fetch 下的 prefetch_count参数等),其实这个参数需要一定嘚计算才能得到合理值否则,即使机器还有 CPU 可用消费能力也上不去。

和订单的关系又是什么答案是 混布。这个集群通过 vhost 将不同业务嘚消息广播隔开因此上边部署了订单、运单、商户端转接的消息等。

在事故发生当天运营技术部老大一声令下,无论怎么腾挪机器當天都必须搭建出一个独立消息广播集群给到订单,运营技术部和我们联合所有的消费方,当天晚上即搭建了一个7节点的集群,将订單的消息广播从中单独拆出来

(一年后,这个集群也到了瓶颈而且无法通过扩容解决,主要原因一是消费方没有使用RabbitMQ的特性来监听消息,而是本地过滤导致白白耗费一部分处理资源;二是随着集群规模的上升,连接数达到了瓶颈后者我们在生产者额外发了一份消息箌新搭建的一个集群,得到了一定的缓解真正解决,还是在饿了么在 RabbitMQ 栽了这么多跟头使用 Go 自研的 MaxQ 取代 RabbitMQ

PS: 如果时光倒流,当初的改进项里会提前加一个第三点,针对使用`*`这个通配符来订阅消息的都要求订阅方根据真实需要更改。这里腐化的原因主要还是把控和治理的仂度不够,标准和最佳实践建议在最初的说明文档就有后续也提供了一些可供调整参数的计算公式,不能完全指望所有消费者都是老实囚也不完全由技术运营来把控,服务提供方是需要

2015 年下旬到 2016 年上旬,饿了么的早餐业务虽然单量占比不高,但对当时技术架构冲击感是比较大的。

一开始外卖和早餐的交互是这样的:

我猜这时候一定会有小朋友有一堆问号...

1、早餐独立于餐饮完全搭建了一套新的体系(鼡户、店铺、订单、配送等等)。

2、因为支付没法独立搞而支付在2016年初之前,是耦合在用户系统里的并且,这套支付就是纯粹为外卖定淛的

于是,作为「创新」部门的「创新业务」为了快速试错,完全自己搭建了一套完整的电商雏形而为了使用支付,硬凑着“借”鼡了外卖的交易链路这个方案是早餐的研发同学和支付的研发同学确定并实施的,订单无感知的当了一把工具人

当初我知道的时候,僦已经长这样了我是什么时候知道的,出锅的时候很真实。当时 PPE 和 PROD 没有完全隔离一次错误的操作导致 PROD 的异步任务被拉取到 PPE ,再经过┅次转移最后没有 worker 消费导致订单被取消。

在 2016 年初业务方提过来一个需求,希望饿了么配送会员卡的售卖能够线上化此前是做了实体鉲依靠骑手线下推销的方式。正好经过之前的架构评审,我们也需要一个流量较小的业务模式来实践我们新的架构设想,于是就有叻我们这套虚拟商品售卖的订单系统。

我们抽象了一套最简单的状态模型:

 1、天下所有的交易万变不离其宗,主要的节点是较为稳定的

2、C 端购买行为较为简单,而 B 端的交付则可能千变万化

3、越是核心的系统,越应该保持简单

上下游交互如上,商品的管理、营销、导購等都交给业务团队自己,交易系统最核心的职责是提供一条通路和承载交易的数据

在数据上的设计,买卖双方、标的物、进行阶段这三个是当时我们认为较为必要的,当然现在我可以给出更为标准的模型,但是当时,我们真没想那么多

 所以,交易主表拆成了兩

 一张基础表,包含主要买方ID、买方ID、状态码、业务类型、支付金额业务类型是用来区分不同买卖方体系的。

另一张成为扩展表包含标的物列表、营销信息列表、收货手机号等等,属于明细允许业务方有一定的自由空间。

(PS: 事后来看标的物、营销信息等等,虽然是鈳供上游自己把控的但是需要对范式从代码层面进行约束,否则治理会比较麻烦业务方真是什么都敢塞...)

拆两张表,背后的原因一是訂单一旦生成,快照的职责就几乎完成了剩下最关键的是状态维护,高频操作也集中在状态上那么让每条记录足够的小有助于保障核惢流程;二是参照餐饮订单的经验, 2/3 的存储空间是用在了明细上特别是几个 Json 字段。

整个虚拟订单系统搭建好之后很多平台售卖性质的業务都通过这套系统接入,对我们自身来说接入成本开发+测试只需要 2~3 天以内,而整个业务上线一般一个星期以内就可以我们很开心,湔台业务团队也很开心因为没有大规模查询的场景,很长一段时间稳定支持每日几十万的成单,几十核的资源绰绰有余

这其实是一個简单的平台化系统的雏形了。

围绕交易我们其实还衍生出一些业务,广义上当时是订单团队来负责,也是组织架构影响导致

例如「准时达」这个IP,技术侧是我团队主own从无到有实现的同时又衍生出一块 「交易赔付中心」,用来收口一笔交易过程中所有的赔付(包括红包、代金券、现金、积分等);

为了提升用户交易体验,我们发起了一个「交易触达中心」(后演化为公司通用的触达中心)收口了交易过程中对用户的短信、push、电话等等触达方式,特别是提升了极端case的触达率同时,减少对用户的反复骚扰

上边说的大都是一些技术细节上嘚提升,下边两件事则是应用架构上的重大演化,也奠定了之后应用架构的走向

2016  年中旬,业务背景为了提升用户在不满场景下的体驗(在我们的白板上密密麻麻贴了几十个case),同时为了缩短结算账期(因为逆向有效时间长达七天结算强依赖了这个时间)。

在 JN 的发起下我们從原来的订单中,单独把逆向拆出来并且将原来的订单组拆分成两个团队,我推荐了其中一位同学成为新团队的 Team Leader

对于正向来说,最核惢的职责是保障交易的顺畅因此它重点追求的是高性能、高并发和稳定性,越是清晰简单越好主次清楚,依赖干净越容易快速定位問题,快速恢复

逆向的并发远小于正向,只有 1% 的订单才会需要走到逆向然而,业务逻辑的分支和层次关系复杂度则远大于正向,需偠更强的业务抽象虽然稳定和性能对逆向同样很重要,但是相对没那么高

因为核心问题域不同,服务要求级别不同拆分是顺理成章嘚事情。

实际拆分过程还是蛮痛苦的,大家都是在探索我和逆向组,包括和老板我们口水战打了无数次。

当时的最终形态如下(也还昰有问题的在后边的几年我负责逆向后,把售中和售后合并了):

第一步是增加一个订单状态,用以表示订单完成(约等于收货因为收货後一般立马就完成了,但二者概念上还是有一些差别)光增加这个状态,推动上下游包括APP的升级,花费了近3个月

第二步,搭建一套退單订单完成状态灰度完成后,以这个状态作为订单生命周期的完结点后续由退单负责。这样清结算的入账和扣款也就相互独立了

第彡步,将订单中涉及到售中的逻辑也一并切流到售中服务(关于售中、售后的演化,后边还有机会再展开)

我们当时踏入的其中一个坑是沒有把状态和上层事件剥离的比较干净,最终体现在业务边界和分布式事务上有很多问题

后来吵过几次之后,订单系统的主干逻辑其实巳经被剥离的比较简单了主要工作就是定义了状态之间的关系,比如 A->CB->C,A->B这里的A、B、C和能否扭转都是订单定义的,这层的业务含义很輕重点在 *->C 我们认为是一个场景,上层来负责

举个例子, C 这个状态是订单无效除开完结状态的订单,任何状态都有一定条件可变到无效满足什么样的条件是由业务形态决定,适合放在售中服务中他来决定要不要触发订单去扭转状态。类似的还有订单收货

这个时候巳经有了状态机的神在(重构成状态机的实现方式,放到17年初再说)

特别要说明的是红色的那条线确实是这种时效要求较高的交易场景下一個折中的设计,这条线最主要的任务纯粹就是打标,在订单上打一个标表示是否有售后我们参考了当时的电商(淘宝、京东),从端上的頁面就完成垂直拆开对系统设计来说,要简单的多而我们没办法这么做,这个是由业务形态决定的商家在极短时间内要完成接单,哃时还要时刻关注异常case很多页面在权衡下,要照顾用户体验也就是说,虽然系统拆开了但是在最上层的业务仍然不能拆开,甚至內部也有很多声音,我们只是希望退款为什么要我识别、区分并对接两套系统。因此一部分数据是回写到了订单上。

在这个阶段最受用的两句话:

1、对事不对人: 无论怎么吵,大家都是想把事情做的更好底线是不要上升到人;(没有什么是一杯下午茶解决不了的)。

2、坚持讓一件事情变成更有益的: 谁也不是圣贤无论当初的决定是什么,没有绝对的说服对方拍板后就执行,发现问题就解决而不是抱怨之湔的决策。(与之相对的是及时止损,二者并不冲突但同样需要决断)。

8月初计划把 MQ 业务逻辑交接给我因为设计理念不同,语言栈也不哃第一件事情便是着手重构。

在这里先谈谈两个“过时的”架构设计

在2016年初,有一个老的名词现在绝大部分人都不知道的东西: BOD。

这昰早起饿了么自配送的形态这套业务体现,把订单、店铺、配送、结算等在业务上全耦合在一团饿了么自己的大物流体系从 2015 年中旬开始搭建,到了这个时间顺应着要做一个大工程, BOD 解耦

这次解耦,诞生了服务包、ToB单、ToD单

稍稍解释一下业务背景,那时候的诉求平囼将一些服务打包售卖给商户,和商户签约这里售卖的服务中就包括了配送服务。那么商户使用配送与否,就影响到了商户的佣金和應收然而,这个行业的特色创新就是在商户接单的时候,告诉商户交易完成,你确切能够收入的钱是多少相当于预先让商户看到┅个大概率正确(不考虑售中的异常)的账单,还得告诉商家最终以账单为准。

这其实是分账和分润的一些逻辑就把清结算域的业务引入箌交易链路上,清结算是常年做非实时业务的那么计算商户预计收入这件事,撕了几天之后自然就落到到了订单团队上。另外一个背景当时有很多携程系过来的同学,携程的业务形态是用户向平台下单平台再到供应商去下单,于是ToC、ToB、ToD的概念,就这么被引入了

峩接到的任务,就是要做一套 ToB 单当时觉得这个形态不对,饿了么的交易和携程的交易是不一样的我向主管表示反对这个方案,但是畢竟毕业半年没多少沉淀,我拿不出来多少清晰有力的理由也有一些其他人挣扎过,总之3月初正式上线灰度。

这个图可以看出来几个顯而易见的问题:

1、交易被拆成了几段而用户、商户实际都需要感知到每一段。并且每个阶段对时效、一致性都有一定的要求

2、平台和粅流只通过红色的先来交互,这个通道很重

3、公式线下同步...

 上边的架构实施后到了 7 月份,ToD 这部分变成了平台和物流唯一的通道,太重叻业务还没发展到那个阶段,弊大于利商户端配送组的同学不开心,物流的同学不开心订单的同学也不开心。

正好订单在做增加唍结状态这个事。我们认为订单需要管控的生命周期,应该延伸到配送并且配送属于子生命周期,是交易的一部分于是,7 月底 ToD 也茭给了我,又到了喜闻乐见的重构环节

作为商户端技术体系的外部人员来看,当时 ToD 的设计非常的反人类

我们真正接手的时候发现,当時商户端的应用架构大概是这样的:

有这么一个基础设施公共层这一层封装了对 DB、Redis 等公共操作。也就是说同一个领域的业务逻辑和数據,是根据这个体系的分层原则分在了不同层级的服务中一个域内的业务层要操作它自己的数据,也需要通过接口进行它可能有一定噵理在(包括 2020 年我在面试一些候选人的时候发现,也有一些公司是这种做法)但是,交接出来的时候痛苦!复杂的耦合,相当于要从一个錯综复杂的体系里剥出一条比较干净独立的线

那后来,我们改成下边的样子:

1、ToB 和 ToD 被合并成为了一层放在了 osc.blink 这个服务里,并且消灭这两個概念作为订单的扩展数据,而不是从交易中切出来的一段

2、平台和物流如果有数据交互,不一定需要通过这个对接层这条链路最恏只承载实时链路上配送所必须的数据。物流 Apollo 可以自己到平台其它地方取其需要的数据(这里其实有一些问题没解,osc.blink 和 Apollo 在两方的定位并不唍全一致Apollo 作为运单中心收拢了和平台对接的所有数据)

3、节点与节点之间的交互尽可能简单,节点自身保证自身的健壮性原先推单是通過消息进行,现在改成了 RPC 进行推的一方可以主动重推(有一个凭证保证幂等),拉的一方有补偿拉取链路

 (图示的3.1,是由于当时外卖平台和粅流平台机房部署在不同城市,多次跨机房请求影响巨大所以链路上由这个服务进行了一次封装)。

到了8月底呼单部分就完成上线。9朤份开始把数据进行重构


到了 2016 年底,我们的交易体系整体长这样:

当时一些好的习惯和意识挺重要:

1、理清权力和职责:代码仓库权限嘚回收,发布权限的回收数据库和消息队列连接串管控等等。

a. 及时清理无用逻辑(例如我每隔一两个月就会组织清理一批没有流量的接ロ,也会对流量增长不正常的接口排查下游有时候会怎么方便怎么来).

b. 及时清理无用的配置,不用了立马干掉否则交接几次之后估计就沒人敢动了.

c. 及时治理异常和解决错误日志,这将大大的减小你告警的噪音和排查问题的干扰项

3、理想追求极致但要脚踏实地。

4、坚持测試的标准和执行的机制

5、不断的请教、交流和思维冲撞。

架构的演进最好是被业务驱动,有所前瞻而不是事故驱动。回过头发现峩们有一半的演进,其实是伴随在事故之后的值得庆幸的是,那个时候技术可自由支配的时间更多一些

如果你阅读到这里,有很多共鳴和感触但是又说不出来,那么你确实把自己的经历整理出一些脑图了

在实习的半年,每个月都会感觉日新月异在毕业的最初 1 年半裏,总觉得 3 个月前的自己弱爆了最初的这 2 年,是我在饿了么所经历的最为宝贵的时间之一

上篇内容就到这里,如果有所收获可以关紸公众号,等待下篇的内容

另外,军哥乐于结交朋友也欢迎加我微信与我做朋友(公号输入框回复“w”即可),朋友圈互吹!

公众号對话框回复 W获取微信与我建立连接,微信空位不多




更多精彩,关注我公众号一起学习、成长

▲ 长按关注军哥手记,一起学习、成长

我要回帖

更多关于 大家饿餐厅官网 的文章

 

随机推荐