精华内容
下载资源
问答
  • 该文档来自MDCC 2016中国移动开发者大会。冯森林发表了题为“回归初心,从容器化到组件化”的主题演讲,欢迎下载!
  • 外卖客户端容器化架构的演进

    千次阅读 2020-09-30 20:01:48
    总第413篇2020年 第37篇好的架构要不断演变,进而去适应业务的发展。美团在移动端上的架构,也经历了组件化、平台化、RN混合化,到现在开始向容器化变迁。容器化架构充分地利用了现在的跨...

     

    好的架构要不断演变,进而去适应业务的发展。美团在移动端上的架构,也经历了组件化、平台化、RN混合化,到现在开始向容器化变迁。容器化架构充分地利用了现在的跨端技术,将动态化的能力最大化地赋予了业务。

    作为美团最为重要的业务之一,美团外卖移动端的架构演进是怎样的呢?本文将为你揭开背后的思考、技术细节以及实践。

    中秋国庆双节喜临,美团技术团队祝大家节日快乐~~

    1. 背景

    1.1 移动端跨平台技术的介绍

    移动端的跨平台技术不是一个新话题,早在几年前,WebView容器、React Native、Weex、Flutter、小程序等移动端跨平台框架就风起云涌。为什么跨平台这么有吸引力呢?我们设想一下如果可以做到一次开发,多端复用,那么对于公司来说,就可以降低用人成本。对于开发来说,只需要学习一个框架,就可以在Android和iOS双平台上开发。节约下来的成本,可以投入到产品快速验证、快速上线。这对所有人来说都有着极大的吸引力。本节先针对部分移动端跨平台技术进行一些简要的介绍,以便读者能够更好地理解后面的内容。

    1.1.1 WebView容器

    WebView容器的工作原理是基于Web技术来实现界面和功能,通过将原生的接口封装、暴露给JavaScript调用,JavaScript编写的页面可以运行在系统自带的WebView中。这样做的优势是,对于前端开发者比较友好,可以很快地实现页面跨端,同时保留调用原生的能力,通过搭建桥接层和原生能力打通。但这种设计,跨端的能力受限于桥接层,当调用之前没有的原生能力时,就需要增加桥。另外,浏览器内核的渲染独立于系统组件,无法保证原生体验,渲染的效果会差不少。

    1.1.2 React Native

    2015年,Facebook推出了React Native,一经推出就备受关注。它的思路是最大化地复用前端的生态和Native的生态,和WebView容器的最大区别在于View的渲染体系。React Native抛弃了低效的浏览器内核渲染,转而使用自己的DSL生成中间格式,然后映射到对应的平台,渲染成平台的组件。相对WebView容器,体验会有一定的提升。不过,渲染时需要JavaScript和原生之间通信,在有些场景可能会导致卡顿。另外就是,渲染还是在Native层,要求开发人员对Native有一定的熟悉度。

    1.1.3 Flutter

    2018年Google推出Flutter,通过Dart语言构建一套跨平台的开发组件,所有组件基于Skia引擎自绘,在性能上可以和Native平台的View相媲美。Flutter站在前人的肩膀上,参考了React的状态管理、Web的自绘制UI、React Native的HotReload等特点,同时考虑了与Native通信的Channel机制、自渲染、完备的开发工具链。Flutter与上述Recat Native、WebView容器本质上都是不同的,它没有使用WebView、JavaScript解释器或者系统平台自带的原生控件,而是有一套自己专属的Widget,底层渲染使用自身的高性能C/C++ 引擎自绘。但大部分移动端发展到今天,都已经形成了自己的架构,在现有基础上加上Flutter,会形成原有架构和Flutter双平台共存的问题。目前,对新的App来说,是最被看好的跨端方案。

    1.2 美团外卖业务介绍

    作为中国领先的生活服务电子商务平台,美团致力于用科技连接消费者和商家,提供服务以满足人们日常“吃”的需求,并进一步扩展至多种生活和旅游服务。而作为公司最为重要的业务之一,美团外卖从2013年创建以来,已经从单一的品类扩展到附近美食、水果、蔬菜、超市、鲜花、蛋糕等多品类,从早午晚餐,发展到下午茶、宵夜,中餐、西餐、家常菜、小吃、快餐、海鲜、火锅、川菜、蛋糕、烤肉、水果、饮料、甜点等多种类餐饮。美团外卖可以说是当前电商领域,最为复杂的业务之一。

    业务的复杂,给系统架构也带来了不小的挑战。美团外卖业务之所以说是当前电商领域最为复杂的业务,主要源于以下几点特征:

    • 美团外卖业务承载在三个App上,美团外卖App、美团App外卖频道、点评App外卖频道。

    • 美团外卖作为美团公司重要的用户入口,还承担着流量平台的作用,提供平台能力支撑频道业务的发展,如闪购、跑腿、金融等。

    • 美团外卖作为已经成熟的业务,需提供可复用的平台能力,支撑新业务的发展,例如菜大全App的发展。

    • 美团外卖作为一个超级业务方,业务内又运营多个方向业务,如流量业务、交易业务、商家业务、商品业务、营销业务、广告业务等。

    综上所述,可以发现美团外卖不仅仅自身业务比较复杂,而且对外的角色也很复杂。在美团内部,外卖不仅仅是美团平台的一个频道业务,而且自己本身也是一个平台业务,同时美团外卖还承担着新业务发展的平台角色。这意味着想要支持好美团外卖业务的发展是一件非常有挑战的事情。

    1.3 美团外卖移动端历史架构概述

    好的架构源于不停地衍变而非设计。美团外卖的架构,历史上也是经历了很多次迭代。由于外卖业务形态不断地发生变化,原有的设计也需要不断地跟随业务形态进行演进。在不断探索和实践过程中,我们经历了若干个大的架构变迁。从考虑如何高效地复用代码支持外卖App,逐渐地衍变成如何去解决多端代码复用问题,再从多端的代码复用到支持其他频道业务的平台架构上。在平台化架构建设完成后,我们又开始尝试利用动态化技术去支持业务快速上线的诉求。如今,我们面临着多端复用、平台能力、平台支撑、单页面多业务团队、业务动态诉求强等多个业务场景问题。下文我们针对美团外卖移动端架构的变迁史,做一些简单的概述,以便读者阅读本文时能有更好的延续性。

    1.3.1 组件化架构

    早期阶段,美团外卖作为公司的一个孵化业务,在2013年底完成了美团外卖App的1.0版本。随着外卖业务的验证成功和跑通,订单量也快速增长,在2014年底突破了日订单量100万。

    随后在2015年2月,外卖以Native的形式接入美团App,成为美团App的一个业务频道。在接入过程中,我们从美团外卖App拷贝了大量的代码到美团App的外卖频道,两个App上的外卖业务代码也分别由两个独立的团队维护。早期外卖业务变化快,App迭代频繁,写代码的方式也比较粗放,同时美团App也处在一个平台化转变的时期,代码的稳定性和质量都在变化和提升当中。这些因素导致了外卖代码内各子系统之间耦合严重,边界模糊,“你中有我,我中有你”的情况随处可见。这对代码质量、功能扩展以及开发效率都造成很大的影响。

    此时,我们架构重构的目的,就是希望将各个子系统划分为相对独立的组件,建设组件可以直接复用,架构如下图所示:

    1.3.2 平台化架构

    如上文所述,大家可以知道美团外卖和美团外卖频道是由不同的团队在维护发展。2015年,公司考虑到业务发展的一致性,将美团外卖频道团队正式归于美团外卖。从组织架构上来说,美团外卖和美团外卖频道,逐渐融合成一个团队,但是两端的差异性,导致我们不得不仍然阶段性地维持原有的两班人马,各自去维护独立外卖App和美团外卖频道。如何解决这个问题?两端代码复用看起来是唯一的途径。另外,随着业务的快速发展,外卖App所承载的业务模块越来越多,产品功能越来越复杂,团队规模也越来越大,如闪购、跑腿等业务想以独立的Native包的形态接入外卖App,还有外卖的异地研发团队的建立,都带来了挑战。这使得我们在2017年开始了第二次架构重构——平台化架构,目标是希望能够支持多端复用和支持不同团队的业务发展。通过抽象出平台能力层、业务解耦、建立壳容器,最终实现了平台化架构,架构如下图所示:

    1.3.3 RN混合架构

    在平台化架构之后,美团外卖功能持续增加,美团外卖客户端安装包的体积也在持续增加。回顾2017年和2018年,每年几乎都增长100%。如果没有一个有效的手段,安装包将变得越发臃肿。另外,由于原生应用需要依托于应用市场进行更新,每次产品的更新,必须依赖用户的主动更新,使得版本的迭代周期很长。业务上的这些痛点,不断地督促我们去反思到底有没有一种框架可以解决这些问题。

    在2015年的时候,Facebook发布了非常具有颠覆性的React Native框架,简称RN。从名字上看,就可以清楚的明白,这是混合式开发模式,RN使用Native来渲染,JS来编码,从而实现了跨平台开发、快速编译、快速发布、高效渲染和布局。RN作为一种跨平台的移动应用开发框架,它的特性非常符合我们的诉求。美团也积极地探索RN技术。在RN的基础上,美团在脚手架、组件库、预加载、分包构建、发布运维等方面进行了全面的定制及优化,大幅提升RN的开发及发布运维效率,形成了MRN(Meituan React Native)技术体系。

    从2018年开始,美团外卖客户端团队开始尝试使用MRN框架来解决业务上的问题。使用RN的另一方面的好处是,能逐渐的抹平Android和iOS开发技术栈带来的问题,使用一套代码,两个平台上线,理论上人效可以提升一倍,支持的业务需求也可以提升一倍,架构如下图所示:

    2. 美团外卖容器化架构全景图

    2.1 什么是容器化架构

    上文说到,外卖业务已经发展到多App复用、单页面多业务团队开发的业务阶段。要满足这样的业务场景下,寻求一个可持续发展的业务架构是件不容易的事情。经过我们之前架构演进,我们获得了宝贵的经验:在平台化架构的时候,我们将App和业务进行解耦,将App做成壳容器,业务形成独立的业务库,集成到壳容器里面,从而屏蔽了多App的问题,提高了业务的复用度。在RN混合式架构里面,我们引入了RN容器,通过这个容器,使得业务屏蔽了Android和iOS的平台差异。借助这些成功的经验,我们进一步思考,如果我们尝试进一步的细分外卖的业务场景,将不同场景下的基础能力建设成壳容器,业务集成到容器内,是否可以更好的支撑我们多App复用、单页面多业务团队的当前现状呢?

    容器化架构的愿景是:

    • 希望将前端呈现业务的环境抽象出来,将能力进行标准化,形成统一的容器,通过容器去屏蔽平台和端的差异。容器提供上层标准统一的能力接口,使得业务开发人员专注于容器内的业务逻辑的实现,最大复用已有的能力,而不用关注现在的环境是Android还是iOS,现在的端是美团App还是大众点评App。

    • 容器和远端达成呈现协议,使得端上的内容具备随时可变化的能力。容器化架构的实现是存在一定前提的,如果业务的发展本身处在一个探索阶段,还有较多可变的因素,是无法形成稳定的能力层的,这时候建设容器化架构反而使得架构偏向复杂。但对于外卖业务场景来说,经过多年的沉淀固定,外卖业务逐渐形成了一套稳定的业务形态,已经进入到场景细分和快速迭代业务模块的阶段。在这样的阶段下,容器化架构才有可实施的前提。

    2.2 容器化架构的优势

    当我们把承载外卖业务的环境进行了抽象和标准化后,就可以获得以下若干点好处。首先动态化属性提升,我们可以把原有必须在客户端上写的业务放到了远端,业务的动态性得到很大的提升,具备随时上线业务的可能。对于开发过程而言,编译部署的速度也得到了极大提升。如果涉及到客户端的代码改动,那客户端的编译打包,即使是增量的编译,也至少是秒级的编译速度。而容器化后,我们只打包必要的业务,把业务动态下发到容器呈现,客户端代码本身不会有变化,这样就可以从秒级的编译减少到毫秒级的编译。同样,业务动态下发,对减少客户端的包大小也有很大的帮助。

    然后,容器位于应用之内,我们向应用中引入相同的容器SDK,容器屏蔽了应用之间的差异,对于Android和iOS平台,在设计上,通过容器这一层去尽可能屏蔽平台之间的差异,使业务开发人员只需要认识容器,不需要花费大量的精力去关注应用和平台之间的差异,从而使得开发效率得到了极大的提升。

    其次,容器化后,容器对承载的内容是有接口协议要求的,承载的内容只有满足容器定义的协议才能得到容器带来的好处,这促使业务得到了更细粒度的细分,业务开发时候,对模块化的意识得到了保障。另外,容器这一层提供的接口在Android和iOS上是标准化的,业务的开发也因为依赖的标准化,而趋向标准化,双端的业务一致性得到了提升。这些潜在的架构好处,对未来的业务维护和扩展都打下了比较好的地基。

    2.3 外卖容器化架构全景图

    整个外卖容器化架构可以按照从下到上,从左到右的视角进行解读:

    最底层是系统服务,因为我们采用了H5和RN这样跨端的技术栈,使得iOS系统和Android系统成为了最底层。

    系统服务之上是集团基于Native建设的基建,全公司通用,覆盖了研发工程中方方面面的基础服务。

    在基建之上是我们定义的容器层。我们尝试用单一技术栈解决所有问题。但经过我们的探索,觉得不太可能实现。好的架构要匹配业务形态,业务的诉求决定了我们不能选择唯一的技术栈去解决所有问题,细分外卖的业务场景可得到以下3个方向的页面分类:

    • 高PV主流程页面,例如首页、金刚页、商家页等,这类页面的PV远高于其他页面。这类页面的特点是,交互强、曝光度高、多团队参与建设和维护。针对这类页面,为了给用户提供极致的体验,是无法采用H5或RN实现的,即使性能上能够满足,但是这些页面是多团队共同参与建设,如果用H5或RN实现,那么单一团队改动,都会造成全页面受到无法预料的影响,其他未改动的业务方肯定是无法接受的。所以这类页面,我们采用的是局部动态化+页面模块化的方案,我们针对页面进行容器化改造,将页面变成容器,容器承载模块。每个模块归不同的业务方进行维护,从模块的维度进行解耦,每个模块都可以动态配置和下发。

    • 低PV辅助页面,例如帮助、足迹、收藏等,这类页面的PV低,但胜在数量多,都用原生实现成本比较高,如果都用H5来实现,不少页面和原生的关联还是比较近,不是非常适合。针对这类页面,我们采用集团提供的MRN基建去承载,MRN作为跨端的技术栈,我们已经在之前的RN混合架构的时候,建设了较为丰富的组件,针对自定义的MRN容器做了比较丰富的建设。同时,MRN具备动态下发的能力,满足业务的诉求。

    • 向外投放的运营活动页面,例如圣诞节活动,时效性比较强。这类页面由H5技术栈去完成,一方面可以满足时效性,另一方面H5的动态下发能力也是最强的,这样的特性能够充分的满足业务的诉求。我们使用集团提供的Titans基建,通过建设业务自定义的Titans容器,支撑业务的发展。

    再往上,就是垂直的业务,外卖目前有流量业务、交易业务、商家业务、商品业务、广告业务、营销业务、闪购业务等。业务都是垂直向下依赖,直接可见容器,可见基建,能够很好地获取到各种已经建设的能力去完成业务的需求。

    最上面是承载的App端,目前有四端,包括外卖、点评、美团、闪购等等。

    右侧是测试发布和线上监控,相对于常规的移动端App架构而言,容器化架构的测试发布和监控是更为精细化的。不仅仅要关注端本身的可用性,还需要关注容器、容器承载的模块、模块展示的模板,模板里面的样式这些的可用性。

    2.4 容器化的挑战

    容器化架构相对常规的移动端架构而言,它从管理移动端的代码转变成管理移动端的容器建设代码和业务远端开发代码,多出了容器和业务远端下发。这不仅仅是对技术上的挑战,对长期做客户端开发同学,也需要一个思维转变的跳转。

    一致性的挑战:容器需要在多个宿主应用之中运行,宿主应用的环境一致性直接影响了容器的一致性。我们的策略是两手准备,一方面利用外卖业务的优势推动宿主应用的环境对齐;另一方面将容器建设成SDK,通过SDK将长期保持容器的一致性,也通过SDK内部的设计屏蔽应用之间的差异;对于Android和iOS平台,我们通过分层的设计,尽可能屏蔽平台的差异。综上所述,一致性的挑战在于(1)容器运行的宿主应用的环境一致性;(2)不同应用不同版本容器的一致性;(3)Android和iOS平台容器的对业务的一致性。

    动态发布的挑战:长期以来,客户端同学的开发概念里面只有App版本的概念,而当我们逐渐把业务代码做成远端下发时,将会新增一个线上动态发版的概念。当我们在发布业务的时候,相对以往的工作,多出需要去考虑这个业务的版本,可以运行的容器对应的App上下界版本。另外,发版的周期也会新增业务的发版周期,不仅仅是App的发版周期。这两者在一起将会产生新的火花,业务的版本和App的版本如何适配的问题,业务动态发版的周期和App的发版周期如何适配的问题。外卖这边的解决方式是建设主版本迭代+周迭代的模型。

    监控运维的挑战:以往的移动端架构,我们更加关注的是端本身的可用性,然而当我们演进到容器化架构的时候,仅仅关注端的可用性已经远远不能确定业务是可用的了。我们需要从端的可用性延伸出下载链路、加载链路,使用链路上的可用性,针对每个重要的环境,都做好监控运维。

    3. 外卖跨端容器建设

    3.1 MRN容器

    3.1.1 MRN容器简介

    React Native框架本身只是一个运行时环境中的渲染引擎,可以将同一套JS代码分别在Android和iOS系统上最终以Native的方式渲染页面,从而为App提供了基础的跨端能力。但从工程化的角度来看,如果想在App中大规模地应用RN技术,除了RN框架本身外,还需要在开发、构建、测试、部署、运维等诸多方面的配合。

    MRN(Meituan React Native)是美团基于React Native框架改造并完善而成的一套动态化方案,在RN的基础上提供了容器化能力、动态化能力、多端复用能力和工程化保障。MRN在开发效率、稳定性、性能体验、动态化和监控运维等多方面进行了能力升级和扩展,满足了美团RN开发工程化的需要。目前,MRN已接入美团40多个App,核心框架及生态工具有超过100位内部代码贡献者,总PV超过4亿。

    3.1.2 Roo组件库

    下面再介绍一下外卖建设的两个UI相关的技术项目,Roo组件库和组件样式动态配置。

    • Roo组件库:外卖在RN及MRN框架提供的UI组件基础之上,又扩展了适用于外卖业务的标准化UI组件库。UI组件库一方面统一了我们的设计规范和开发规范,提高了UI一致性;另一方面,组件封装也提升了RN页面的开发效率和质量。

    • 组件样式动态配置:有了标准的Roo组件,我们进一步给标准组件的动态添加了样式动态配置能力。在使用组件时,很多样式是支持动态下发的,例如字体、圆角、背景色等,方便我们进行UI的适配和改版。

    外卖在2018年底开始试验MRN容器在外卖业务上的应用,并在2019年上半年进行了大面积的页面落地。目前,外卖已有近60个RN页面上线,占外卖页面比例超80%,其中包括Tab页面“我的”、提单选择红包页、订单评价页等高PV页面。MRN容器的接入,给外卖App的容器化、动态化、人效提升、包大小瘦身等方面都做出了不小的贡献。

    3.2 Titans容器

    3.2.1 Titans容器简介

    Titans容器是美团系App统一的Web容器组件,基于苹果提供的WebView组件,将WebView容器化,统一了WebView的UI展示和交互方式,规范了桥协议的使用范式,同时预置了诸多基础能力和业务能力。Titans容器大大提高了Web页面的开发效率和用户体验上的一致性。

    • Web容器:Titans容器提供了统一的UI展示和自定义样式,例如导航栏样式、页面Loading状态、进度条样式等;还有统一的交互方式,例如页面跳转、Scheme协议的解析等。

    • KNB统一桥服务:Web容器虽然在动态化和Android、iOS双端复用上很好地弥补了Native的不足,但在很多地方体验上又难以达到Native的标准。因此,KNB桥应运而生,KNB定义了Native和JS通信的标准方式,方便开发时进行桥协议扩展,同时KNB也内置众多的Native基础能力,极大地提高了Titans容器的用户体验和开发效率。

    • Web业务增强能力:Titans容器中预置了丰富的基础业务页面,例如登录页面、分享弹窗等。

    • 提供链路增强:提供了长连接、离线化等方式来提高网络请求的速度和成功率。

    • WebView预加载:在App启动之后,用户点击网页入口之前,提前加载好HTML主文档和基础库,这样当用户点击页面入口时,App直接使用已准备好的WebView,仅需加载少量的业务代码。从而达到白屏时间短、加载页面迅速的效果。

    Titans容器在外卖业务中的使用场景非常丰富,其中最重要的使用场景是各种运营页和活动页,例如点击首页顶部Banner的广告落地页、为你优选、限时秒杀等活动运营页等;还有客服页、帮助反馈页、商家入驻页、美团公益页等功能性页面;作为一级入口页面的美团会员页面,也是一个基于Enlight的Titans容器。

    4. 外卖页面容器建设

    外卖容器化建设,首先需要要区分的是核心页面和非核心页面。外卖业务中对核心页面的定义是页面DAU>美团DAU的5%或者是下单关键路径。为什么要先按照是否为核心页面进行拆分呢?重点就在于改造的成本。核心页面的业务复杂度决定了它不容易做全页面的动态化,它比较适合做局部的动态化方案。核心页面的复杂度在于业务本身复杂,最重要的是核心页面往往会有多个垂直业务团队共同的开发维护,大家各自有重点关注的模块,做全页面的动态化,无法做到有效的物理隔离。

    而对于非核心页面,业务功能和交互相对简单,组织关系也较为确定,更适合做标准的MRN和Titans容器化。所以我们的策略是核心页面做到支撑页面模块级别的业务动态和复用,非核心页面可以做到页面级别的动态化和复用。页面容器化的核心含义就是把一个页面划分为若干个模块,每个模块成为一个业务容器,每个容器的填充既可以用Native的方式实现,也可以用Mach实现(Mach是外卖自研的页面局部动态化技术),可以支持iOS/Android/小程序三端跨平台运行。页面本身则化身为容器的管理者,负责子容器的编排和布局,并支持其动态化。

    4.1 页面容器化设计思路

    页面容器化设计中主要分为三个阶段,模块有序化、模块编排化、渐进式业务落地。

    • 模块有序化:将耦合的外卖业务代码按模块维度进行拆分,建立标准化的模块间组合和交互方案,降低模块内改动对其他模块的影响。这个阶段我们同时完成了Native原生模块和局部动态化模块的标准化改造。

    • 模块编排化:页面容器化的一个特点是页面具备编排模块的能力,在这个阶段我们在客户端增加了对业务模块结构编排能力的支持,同时我们跟后端的同学共建了配置平台,通过配置化的方式打通了AB实验平台、统一数据服务等多个平台。在标准化的数据协议的支撑下,页面支持了AB实验动态上线,大大降低了客户端在AB实验方面的开发成本,做到了客户端零成本,后端低成本,高效地支撑了外卖首页六周年的大改版。

    • 渐进式业务落地:页面容器化后最明显的收益是支持业务需求的动态上线,只有页面容器中的业务模块具备动态能力才能实现这个目标,这会涉及Native模块迁移为Mach模块的过程。在这个方面,我们的思路是跟随业务需求渐进式落地。在模块编排阶段,我们设计了Native模块向Mach模块迁移的能力,同时设计了覆盖模板维度和API接口维度的三重降级方案,来保障模块动态化迁移的稳定性。

    4.2 业务构建模块标准化

    从App页面开发的角度看,一个完整的页面可以按照不同的功能及不同业务属性划分出多个不同的模块。

    业务构建泛指由多个业务模块组合拼装为一个业务页面的过程,涉及页面本身(UIViewController/Activity)以及各个业务模块的构造过程,前后端业务数据以及页面和业务模块之间的数据交互过程,业务模块内部的数据处理以及视图刷新流程。

    模块标准化指的将业务构建涉及到的多个过程通过规范化的方式确定下来,形成唯一的标准。模块标准化一方面能够在解决业务共性问题的基础上提供业务难点专项解决方案,另一方面能够在框架基础上形成能力约束,减少重复建设、低质量建设的问题。

    业务构建模块标准化中我们抽象了四层,下面将分别进行解读。

    • 最底层是框架能力层,是外卖业务团队自研的符合外卖业务特点的双端模块化框架。框架解决了不同页面场景下的共性问题,对典型的业务痛点也进行了支持。它是一种页面框架设计在iOS、Android双端对齐的实现方案,这种双端对齐的能力为页面容器化设计的双端一致性提供了保障。

    • 统一接口层是对框架能力层的标准化抽象,它可以保证任一模块调用的能力在各个业务场景下的实现都是一致的,有了这一层抽象任一模块都可以直接在各个场景下复用。

    • 在往上就是App全局的模块复用层,标准化后的模块可以通过唯一标示向模块复用池注册模块,这种中心化的注册方式可以让业务模块在跨业务库的场景下可以灵活地复用。

    • 最上层就是外卖的核心业务场景层,每一个场景都对应了一个标准化的页面容器,页面容器通过实现容器化接口来完成页面容器的构建。

    通过业务构建模块标准化的建设,业务模块已经是标准化的了,可以在跨页面间自由组合,这为页面容器化打下了基础。

    在页面容器化中最基础的能力有以下几点:页面中业务模块可编排能力,动态上线前端AB实验的能力,增量上线动态模块的能力。实现这些能力最重要的就是进行前后端数据协议标准化建设。客户端根据数据协议中的模块唯一标识匹配并构造业务模块,在完成模块数据的填充后会根据数据协议中的模块布局信息完成模块的布局。针对Mach动态模块,我们创建了基于模板ID的模块匹配和数据填充流程,可以支持Mach动态模板的增量上线。在数据协议中针对前端AB实验我们预留了AB实验和通参字段,在数据填充阶段通过容器化接口传入动态模块中,用于支持AB实验的动态上线。

    在容器化上线的过程中属于接口的大版本升级,为了保证容器的高可用性,客户端从模块级别和API级别实现了两套降级容灾方案。

    模块级别的降级方案主要针对Mach动态模块,与Native模块不同,Mach动态模块需要预先下载动态模板才能正常地完成模块的载入和渲染。为了保证动态模块的加载成功率,我们一方面在接口上线前利用Eva(美团内部系统)对Mach模板的下载进行预热。另一方面,我们设计了动态模块的主动降级方案,针对动态模块的动态上线使用Native模块进行兜底降级,对于跟版动态模块使用App内置模板的方案进行兜底降级。

    API级别的容灾方案主要为了保障客户端在新接口不稳定的情况下可以自行降级到旧接口。针对这个问题,我们对线上老接口设计了数据结构映射方案,在客户端通过配置化的方式可以把老接口的数据结构映射为新接口的数据结构。这样在上层业务无感知的情况下,可以做到容灾方案的上下线。

    4.3 小结

    通过页面容器化,使得页面只需要关心页面级的构造方式,而无需关心某一模块内部如何实现动态化的。把页面与页面的模块分离,也符合目前外卖客户端的组织结构,有利于业务组间的协作。同时,页面容器化使得外卖核心页面具备了符合外卖业务场景下的动态能力,渐进式把Native静态模块过渡到具备动态能力的模块,从模块的维度使整个页面具备了动态能力。这种渐进式的迁移方案把容器迁移跟业务模块的迁移分隔开,大大降低了页面容器化改造的风险。

    5. 外卖容器化架构的衡量指标

    5.1 容器化架构衡量指标的特点

    质量和性能指标是衡量我们App开发质量和用户体验的重要依据,是我们一直都非常关注的重点数据。在非容器化时代,我们大多数的指标都和App的使用环节紧密相关,因为在非容器化时代,逻辑链路相对简单,例如我们打开一个新页面时,我们首先创建页面实例,然后发起网络请求,同时页面会经历一系列生命周期方法,最后渲染。这时我们可能会关注网络请求的成功率和请求时间,页面的渲染时间,和过成功是否发生Crash,这个过程相对更短暂,指标更少,所以监控起来也更容易。

    外卖的容器化大大提升了外卖业务的复用能力、动态能力、模块化和开发效率,但同时也带来了更长的逻辑链路,链路从时间维度上划分是:下载链路、加载链路、使用链路。例如我们在使用MRN容器的时候,会涉及到bundle的启动下载或预热下载,bundle解压缩,MRN容器引擎初始化,bundle加载,JS的加载、执行,页面渲染等步骤,其中的每个步骤都可能存在性能问题和质量风险。因此,我们需要升级我们的衡量指标系统来应对容器化带来的新的挑战。

    5.2 链路指标

    • 下载链路:在下载链路中下载容器所需的各种资源,在MRN和Mach中主要是bundle的下载任务,只有bundle下载成功,才能进行后面的各项操作。所以bundle下载的成功率是下载链路中最重要的指标,同时bundle下载的时机也很重要。外卖业务中有各种bundel上百个,如果在启动时拉取所有bundle,对冷启动时间会造成极大的影响。我们采用了bundle预热的方法,发布bundle是给bundle打上相应的Tag,在适当的时机去下载,避免集中下载。

    • 加载链路:在加载链路中重要工作是对下载链路中下载的资源的解压和解析。例如在用PGA加载页面时,会进行模块的解析、模块匹配、模块降级、数据模型生成等步骤。在MRN中会进行bundle解压、引擎初始化、bundle加载等步骤。加载链路往往是比较消耗计算资源的步骤,对页面打开和加载时间影响较大,所以我们会比较关注加载链路的性能指标。

    • 使用链路:使用链路和非容器化的使用阶段基本相同,会主要关注页面的加载时间、Crash率、页面页面FPS、页面卡顿等指标。除此之外,还会关注和容器本身特性相关的一些指标,例如在MRN容器中,我们还会关注JS错误率、JS渲染时间、白屏率等指标。

    5.3 关键指标

    因为容器化的使用形成了一个串行的链路,所以如果某个关键节点失败,会导致容器功能不可使用,关键指标的任务就是从上述众多的指标当中筛选出这些关键节点。例如在下载链路中bundle下载的成功率和API的成功率,加载链路中bundle加载的成功率和模块匹配的成功率,下载或加载失败都无法再进行链路中的后续步骤,针对上面的成功率指标,我们会添加分钟级别的实时监控告警,做到及时发现,快速响应和紧急修复。

    在使用链路中模块渲染的成功率、Native Crash率、JS错误率也属于关键指标,这些任务的失败也会导致容器的不可用,针对这些指标我们也会采用实时监控措施,并且添加降级手段,例如回滚bundle版本,或者把MRN和Mach容器降级为Native容器。

    6. 外卖容器化架构的监控运维

    上面讲到了容器化架构的各项衡量指标,那么把这些指标具体落到实处的工作就是线上的运维监控工作。工欲善其事,必先利其器,对于监控运维工作,一定要有合适的监控工具辅助配合才能事半功倍,公司内有很多优秀的监控统计工具可供使用,这里的难点就是如何根据监控的需要判断选择合适的工具。还有就是合理的划分监控维度和数据指标的优先级,例如对于能够影响到链路稳定性的关键指标,我们需要做到分钟级的监控,一旦出现问题就能及时收到告警,对于非关键指标,则通过生成日报的方式,方便开发者的统计和分析。

    工具的使用上主要分为大盘工具、具体异常工具、灰度降级工具、告警工具等(以下是美团内部使用的工具)。

    • 大盘工具:主要使用CAT、天网、Crash平台等工具。这些工具收集、统计大盘数据,然后生成可视化的图标和曲线。方便开发者了解大盘的整体情况和变化趋势。

    • 具体异常工具:使用Sniffer、Logan等工具。这些工具可以用来获取发生异常时的上下文和设备信息,回捞用户行为日志,方便定位排查具体问题。

    • 灰度降级工具:使用ABTest平台、Horn等工具。用于下发配置,以进行灰度控制或开关控制。

    • 告警工具:告警小助手。将告警通过IM软件及时发送到个人或群组,做到及时发现及时处理。

    业务覆盖维度监控可以分为全局监控和局部(单业务)监控。

    • 全局监控:监控各项容器化质量指标、性能指标,生成每日报表,方便跟踪监控容器化的整体质量。

    • 局部(单业务)监控:实时监控每个页面、每个容器的线上数据,做到有问题及时发现,及时定位,及时处理。

    时间维度监控:可以按天、小时、分钟的时间维度。天级别的监控主要是一些非关键路径指标,例如一些性能指标,页面加载时间、页面FPS、JS渲染时间等,我们可以按天维度的生成数据报表,已邮件的数据发送日报。当App灰度上线时,我们会开始小时级别的监控,每过半小时通过IM软件向广播一些关键指标,方便开发者跟踪线上数据的稳定性。分钟级别的监控则是针对关键指标,观察分钟维度上的变化,如果关键指标超过阈值,或者波动过大,就会及时产生告警。

    下面我们以一个开发者的视角去看一下外卖容器化架构的监控运维系统。从获取信息的方式上可以分为主动查询和被动推送,开发者可以通过监控工具监控全局和局部数据的变化趋势,也可以分析具体异常Case;也可以从IM工具,邮件等收到相关的推送数据,以便及时响应。在控制运维上,开发者可以通过Eva、Horn等美团内部的灰度系统进行灰度发布,当灰度期发现问题的时候,可以及时地通过停止灰度,版本回滚,关闭入口的方式进行降级容灾处理。

    7. 外卖容器化架构的发布能力

    7.1 容器化架构发布体系

    容器化使外卖业务具备了强大的动态化能力,但动态化能力又和需要相应的发布能力来支持,发布能力是我们业务开发质量和效率的重要保障,也是我们容器化建设工作过程中的重点环节,这一节主要介绍一下外卖容器化的发布能力。

    从发布能力类型的角度看主要可以分为三种类型:(1)容器内容的发布,包括发布整个页面或者发布页面中的局部模块;(2)配置下发,通过API或其他配置平台,下发布局协议、AB测试、样式配置、功能配置、模板配置、容器配置等,大大提高了业务的灵活度和线上验证能力;(3)灰度、降级下发,通过UUID,用户画像等信息做到灰度发布,降级回滚等控制能力。

    从发布资源的的角度看主要分为两种:一种是普通的资源,例如发布一个Web页面,或者通过发布新版API来控制页面局部容器的展示与否和展示的位置,同时我们也可以进行一些AB Test操作;另一种是bundle资源,主要是针对MRN容器和Mach容器,每个MRN容器和Mach容器的资源都会先被打包成一个bundle,然后通过发布系统下发到终端,然后终端解析bundle中的代码和资源,最终渲染页面。

    从发布阶段的角度看,可以分为测试阶段、上线阶段、灰度阶段和全量阶段,其中上线阶段是最终的环节,我们增加了很多校验和保护手段来尽量保证上线操作的正确性。

    7.2 跟版本发布流程

    虽然我们具随时备动态发布能力,但正常的版本迭代还是会存在中,所以外卖这边的节奏是周动态迭代+双周版本迭代,这保证了我们的开发工作有个一清晰的周期。在动态发布阶段中最关键的阶段操作上线阶段。以MRN为例,目前外卖业务中应有70多个bundle,再算上测试环境的bundle就有接近150个bundle,只是管理这些bundle就是一个复杂的工作,况且在进行上线操作时还是涉及发布的目标App、App版本的上下界、MRN版本的上下界等,一不小心就会造成操作失误,所以进行上线操作时需要非常谨慎。

    我们针对操作上线阶段进行了事务流水线,通过流水线建立保护措施,一个bundle的上线要经历一个流水线的若干操作。首先,操作人根据上线SOP手册进行若干检查操作,同时编写标准格式的发布说明,然后周知相关核心人员后在操作系统上发起上线申请,Leader和QA收到申请后会进行检查并审批,审批通过后还要避开App使用的高峰期或节假日上线,上线后通过灰度发布观察各项数据指标,指标正常后全量发布。

    7.3 bundle资源发布

    bundle是我们最常发布的资源类型,这里再结合发布工具讲解一下bundle的发布过程。MRN和Mach都是以bundle的形式下发到设备终端的,我们在发布bundle的时候主要会用到两个工具,打包工具Talos和发布工具Eva(美团内部工具)。一个bundle的工程文件主要由三个部分组成:配置文件、源代码和资源文件,其中配置文件用于指导Talos对工程文件进行打包,多个bundle可以共享一份配置文件。当我们准备发布一个bundle时,先找到该bundle在Talos的发布模板,选择发布环境(测试或线上),然后进行一键打包,然后Talos会进行一系列流水线操作,包括Clone代码、配置环境、进行Lint检查、构建和上传等。Talos打包完毕后将bundle上传到Eva系统,然后Eva负责bundle的分包、上线、下线、灰度等操作,最终下发到终端设备上。

    未来,我们还将引入美团住宿的MRN-DevOps来进一步的屏蔽当前多系统的问题,降低整个周期管理的成本,特别是发布前的人工检查成本,逐渐实现RD在一个平台上操作从研发到发布运维的所有实现。尽可能地减少人工成本,提升自动化。

    7.4 多种发布能力综合使用

    上面介绍的是以bundle资源形式的发布流程,过程较为清晰简单。下面再结合外卖首页,介绍一下局部容器化的发布方式。外卖首页是典型的流式列表,在局部容器化的架构下,首页就是由一个个矩形容器以ListView方式布局的,容器分两种,Native容器和Mach容器,Mach容器是一个通用容器,我们可以编写不同的样式模板,下发到终端后交由通用Mach容器来渲染,以此达到只使用通用容器展示不同UI样式的目的,这里涉及了Mach的发布系统。

    首页各子容器相当于一块块积木,它们的位置排布、展示与否、模板的选择等最终交由API控制,API具备了控制首页布局,样式展示的能力,而不再是单纯的数据源。同时,首页也涉及了AB能力、灰度降级策略等其实配置项下发系统。可以看到外卖首页的容器化是由多种发布能力配合支撑的,是外卖发布能力体系的“集大成者”。

    8. 总结

    好的架构是要随着业务的发展,不断演变去适应业务的发展。美团外卖从一个很小规模,每日单量只有几千的业务,逐渐地走到今天,每日单量峰值超过4000万,组织架构也从一个十几个人的团队,逐渐发展到现在多角色、多垂直业务方向,上千人共同协作的团队。移动端上的架构,为了适应业务的发展要求,也经历了组件化、平台化、RN混合化,再到现在向容器化的变迁。

    容器化架构相对于传统的移动端架构而言,充分地利用了现在的跨端技术,将动态化的能力最大化的赋予业务。通过动态化,带来业务迭代周期缩短、编译的加速、开发效率的提升等好处。同时,也解决了我们面临着的多端复用、平台能力、平台支撑、单页面多业务团队、业务动态诉求强等业务问题。

    当然,容器化架构带来好处的同时,对线上的可用性、容器的可用性、支撑业务的线上发布上提出了更加严格的要求。我们通过监控下载、加载、使用链路上的可用性,来保障线上动态业务的可用性。针对容器,我们利用成熟的测试基建,建设容器的自动化测试来保障容器的可用性。针对发布,我们建设迭代流程,配合发布流水线,将线上的发布变得更为可控。

    截止到目前为止,外卖业务经过了几十个动态化业务上线窗口,累积共发版百次以上。未来半年,我们还将进一步从业务需求入手,将业务需求细分归类,让产品侧逐渐建立容器和动态化需求的概念,能够从源头上,逐渐的将业务进行划分,最终使得每个业务需求,都可以归类抽象成可以动态下发的业务和容器能力建设,从而进一步的完善容器化架构的能力和支持更多的的业务场景。

    9. 参考资料

    10. 作者简介

    郭赛,同同,徐宏,均为美团外卖iOS工程师。

    ----------  END  ----------

    招聘信息

    美团外卖长期招聘Android、iOS、FE高级/资深工程师和技术专家,感兴趣的同学可投递简历至:tech@meituan.com(邮件标题请注明:美团外卖)。

    也许你还想看

    | React Native在美团外卖客户端的实践

    | 美团外卖iOS多端复用的推动、支撑与思考

    | 美团外卖前端容器化演进实践

    展开全文
  • 容器和云原生(一):初识容器化和云原生

    千次阅读 多人点赞 2021-01-29 15:49:45
    目前亟待增加裸金属服务器配置相关知识和云原生相关内容,那就从容器化和云原生下手,本节把基于k8s的容器化知识挂载到自己的知识树上,然后在测试环境进行开发测试; 一、理解容器化 什么是容器 容器是云原生...

    总聚焦于应用系统开发和建立在应用系统上的业务模型开发,很容易忽略基础资源重要性(包括裸金属服务器配置和优化、最优组网实践和网络拓扑优化、应用部署的持续集成和持续开发、云上资源分配和云原生),努力走出舒适区尝试新知识才能打开新思路,目前亟待增加裸金属服务器配置相关知识和云原生相关内容,那就从容器化和云原生下手,本节把基于k8s的容器化知识挂载到自己的知识树上,然后在测试环境进行开发测试;

    目录

    一、理解容器化

    什么是容器

    什么是Docker

    什么是pod

    什么是微服务

    什么是devops

    二、理解云原生

    三、本地测试-DockerDesktop

    四、后续学习路径


     

    一、理解容器化

    什么是容器

    容器是云原生概念的重要组成部分,一种计算单元,容器比虚拟化技术更轻量化、更小开销的方式运行,作为应用的包装形式,容器赋予应用独立和便携的能力。随着Docker、Kubernetes技术的成熟,容器也成为了时下最火的开发理念。并非所有的应用都适合选择容器,开发者可以根据自己应用的特点和需求选择最适合的计算单元。如果应用是高性能、互信的,且处于同一个管理区域,那么用线程或者进程就可以满足;但如果你的应用是多租户的,并且和其他应用运行在同一个空间,那么你就需要考虑如何将这些应用安全地隔离开,使得数据不会被泄露或性能受到影响,容器也许就是一个不错的选择。

    容器是「高度隔离的进程」:在一般进程的隔离基础上增加了新的隔离机制,这些隔离机制是使用Linux的内核提供的,它包括一些命名空间(Name Spaces)和CGroup。命名空间可以分为网络、存储和计算三大类。其中,最为重要的是网络命名空间。它保证了容器的网络是独立于其他容器网络的。每个容器自己看到的文件系统和其他容器的是不共享的,每个容器只能看到自己的进程ID,而进程编号也是连续的。容器最大的特征没有自己独立的操作系统,而是共享其宿主机上的一个操作系统;而虚拟机则运行在「一台独立的服务器上」,容器相比于虚拟机的成本小但隔离性欠缺。

    容器是「应用的闭包」:应用不是单一的可执行文件,稍微复杂的应用包括:代码、可执行文件、配置依赖、外部依赖(动态链接库)等。所以在应用发行包装的时候,需要考虑目标操作系统的版本、系统架构以及它所依赖的模块等因素。否则应用安装时会改动系统的不同部分,容器作为应用的包装,它最大的特点就是实现了应用的独立和便携,容器本身包含了应用所有的依赖,这使得它可以再任意的基础设施上运行,不会因为系统版本、架构的问题,而导致各种意外。

    什么是Docker

    Docker是容器管理平台,容器是应用运行单元,Docker用来创建、管理和销毁这些单元的,在创建和管理这些计算单元的时候,需要用到计算单元的包装(也就是它的软件发行包),这些包装以容器镜像的方式存放在它的运行环境中,所有的容器计算单元都是通过这些镜像来创建的。

    镜像本身会有版本的发布、升级等需求,这就涉及到Docker的另一个重要组成部分DockerHub了。DockerHub有点像苹果的App Store,它是一个非常大的「容器市场」,所有常用的软件都可以在DockerHub上找到。

    最后一个Docker的重要模块,就是用户界面和管理工具,它们用来向容器的运行环境发布命令或查看状态。只需要用一个Docker的命令加上一些参数,就可以实现创建、删除、查看容器的运行情况等操作,只需要安装好Docker就可以尝试运行这个Hello World的容器了,容器的典型应用可以分为两类:微服务和DevOps。

    什么是pod

    Pod是组合的多容器运行单元,也是Kubernetes的基础单元,可以看作是容器的扩展或者增强型的容器。Pod里面包括一个主容器和数个辅助容器,它们共同完成一个特定的功能。把多个进程(容器也是一种隔离的进程)打包在一个Name Space里的时候,就构成了一个Pod。Pod里面不同进程的应用包装仍然是独立的(每个容器都会有自己的镜像)。 

    Pod的意义在于既保持主容器和辅助容器的的密切关系,又保持主容器的独立性。由于主容器和辅助容器的生命周期相同,可以同时被创建和销毁,因此把它们放在一个Pod中,可以使他们的交互更加高效,另一方面主容器需要完成一些主要工作,而另一些工作可能是有共性的,就可以单独打包由辅助容器来运行。 非常推荐大家去一个叫Katacoda的网站,它上面有大量免费的在线实验,包括Docker及Docker Image等动手操作项目

    什么是微服务

    微服务是指系统的不同单元或功能运行不同的容器,每一个服务的容器数量可以根据自己的负载进行调整。比如,一个大系统包含用户登录、货品展示、货品交互等功能,但这个系统的各个部分并不是同时线性增加的,有些部分可能忙一些,有些部分的容量可能还有富余。 

    什么是devops

    DevOps是指开发者、测试、生产过程流水线化。因为容器的「自包含」特性,当它作为标准的流通物品,可以使开发环境、测试环境和生产环境的应用包装完全一致,这样就减少了应用由于依赖关系配置错误等导致的意外,从而使得开发、测试、生产的整个流水线变得更高效。

    二、理解云原生

    云原生(CloudNative)以容器化、微服务、可持续交付性,快速构建/运行弹性扩展应用,应用构建简便快捷,部署轻松自如,应用按需伸缩,云原生是一套技术体系/方法论。Cloud表示应用程序位于云中,而非传统的数据中心;Native表示应用程序从设计之初即考虑到云的环境,原生为云而设计,在云上以最佳姿势运行,充分利用和发挥云平台的弹性+分布式优势。

    云原生概括为4个要点:DevOps+持续交付+微服务+容器,云原生架构的应用系统应该采用开源堆栈(K8S+Docker)进行容器化,基于微服务架构提高灵活性和可维护性,借助敏捷方法、DevOps支持持续迭代和运维自动化,利用云平台设施实现弹性伸缩、动态调度、优化资源利用率。

    云原生构建应用简便快捷,部署应用轻松自如、运行应用按需伸缩。优点不一而足,缺点微乎其微;秒杀传统Web框架,吊打祖传IT模式,实在是保命装逼、评优晋级不可多得的终极绝密武器。

    三、本地测试-DockerDesktop

    本地使用docker-desktop安装mysql;

    官方下载地址:docker-desktop的链接地址

     安装过程中报错,WSL 2地址:wsl2

    设置国内镜像地址,并重启;

    {
      "registry-mirrors": [
        "https://docker.mirrors.ustc.edu.cn",
        "http://hub-mirror.c.163.com"
      ],
      "insecure-registries": [],
      "debug": false,
      "experimental": false,
      "features": {
        "buildkit": true
      }
    }

     本地安装mysql是如此地复杂,但是在使用docker-desktop就非常的简单:

    # 拉取镜像
    docker pull mysql:5.7.29
    
    # 镜像运行之后就是容器container了,run就启动了该容器
    docker run --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7.29
    
    # 进入mysql这个容器内,在docker-desktop可以进入
    docker exec -it mysql bash
    
    # 进入镜像后就可以访问mysql
    mysql -u root -p //回车输入密码
    

    把window的telnet功能打开;telnet 127.0.0.1 3306端口可用,说明已完成安装,跟本地安装mysql相比快捷而省时间,秀的一批;

    四、后续学习路径

    1.学习dockerfile;

    2.云原生内容;

    展开全文
  • 深入理解分布式技术 - 容器化技术

    千次阅读 2021-02-11 20:58:08
    文章目录概述虚拟化技术容器化技术 概述 随着各种云服务的发展,越来越多的服务运行在以 Docker 为代表的容器之内。 相比传统虚拟化技术,容器技术是一种更加轻量级的操作系统隔离方案,可以将应用程序及其运行...

    在这里插入图片描述


    概述

    随着各种云服务的发展,越来越多的服务运行在以 Docker 为代表的容器之内。

    相比传统虚拟化技术,容器技术是一种更加轻量级的操作系统隔离方案,可以将应用程序及其运行依赖环境打包到镜像中,通过容器引擎进行调度,并且提供进程隔离和资源限制的运行环境。


    虚拟化技术

    虚拟化技术通过 Hypervisor 实现虚拟机与底层硬件的解耦,虚拟机实现依赖 Hypervisor 层,Hypervisor 是整个虚拟机的核心所在。

    Hypervisor 也叫作虚拟机监

    展开全文
  • 为了能够适应容器云平台的管理模式和管理理念,应用系统需要完成容器化的改造过程。对于新开发的应用,建议直接基于微服务架构进行容器化的应用开发;对于已经运行多年的传统应用系统,也应该逐步将其改造成能够部署...

    为了能够适应容器云平台的管理模式和管理理念,应用系统需要完成容器化的改造过程。对于新开发的应用,建议直接基于微服务架构进行容器化的应用开发;对于已经运行多年的传统应用系统,也应该逐步将其改造成能够部署到容器云平台上的容器化应用。本文针对传统的Java 应用,对如何将应用进行容器化改造和迁移到Kubernetes 平台上进行说明。

    要将传统Java 应用改造迁移到Kubernetes 平台上运行,通常要经过以下几个步骤。

    (1)进行应用代码改造,要考虑配置文件、多实例部署下的分布式架构问题,并对程序代码和架构做出相应的改造。

    (2)进行容器化改造,选择合适的基础镜像并打包生成新的应用镜像,使得应用能以容器方式部署、运行。

    (3)进行Kubernetes 建模与部署,采用合适的Kubernetes 资源对象建模Java 应用,最终发布到Kubernetes 平台上实现应用的自动化运维。

    接下来以一个传统的Java 应用改造迁移过程为例,来说明上述步骤中的细节。

    1 Java 应用的容器化改造迁移

    我们的目标是搭建一个简单的学员分数管理系统(Study Application),应用界面与架构如下图。

    Study Application 是一个典型的J2EE 系统,为了方便理解,并没有采用额外的框架技术,而是采用了MySQL 数据库,将JSP 作为Web 页面,并通过JDBC 进行数据库操作,整个系统以标准方式部署在Tomcat 的webapp 目录下。

    下图所示是Study Application的目录结构与说明。

    下面是在index.jsp 中访问数据库的关键代码, 数据库连接的配置信息被放在jdbc.properties 属性文件中,便于在不同的环境下修改:

        Class.forName("com.mysql.jdbc.Driver");
        java.util.Properties pps = new java.util.Properties();
        pps.load(new java.io.FileInputStream("jdbc.properties"));
        String ip=pps.getProperty("mysql_ip");
        String user=pps.getProperty("user");
        String password=pps.getProperty("password");
        System.out.println("Connecting to database...");
        conn =
    java.sql.DriverManager.getConnection("jdbc:mysql://"+ip+":3306"+"?useUnicode=true&characterEncoding=UTF-8", user,password)
            stmt = conn.createStatement();
            String sql = "show databases like 'HPE_APP'";
            rs =stmt.executeQuery(sql);

    我们知道,应用在以容器化运行以后,是不建议进入容器里修改配置文件的(在多实例情况下很难保持配置文件同步更新),因此,需要修改从jdbc.properties 属性文件中获取数据库连接的以上代码,根据容器环境的要求,将其改为从环境变量中获取,改造后的代码如下:

        String ip=System.getenv("mysql_ip");
        String user=System.getenv("user");
        String password=System.getenv("password");

    改造后的代码基本达到了容器化的要求,但对于一个完整的应用来说,由于还存在用户Session 会话保持的问题,因此还需要实现分布式的Session 会话机制,才能做到多实例部署,此时可以考虑采用Spring Session 框架来改造、升级我们的单体应用。对于大部分RESTful 服务,由于不需要会话保持功能,因此可以直接多副本部署,多个实例可以同时提供服务。

    2 Java 应用的容器镜像构建

    接下来,我们需要将自己的Java 应用打包为Docker 镜像,以容器方式启动并提供服务。在打包镜像时,需要注意以下几个关键问题。

    (1)需要注意基础镜像的选择问题。选择基础镜像的两个原则:标准化与精简化。尽可能选择Docker 官方发布的基础镜像,这些基础镜像通常符合标准化与精简化这两个目标。比如,它们都有Dockerfile 源文件,我们可以获知此镜像是如何制作的,并可以在此基础上实现诸如软件版本、性能优化、日志及安全等方面的特殊定制,然后打包为公司级别的内部标准镜像,供各个项目使用。

    (2)需要注意业务进程的启动方式。与在物理机上将自己的程序放到后台运行的方式不同,在容器化时,我们需要将自己的业务进程放到前台运行。这样一来,当业务进程由于某种原因而停止时,容器也随之销毁,我们就能及时观察到这种严重故障,并做出相应的行动来恢复系统。目前有一些系统在容器化的过程中采用了supervisord 这样的工具,将业务的主进程和辅助进程放到后台启动,并交给supervisord 监管,这种做法虽然在一定程度上也能实现自动重启故障进程的目标,但它将问题隐藏得更深,即使业务进程由于特殊故障始终无法重启成功,运维人员也发现不了问题,因此不建议采用这种方式启动业务进程。

    (3)需要注意程序的日志输出问题。在物理机上运行业务进程时,我们通常会把程序日志输出到指定的文件中,以便更好地排查故障。但在容器化以后,我们需要改变这种做法,将程序的日志直接输出在容器的屏幕上(或者说控制台Console 上),此时Docker 会将这些输出日志存放到容器之外的特定文件中,第三方的日志收集工具(例如Elasticsearch)就可以方便采集这些日志并实现集中化的日志搜索和分析功能。此外,Docker 也提供了统一的log 命令来查看容器的日志,这推进了系统运维的标准化。Java 中常用的Log4j 及Slf4j日志框架都支持把日志输出到控制台的配置方式,在打包应用时,需要对日志的配置文件做出相应的修改。

    (4)需要注意文件操作的问题。当业务进程运行在物理机上时,它看到的文件系统就是物理机的文件系统;但当业务进程运行在容器中时,它所访问的文件系统就是一种特殊的、被隔离的、分层模式的虚拟文件系统,在这种情况下,频繁进行I/O 操作的性能比较低。为了解决这个问题,容器可以使用Volume 将频繁进行操作的目录映射到容器外部(通常是物理机上);同时,Volume 也是容器与外部交换文件的重要工具,因此在制作镜像和运行容器时,需要考虑Volume 映射的问题,对于在程序运行过程中产生的大量临时文件和被频繁读写的文件,或者在需要跟外界交换文件时,可以选择挂载Volume。

    下图是Study Application 打包镜像的示意图及对应的Dockerfile 源码。

    Study Application 的镜像继承了tomcat:9-alpine 这个官方的基础镜像,这个镜像基于Alpine Linux,如果对比一下,我们会发现,基于alpine 的镜像不到5MB,而基于Ubuntu或CentOS 的镜像都在100MB 以上。此外,从Study Application 的Dockerfile 来看,制作Java 类型应用的Docker 镜像是很方便的一件事,通常只需几行代码。

    3 在Kubernetes 上建模与部署

    在应用容器化后,就可以在Kubernetes 上建模与部署了,在建模的过程中,我们需要考虑一些关键问题,这些问题及其答案如下。

    (1)将业务进程建模为Pod 还是RC?

    对于这个问题,最重要的判断依据是该进程提供的是有状态服务还是无状态服务。对于无状态服务,比如大多数REST 接口的服务,通常是可以在任意节点上启动并提供服务的,例如我们这里的Web 应用程序就符合无状态服务。但对于有状态服务,比如MySQL服务,我们通常不能这么做,因为它依赖本地存储的数据库文件。对于有状态服务,我们通常只能将业务进程建模为Pod,这是因为RC 控制的Pod 实例可以从一台节点飘到另一台节点上,如果我们能够通过共享存储解决Pod 的状态问题,则也可以把某些有状态服务的进程建模为RC,这种做法与StatefulSet 很类似。

    (2)我们是否需要在Pod 的基础上,继续建模对应的Service?

    这主要取决于此Pod 是否会被其他业务进程(或终端用户)所访问,对于不会被其他业务进程所访问的Pod,我们无须建模对应的Service。实际上,在一个分布式系统中,大多数进程都会被建模为Service 并对应一个微服务,如果某个服务还需要被终端用户访问,则往往还需要“导出”外网访问地址,比如NodePort 端口。对于无须外部访问的Service,还可以考虑建模为Headless Service,在这种情况下,该Service 不会分配一个虚拟的ClusterIP,通信效率更高。

    (3)是否需要考虑应用的数据存储问题?

    如果只是本机存储,则可以直接使用Kubernetes Volume 资源对象;如果希望有远程存储功能,则可以考虑使用PV(Persistent Volume)。这样一来,不管Pod 被调度到哪台机器,都可以继续访问原来的存储数据。如果希望系统自动管理共享存储的空间,则可以考虑建模对应的StorageClass。

    (4)是否需要考虑应用的配置问题?

    我们知道,在几乎所有应用开发中,都会涉及配置文件的管理问题,比如StudyApplication 中的数据库配置信息,常见的互联网应用还有缓存中间件、消息队列、全文检索等一系列中间件的配置文件。而在分布式情况下,发布在多个节点上的Pod 副本都需要访问同一份配置文件,这也加大了配置管理的难度,为此业内的一些大公司专门开发了自己的一套配置管理中心,如360 的Qcon、百度的Disconf 等,但这些解决方案都比较复杂而且有侵入性。Kubernetes 则提供了无侵入的更简单的方案,这就是ConfigMap,我们可以把任意数量的配置文件放入ConfigMap 中,实现集中化管理,然后通过环境变量的方式将配置数据传递到Pod 里,或者通过Volume 方式挂载到Pod 内。

    在Study Application 中,Web 应用在Kubernetes 上的建模如图6-4 所示。我们通过定义一个RC 来控制Web 的Pod 实例,数据库连接信息则通过环境变量传递到Pod 里,然后定义一个Service,并且通过NodePort 方式暴露到集群外供用户访问,即可完成这个Java应用的容器化改造工作。


    本文选自《Kubernetes权威指南:企业级容器云实战》一书,电子工业出版社9月出版。本书通过全新的视角,针对容器云领域现下的热点和技术难点,给出了基于Kubernetes的企业级容器云落地指南,为企业传统IT转型和业务上云提供助力。

    展开全文
  • 本课程是为了给新手小白入门的免费课程,帮助大家理解初步的了解虚拟化,云计算和容器化的概念,同时也教会大家怎么样在自己的电脑上很快的搭建一个用于学习以后知识的练习环境。 虚拟化、云计算和容器化,这三个...
  • 美团外卖前端容器化演进实践

    千次阅读 2019-11-28 20:00:43
    总第372篇2019年 第50篇提单页在美团外卖交易链路中非常重要,但随着业务不断发展,提单页模块越来越多,逻辑的耦合也越来越重。为了解决这一问题,需要实现提单页的动态,而动态是需要...
  • Docker容器化开发流程(一)介绍

    千次阅读 2020-04-11 20:50:33
    文章目录目标容器化开发模式生产环境使用docker 的问题容器化流程 目标 了解容器化开发模式 了解容器化开发流程 参考: Docker技术入门与实战 第二版 书籍 [认识容器]...
  • 物理机 虚拟机 容器化
  • 我们先来瞧一瞧,没有使用docker容器部署应用的时候的场景: 哈二的公司开发了3个基于java8的web应用,然后部署,仅仅需要放三个jar包到服务器。然后突然某一次更新,其中一个服务出了一个严...
  • 嵌入式设备的容器化App

    千次阅读 2019-06-10 10:15:52
    为此,我们开始了一个边缘设备软件的开发原型项目(Edge Device),目标是在一个小型cortex-A SoC 嵌入式平台上开发一个容器化APP 环境。构建边缘设备容器化APP 的概念平台。它具有如下特点 -采用 linux OS 。 ...
  • 对传统应用进行容器化改造

    千次阅读 2018-11-27 14:00:13
    本文接下来简要介绍什么是容器化,要在 Docker 容器中运行传统应用的缘由,容器化的过程,其间可能遇到的问题,在用容器部署之后的其他步骤等。这将明显减轻部署工作的压力,并让应用朝着零停机部署和横向缩放的方向...
  • 概要简述 时至今日,企业IT领域中最主要的问题在于如何解决不同功能部门之间的固有摩擦。一方面,业务线的主要诉求是在市场上实现差异性竞争...在多数组织成员看来,容器技术能够切实解决双方之间所存在的各类矛盾
  • 超详细Docker容器化自动部署(纯手打)

    千次阅读 2019-12-12 10:53:34
    微服务容器化自动部署 1. 传统手动部署: 首先基于源码打包生成jar包(或war包),将jar包(或war包)上传至虚 拟机并拷贝至JDK容器。 2. 通过Maven插件自动部署: 对于数量众多的微服务,手动部署无疑是非常麻烦...
  • 容器化部署OpenStack的正确姿势

    千次阅读 2019-03-05 15:06:39
    当前,以OpenStack为代表的IaaS开源技术和以Docker为代表的PaaS/CaaS容器技术日益成熟,二者如何强强联合,一直是业界颇为关心的焦点领域。本次分享主要是和大家交流基于Docker容器运行和部署OpenStack。那么,安装...
  • 容器化应用

    千次阅读 2018-07-15 18:57:58
    在进行容器化的时候,听起来好像很高端,但是如何说服别人进行容器化容器化应用是否能带来价值,那么就需要根据当前环境来进行考虑。。。  1、 硬件平台是否支持容器化  到处都在吹捧一次build,到处运行,一次...
  • Kubernetes 是 Google 开源的容器集群管理系统,它构建在目前流行的 Docker 技术之上,为容器化的应用提供资源调度、部署运行、服务发现、扩容缩容等一整套功能,用于容器集群的自动化部署、扩容以及运维的开源平台...
  • 一篇文章搞懂最流行的容器化技术Docker!
  • 什么是容器化

    千次阅读 2020-07-20 10:11:50
    虚拟机与容器对比图
  • Android容器化/组件化方案

    千次阅读 2017-09-25 10:31:55
    Android容器化方案撰写日期:2017-6-1 作者:庄文志项目背景项目在初期,因为功能少,项目紧张,我们只会在耦合度较高的情况下进行开发,各功能的耦合上如下:1)在这种情况下,各个模块之间耦合度高,各模块之间...
  • 目录 引言 … 1 关于本书 … 1 版本 … 1 本书不包含的内容 … 2 本书的目标读者 … 2 如何使用本书 … 2 微服务和容器示例应用:ESHOPONCONTAINERS … 2 请向我们发送您的反馈 … ...Docker容器和虚拟机之间的对比...
  • Docker 容器化技术介绍(一) 之 虚拟化技术 Docker 容器化技术介绍(二) 之 Docker 简介 Docker 容器化技术介绍(三) 之 Docker 组件 Docker 容器化技术介绍(四) 之 Docker的安装与启动 Docker 容器化技术...
  • Qunar 云原生容器化落地实践

    千次阅读 2021-09-17 13:37:46
    近几年,云原生和容器技术非常火爆,且日趋成熟,众多企业慢慢开始容器化建设,并在云原生技术方向上不断的探索和实践。基于这个大的趋势, 2020 年底 Qunar 也向云原生迈出了第一步——容器化。 云原生是一系列可以...
  • .NET Core容器化(Docker)

    千次阅读 2018-08-20 22:09:15
    那这一节我们就结合简单实例一步一步教你如何借助Docker来容器化 .NET Core应用,以完成跨平台的构建和部署。 2. 环境准备 自从玩.NET就一直和Windows系统打交道,如果还基于Windows来展开本节内容,不...
  • 应用容器化之Kubernetes实践

    万次阅读 2016-08-15 08:34:09
    主要以ZooKeeper、Redis、Kafka、MongoDB等应用容器化在Kubernetes平台上面实践。从计算、网络、存储方面解析应用在集成中的问题,以及部分传统应用在容器化过程中设计的应用二次开发等问题。首先介绍应用Docker化的...
  • 简介:云原生技术栈是下一代应用转型的必然选择,它包含了微服务架构,DevOps和容器技术。对于微服务架构来说,应用是“第一公民”,他逐渐蚕食原来底层软件或者硬件的功能,例如服务注册与发现以及负载均衡;而对于...
  • Docker入门一 容器化的概念

    千次阅读 2020-04-11 20:58:29
    文章目录目标了解dockerdocker 基本组成docker 操作流程 目标 ...docker 的容器技术是虚拟的一种。 跟虚拟机进行对比,docker容器不会包含操作系统 什么是docker 将应用程序自动部署到容...
  • Docker 容器化技术介绍(一) 之 虚拟化技术 Docker 容器化技术介绍(二) 之 Docker 简介 Docker 容器化技术介绍(三) 之 Docker 组件 Docker 容器化技术介绍(四) 之 Docker的安装与启动 Docker 容器化技术...
  • 我们是否应该将数据库也容器化

    千次阅读 2018-08-16 13:59:19
    将服务容器化的目的有这几个方面:易于构建新环境、易于重新部署(持续集成)、容易水平伸缩(从实践得出)、易于维护环境一致。 现在认为数据库不适合容器化,具体原因有一下几点: 1. 数据不安全 即使你要把 ...
  • 云计算、虚拟化、容器化杂谈

    千次阅读 2017-11-20 18:56:52
    虚拟机技术已经发展了很多年,虚拟机和虚拟层间的接口、虚拟机镜像格式等都已经标准了,相应的管理工具、分布式集群管理工具都有比较完善的解决方案,而容器最近几年才兴起,配套技术和标准还在完善中;...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 937,026
精华内容 374,810
关键字:

容器化