当你在云原生环境下开发分布式系统…

2023-06-02 0 280

当你在云原生环境下开发分布式系统…

迪罗尔和小睿 generated by Midjourney

责任编辑讲诉了ML system技师“迪罗尔”和排序架构技师“小睿”在云原生植物自然环境下合作开发网络通讯的故事情节。本故事情节确有其事,意在表明如前所述Ray合作开发分布式控制系统的单纯性和可用性。

市场需求

迪罗尔是两个ML system技师,平常采用最少的C语言是Python。前段时间顾问交予他两个各项任务:“合作开发两个AutoML Service,为子公司的组织机构提供更多单纯功能强大并高效的AutoML各项任务网络连接服务项目。”

领到那个各项任务后,迪罗尔具体来说预测了市场需求,展开了控制系统设计:

整座服务项目须要两个出口处,能重新命名为“proxy”,提供更多服务项目允诺Request和服务项目结论查阅QueryUSB;

他们提供更多一个“client”方便快捷采用者软件控制系统,类似于SDK,透过服务项目辨认出与“proxy”展开可视化;

考虑到每一AutoML各项任务单厢在runtime展开多结点虚拟化,他们为每一各项博尔兹纳区两个“trainer”展开协同和调度;

或者说继续执行训练各项任务的是两个个“worker”民主化;

子公司基础建设早已云原生植物化,大部份模块的天然资源透过Kubernetes展开灵活性运维。

迪罗尔还画了两张洼瓣,并在洼瓣中记号了整座控制系统的各项任务流:

当你在云原生环境下开发分布式系统…

迪罗尔预测了整套网络通讯的特点:

当你在云原生环境下开发分布式系统…

云原生植物:整座控制系统云原生植物化,依赖K8S Pod的交付能力,天然资源灵活性化;

动态化:控制系统会在运行时展开大量天然资源的申请,天然资源申请规格和数量不固定;

多角色:控制系统中角色较多,不同角色间透过不同的功能共同协作完成分布式各项任务;

有状态:控制系统中存在多种有状态的角色;

频通信:控制系统中不同角色或模块间须要频繁展开通信。

迪罗尔在团队的架构会上分享了整座AutoML Service的架构设计,得到了团队同学的认可,顾问对该架构也表示满意,迪罗尔非常开心。顾问问迪罗尔AutoML Service什么时候能合作开发好,迪罗尔信心满满,答应顾问2周时间内完成。

技术栈

接下来,迪罗尔开始了为期2周的合作开发。他具体来说须要预测技术栈,选择一套合适的技术来完成整套网络通讯。他的思考过程如下:

要想实现整套网络通讯,具体来说须要实现两个个单点应用。AutoML Service里的“proxy”、“trainer”和“worker”都能看作独立的单点应用。考虑到自己最熟悉的C语言是Python,迪罗尔选择透过Python合作开发这些单点应用。

对于“proxy”和“trainer”来说,民主化内部须要解决并发和异步IO问题。迪罗尔之前用过asyncio,对于Python协程的采用早已是轻车熟路了。

有了单体应用后,迪罗尔想到,接下来须要考虑模块间通信的问题。迪罗尔调研了一番辨认出,Protobuf+gRPC是非常主流的实现方式,所以选择了此方案。迪罗尔之前虽然没有用过gRPC,但透过阅读官方tutorial,辨认出软件控制系统RPC架构并没有那么复杂,所以还是信心满满。另外迪罗尔还想到控制系统间可能会传输一些Python的数据结构,如numpy,无法直接用Protobuf,须要引入Pickle做一层序列化。

接下来,迪罗尔想到了另外两个问题:为了防止AutoML各项任务的结论数据丢失,是不是须要网络连接存储控制系统?迪罗尔听说隔壁团队经常透过RocksDB做本地的持久化存储,用HDFS做远程的持久化存储。但迪罗尔没有接触过这些控制系统,有点无从下手。这时候迪罗尔早已开始紧张起来了,他开始担心整体研发的工作量。

接下来的问题,更是让迪罗尔陷入焦虑。迪罗尔知道子公司早已全面采用K8S,但自己没有或者说采用过,所以请教了顾问,如何采用K8S部署AutoML Service。顾问又预测了一下洼瓣,意味深长地说:“你看,你整座控制系统是高灵活性的,并且是在运行时也会展开天然资源申请和释放,这就表明你的应用不仅须要初始化的时候透过kubectl展开部署,还须要在运行时与K8S apiserver展开频繁可视化呀。他们最好用Operator的形式,合作开发两个AutoML operator来做这件事情。” 迪罗尔一脸懵,问到:“还要合作开发operator?但我没有写过Go呀!” 顾问接着说:“Operator模式意在记述(正在管理两个或一组服务项目的)运维人员的关键目标。这些运维人员负责一些特定的应用和 Service…” 迪罗尔越听越迷糊,跟顾问说回去学习一下K8S再过来请教。

除了以上问题,迪罗尔还想到要网络连接监控控制系统。了解了下子公司里其他应用都是采用Prometheus和Grafana两件套,迪罗尔也决定采用此方案。

当你在云原生环境下开发分布式系统…

代码实现

技术栈选择好后,迪罗尔赶紧进入研发状态。从自己最熟悉的python代码开始合作开发,编写单体应用“proxy”,“trainer”,“worker”的内部逻辑,然后定义通信协议……

从C语言的角度看,整座实现过程中,迪罗尔至少须要编写以下5种语言的代码:

Python:单体应用的核心合作开发语言,AutoML各项任务的处理、训练过程的实现等;

Protobuf:定义“client”与“proxy”之间,“proxy”与“trainer”之间,“trainer”与“worker”之间的通信协议,然后透过codegen生成Python代码软件控制系统到应用内;

Dockerfile:定制各个模块的运行时自然环境依赖,比如python3.9,训练须要的pip包依赖等;

Go:AutoML operator的实现,CRD的定义,http灵活性服务项目等;

YAML:AutoML operator配置,AutoML Service初始化配置、灵活性配置等。

当你在云原生环境下开发分布式系统…

或者说合作开发后,迪罗尔才意识到了是自己严重低估了控制系统的合作开发量和复杂度,眼看2周的时间马上就要到了,自己才刚刚合作开发完单体应用和通信过程,还在学习K8S相关基础知识。

转折

迪罗尔非常沮丧,又去找顾问展开沟通,看看能不能把研发交付的时间延长1~2周。这时候,团队新入职的同学小睿发经验。” 他向迪罗尔了解了下情况,然后总结到:

“你要实现的是两个非常典型的网络通讯。其中包括一些网络通讯通用能力的构建,包括:模块通信、数据存储、部署、天然资源运维、故障恢复、运维与监控等。这些通用问题非常常见,几乎大部份的复杂网络通讯单厢遇到。如果靠每一控制系统的研发团队自己去解决上述问题,那会消耗非常多的精力,并且往往最终的实现在效率和稳定性上很难保证。”

迪罗尔似乎听懂了小睿的意思,问到:“那该怎么办呢?最佳实践是什么?”

小睿继续说道:“他们能把这些网络通讯的通用问题交予Ray来解决,这样团队就能把大部分的研发精力投入到或者说的业务逻辑上啦!”

当你在云原生环境下开发分布式系统…

研发精力投入的转变

迪罗尔追问到:“Ray?Ray是什么?好学吗?

小睿回答到:“Ray的API非常单纯,我给你大概讲一下你就明白啦!”

小睿开始介绍起来:

当你在云原生环境下开发分布式系统…

从历史上看,Ray是由加州大学伯克利分校RISELab在2017年发起的开源项目,开源以来取得了不错的活跃度,目前Contributors数量800+,Stars数25k+。

从功能上看,Ray是两个通用的分布式排序引擎,它的Core部分的主要设计思想是:“不绑定任何的排序模式,把单机编程中的基本概念展开分布式化”。具体来说,就是能将单机编程中的Function映射成网络通讯中的Task,把单机编程中的Class映射成网络通讯中的Actor。它的USB非常的单纯功能强大,如下:

当你在云原生环境下开发分布式系统…

分布式Task

当你在云原生环境下开发分布式系统…

分布式Actor

能看出,Ray的分布式编程API并没有改变采用者单机编程的习惯,仅仅透过单纯的改动,就能将单机程序改造成分布式程序。

迪罗尔跟着小睿学习了Ray的USB后,豁然开朗:“Ray中的Task是一种无状态排序单元Actor是一种有状态排序单元,我能这样理解吗?”

小睿肯定到:“非常正确!”

迪罗尔继续说:“那我是不是能透过Actor实现AutoML Service中的proxy和trainer,然后透过Task实现AutoML Service里的worker呢?”

小睿回答到:“能的!开始合作开发吧!”

迪罗尔重新绘制了洼瓣,在Kubernetes之上增加了Ray作为分布式底盘,然后透过Ray的Actor和Task实现相关的模块:

当你在云原生环境下开发分布式系统…

接下来,迪罗尔和小睿具体来说在子公司的Kubernetes自然环境部署了两个Ray集群。Ray集群的部署非常单纯,能透过Ray封装的命令行工具实现一键部署,部署平台除了Kubernetes,还能选择各大主流云厂商:

当你在云原生环境下开发分布式系统…

然后就是具体的应用合作开发。根据洼瓣,他们从右向左开始实现。

具体来说实现“worker”的逻辑:定义两个单机可运行的Function,Function内部逻辑即透过训练集和测试集做一次训练和评估。能透过@ray.remote将Function转换成Ray Task:

当你在云原生环境下开发分布式系统…

worker实现

然后实现“trainer”的逻辑:定义两个Trainer Class,其中成员函数train封装了对上述“worker”分布式Task的并发调用。透过@ray.remote将Class转换成Ray Actor:

当你在云原生环境下开发分布式系统…

trainer实现

然后实现“proxy”的逻辑:定义两个Proxy Class,其中成员函数do_auto_ml封装了对上述“trainer”分布式Actor按需部署与调用。同样透过@ray.remote将Class转换成Ray Actor:

当你在云原生环境下开发分布式系统…

proxy实现

“client”的逻辑:“client”的主要交换对象是“proxy”。具体来说透过ray.get_actor对“proxy”展开服务项目辨认出,然后直接调用Actor的remote方法展开服务项目访问与结论查阅:

当你在云原生环境下开发分布式系统…

client实现

至此,AutoML Service的全部流程合作开发完成!接下来他们看一些细节:

定制天然资源:AutoML Service中的每一单点应用可能会有差异化的天然资源定制市场需求,比如“worker”须要展开训练,可能会用到GPU;而“proxy”和“trainer”更多的是控制逻辑,分配相应的CPU即可。这部分的市场需求在云原生植物自然环境下是透过Yaml文件指定的,而在Ray中更为单纯灵活,直接在代码中指定即可。迪罗尔透过Ray的天然资源定制USB为每一模块设置了相应的天然资源:

当你在云原生环境下开发分布式系统…

定制天然资源

自然环境依赖:同样的,AutoML Service的每一单点应用可能会有差异化的自然环境定制市场需求。Ray中的运行时自然环境定制USB非常灵活,插件也非常丰富,可以满足不同维度、不同语言和不同场景的运行时自然环境要求。迪罗尔透过runtime envUSB为不同的单点应用定制自然环境,如“worker”,须要python3.9和一些pip包依赖:

当你在云原生环境下开发分布式系统…

自然环境定制

运维与监控:最后,迪罗尔透过Ray Dashboard观察了整座网络通讯的运行情况和日志,并且透过内置的MetricsUSB和Grafana大盘对控制系统指标展开监控:

当你在云原生环境下开发分布式系统…

运维与监控

至此,迪罗尔早已完成了AutoML Service初版的合作开发。令他震惊的是,整座合作开发仅耗时2天!更为令他震惊的是,整座应用仅不到300行代码

迪罗尔非常激动,或者说体会到了如前所述Ray合作开发网络通讯的单纯性和可用性,他非常感谢小睿的帮助。

总结

事后,迪罗尔和小睿做了两个实验。他们一起将迪罗尔之前透过原生植物方式合作开发的版本展开了完善,最终也形成了两个能跑的版本。他们对两种方式展开了对比

原生植物方式

Ray的方式

研发效率

15人天

2人天

代码

Python 800行

Protobuf 100行

Dockerfile 50行

Go 1100行

YAML 300行

Python 260行

特点

多语言

多程序出口处

应用、运维部署、配置解耦

单语言

两个main函数,单程序出口处

应用、运维部署、配置融为一体

两种实现方式的Demo地址

原生植物方式实现代码:https://github.com/SongGuyang/ray-python-example/tree/main/automl_service/cloud_native

Ray方式实现代码:https://github.com/SongGuyang/ray-python-example/tree/main/automl_service/ray

备注:研发效率中的人天数据包含相关技术的学习时间;此Demo中的实现并没有包含Fault tolerance功能,期待后续更新。关于他们

Ray中文社区由Ray开源社区核心成员维护,微信交流群已建立。目前群成员已有几百人,日常交流十分活跃。欢迎大家添加“Ray小助理”申请入群。

当你在云原生环境下开发分布式系统…

Ray Forward Meetup 2023 即将在2023年7月1日举办,议题火热征集中!包括Anyscale开源负责人和蚂蚁Ray团队负责人等多国内外Ray社区资深专家报名,说出你和Ray的故事情节!

当你在云原生环境下开发分布式系统…

Ray Forward Meetup 2023 议题征集

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务