44

蘑菇街 DevOps 实践和转型之路

 5 years ago
source link: https://mp.weixin.qq.com/s/5cXgdTJnY1fb7u9Fd-g2SQ?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

veEj22Y.jpg!web

本文整理自2018GOPS·深圳站演讲:《蘑菇街 DevOps 实践和转型之路》

作者介绍: 我的题目是《蘑菇街 DevOps 实践和转型之路》。2015年前,在华为公司,2015年后到了蘑菇街。我在华为接触的更多的是电信级业务,软件开发和运维模式,也是电信级管理模式。到了蘑菇街后,到现在3年多,全部专注在互联网运维领域,我今天的分享的内容航,也是这3年来我们团队实践的内容。旁边是我的个人公众号二维码,主要分享一些运维时间和工作感受,大家感兴趣的可以扫一下。

EziUZjb.jpg!web

今天分享的内容有三个方面:

  • 第一,蘑菇街技术架构演进简介;

  • 第二,DevOps和技术架构;

  • 第三,持续交付实践。

第一部分先讲一下蘑菇街的技术架构演进过程

蘑菇街的业务,简单来讲,我们是专注女性时尚的电商平台。2017年,我们和美丽说合并,成立了美丽联合集团。合并后,技术体系和运维体系是以蘑菇街为主,并进行了融合。

zEZJ7jz.jpg!web

这是蘑菇街的基本数字。我们现在有1000万日活,80%移动流量是来自APP和小程序,每日百万级订单量,1000多线上应用,核心链路占70%,Java为主。我们机房是腾讯云的黑石机房,2017年底,我们把蘑菇街的业务整体搬迁到了腾讯云的黑石机房,结合腾讯云的弹性能力,大大提升了我们的运维效率。我们研发团队有700多人,运维团队有25人。

q226faa.jpg!web

这是蘑菇街最早期的技术架构,2011年的业务是导购型的,那时候我们采取最简单的LNMP架构。这样的架构比较简单,实际上可以认为它是没有架构的,我们就这样一直发展到2013年。

3U7nIvU.jpg!web2014年后,我们看到这个PHP工程越来越大,变得非常臃肿,这样的变化有两个方面。第一,蘑菇街从最初只做导购的业务形态到后来做电商,业务体系越来越丰富,有了电商要做用户、交易、商品、支付、广告等,业务的范围非常大。第二,蘑菇街研发团队的规模从最初二三十人到上百人,2014年后,差不多有300多人。

业务范围扩大,开发人员规模增长,大家都在这一个工程上写代码,自然而然,这个工程就变的越来越臃肿。

Vvyaiav.jpg!web

工程大了后带来什么问题?软件上的耦合性太高了,改一个地方会影响很多地方,到底影响什么,又很难理清楚的,最初一开始到工程的开发人员是清楚的,但是人员不断有新的进来,他们不清楚,会导致代码的耦合性高,开发效率就降低,业务的迭代速度就下降了。这时候,业务跟开发的矛盾是比较严重的。
另外一点,到目前这个阶段,代码非常复杂,整个过程耦合性非常高,改动的成本非常高。但是,这个阶段的挑战主要在开发,运维是没有什么挑战性的。因为运维只面对一个工程,不管后面多少台机器都无所谓。对运维来说,并没有太大的挑战,但对开发来说,这个代码基本上是不可维护的。
这个架构图往下看,中间还有一个中间层,从软件工程角度来说,我们从单体工程演进到分层架构的架构体系下,有点演进的意思。
来看一下我们的解决方案,讲的通俗一点,就是拆,把大工程拆成小工程,其实就是做服务化,现在比较流行的叫法是微服务。通俗点讲就是把大工程拆成一个个APP,可以按照业务领域拆成商品应用、购物车的应用等等。
如下是商品案例,里面有不同的服务,服务后面有不同的API,就是大致的拆分过程。但这里想表达的是,我们都在讲微服务、服务化,其实微服务也好,服务化也好,粒度到什么程度?这还是非常考验业务架构师的水平和能力的,这要跟后面的运维成本进行权衡。举个例子,商品中间有不同的服务。如果微服务拆得更细一点,后面的API也可以当成独立的服务进行运行。这其实是有很高的代价的,我后面会讲到。

IV36byZ.jpg!web微服务做完后,整个架构形态就变成这样(见下图)。2015年年底到现在没有发生太大的变化,就是这样的架构形态。

mIfMRnm.jpg!web

第二部分DevOps和技术架构

回到我们的主题上来,我刚才讲了这么多关于技术架构的东西,我好像没有提运维,没有提到DevOps,那DevOps跟我们的技术架构到底是什么关系呢?我们先看几个问题:

第一个问题,技术架构跟DevOps有什么关系?
第二个问题,DevOps到底是做什么的?
第三个问题,为什么DevOps的需求会这么强烈?我谈一下我个人的想法和理解。

raqIfiI.jpg!web

我们做微服务,并不是没有代价的,相反,代价是非常高的。我们从一个单体工程进行拆分,拆成几十个、几百个,甚至有上千个应用,当工程拆的很细很小的时候,运维面对的应用工程就不是一个两个了,是几百,甚至上千个了。像BAT那样的,规模会更大,工作量会翻倍,这就是代价。为什么说微服务拆的力度并不是越小越好,这是有成本代价的。
更复杂的一点是,把应用拆出来的之后,他们并不是静态存在的,而是会有非常复杂的调用关系的,真实的场景如下图:

imauQz3.jpg!web通过这两个图,大家能感受到什么?

这时候引入微服务后,系统复杂度远远超出了人脑认知范围,超出人力掌控范畴了。这时候,就要靠技术的手段进行解决,就要有工具、平台、体系去解决这些问题。这些东西谁来建设?要建设的话,是离不开运维和开发的配合的,所以就会倒逼Dev和Ops必须合作共建。

Jz6fYrn.jpg!web

DevOps本质上是技术复杂度上升到一定程度的必然产物。技术复杂度就是引入了微服务和分布式架构引入带来的。DevOps并不是单纯为了解决运维和开发之间矛盾才产生的。这种情况下,面对问题,运维和开发必需要合作,这是倒逼的关系。

有了这样的理解后,我们对DevOps要有重新的定义和理解。微服务和分布式架构下,运维是整个架构体系的一部分,是架构体系的延伸,并是不可分割的关键核心部分。运维能力是整个技术架构体系的能力表现,不再是单纯运维的运维能力体现。

我们做的运维工作是基于架构去做的,没有哪一个运维体系直接放到某个应用上做。这种情况下,必须把视角从运维中跳出来,从全局的角度看事情。这是需要重新定义和理解的。

在座的有没有不是做运维的?有吗?这么多。

我认为这是是好事情,对运维重新的理解和定义,不仅仅是运维的人需要转变思路,开发和架构师都需要转变,如果只把运维定义到搞搞网络和服务器,这样是做不好的,期望从架构设计开始,从最上层的开始有一个转变,这是非常关键的。

第三部分持续交付实践

接下来讲持续交付实践。我主要讲一下持续交付遇到的问题如何做选择。这是服务化之后发布面临的问题(见下图),其中有两个改变,一个是单体工程拆成很多应用,管理复杂度上升了。另外就是技术从PHP迁到Java上,这时候面临什么问题呢?我举个例子,PHP做代码发布的时候怎么发布?PHP代码写完,文件一发就可以了。Java来说,完全不一样,写完代码后要编译、打包,不同的应用有不同的配置,这时候要考虑配置怎么打包进去。因为是在服务化的环境下,在这个环境里,发布一个应用影响的不仅仅是你自己,有可能影响其他的,要有线下的环境保证,整个过程比原来复杂很多。

FVjeayJ.jpg!web这是持续交付过程细节(见下图),需求管理到提交阶段、功能测试、非功能验收,再到部署发布,这个图是我总结出来的。我们做发布、交付的时候,我们也没有什么持续交付的理论指导我们怎么做。当时我们面临很现实的问题是做了服务化之后,效率上不去。

2015年年底有很多团队的服务化改造完。我们2015年年中做改造,我要先把代码拖下来,不同的环境拖不同的配置,再把配置打包,再发布上线,这时候还需要发布前把应用拿下来,再进行变更,再从配置中心上挂上去。这个过程下来,运维人工做一个、两个去做还可以,七八个应用就搞不定了。这个需求是非常迫切的,我们当时只有一个念头,就是赶紧把发布的问题解决了。

YFZvie7.jpg!web

我们发现,最迫切的问题解决后,我们还有很多可以完善的,所以我们不断完善,就把这个东西做成现在这个样子。
这是需求管理(见下图),我们做需求管理最初的目的是代码发布是想每一次变更都可追溯,一个应用变更有两种原因,一个是需求变更,一个是修改BUG。对需求来说,是非常复杂的,所以我们后来跟PMO部门合作,我们要求在项目立项时要把需求分解,每个需求都必须要有业务架构师负责,要把需求拆借成一个个Feature,对应到应用,然后开发,再发布。我们做了这个事情后,带来一个好处,我们原来没有考虑到的。一个需求拆借成这么多Feature后,这些Feature是有关联关系的,Feature1和Feature2是有关联的,开发人员并不能清晰地看到关联关系。这种情况下,关联关系他就管理不起来。

I3qIJrF.jpg!web

我们做了这个事情后,我们要求架构师在需求发布的时候要以需求功能去发布,要协调好不同应用之间的发布顺序,他必须要做这个事情。后来,我们看Google做发布的时候有一个角色,叫发布协调员,其中一个作用就是做这个事情,必须协调一个需求不同的应用之间的发布顺序,甚至是多个需求做一次发布,中间的过程是怎样的,他必须要把这个事情做好。

这是提交阶段。写完代码之后,我们面临代码怎么提交,提交里会涉及到怎么合并,选择什么样的分支模式?这涉及到分支模式的选择,这也涉及到开发团队如何协作的问题,我们归结到是开发模式选择的问题。业界主流的是三种,就是主干开发模式、Gitflow开发模式和分支开发模式。

MriqQjF.jpg!web 主干开发模式 就是从Master分支拉代码直接改,改完之后提交到Master分支,发布的时候发布Master分支。但是,这是有场景的,如果一个团队同时进行一个项目是可以的,这种情况下提交任何代码都有功能测试和非功能测试的环节保证,发布的时候代码是有保证的。但是,这是比较理想的,一个开发团队实际都是同时进行很多项目,一个项目里涉及很多应用。这个情况下,有可能两个项目同时在改一套代码,Master同时在改、同时在提交。我在做项目A的发布时候,会把没有经过质量保证的项目B的代码也发布了。

主干开发模式是一个项目团队同时只在进行一个项目是可以的,它解决不了并行的问题。

所以就有了 Gitflow开发模式 ,它在Master分支上有一个Development分支,任何变更都要从Development分支上迁代码。这种模式可以比较好地解决项目并行的问题,但带来更大的问题,它分支太多了,是非常复杂的,分支管理成本会非常高。

分支开发模式是我们现在采用的模式,我简单说一下。我们从Master分支每次做变更的时候,一个需求拆分多个Feature,从Master分支迁出Feature分支,在Feature分支上做变更,在发布的时候以Master分支为基线,迁出一个release分支,Release发布后,合并回Master分支,这样可以保证始终与线上的版本是同步的。这样的成本会小一点,还能解决项目并行的问题。
代码提交到分支上了,要做一些单元测试和接口测试。我们会用Junit和TestNG分别进行单元测试和接口测试。之后,我们用Maven插件,用来执行Junit或TestNG用例。用JaCoCo分析单元测试和接口测试后的代码覆盖率,之后用Jenkins,自动化测试任务执行,报表生产和输出,与Maven、Junit、Gitlab这些工具结合非常好。

fMBFBfY.jpg!web非功能性验证是穿插在整个过程中的,比如提交阶段会进行非功能性验证,就是安全扫描,要看看有没有漏洞在里面,检查的漏洞非常多,比如远程代码执行。这个工具叫Cobra,是我们安全团队开发的,现在很多公司也在用这个工具在做这个事情。我们做的时候,中间有一步是安全扫描,这个必须通过的,不通过是无法进行下一步。

JB7zaqB.jpg!web我们提交完之后,代码也测试过了,下面就可以打包,这时候我们要做编译构建管理,我们用两个工具,一个是Maven,这是做依赖管理,还用它做打包和自动化的穿插执行。Maven对插件的功能非常好,能非常好地实现自动化。第二是Docker,这不是用于最终的发布,我们用Docker是用它提供非常干净的编译环境。编译的时候非常依赖环境,如果在固定的编译环境下,会导致很多编译冲突。但是,Docker会有很大的好处,它的隔离性非常好。通过Docker拉一个编译环境出来,是非常干净的环境,把代码放进去,把交付件拉出来就可以了,然后把环境销毁掉。Docker同时提供了并行的可能性,我可以在一个物理机上并行几个实例去跑,所以并行效率是有保障的。

3uuIfiq.jpg!web

这个方案我们从2014年用,我们发现Docker这个工具后,没有一下子做交付的工具,我们用来做编译是挺方便的。

这个阶段的难点是什么?就是复杂的多环境和配置管理,这个大家应该有感受。我们做发布也好,做运维管理也好,最麻烦的就是配置管理。我们做一次发布会经历不同的环境,比如线下环境、预发环境、Beta环境、生产环境。配置复杂在什么地方?跟环境相关的配置,线下环境连的DB,跟线上环境连的DB是不一样的,你用的Token,Token也不一样。如果你依赖第三方支付的,你在线上的环境可以直接连正式的支付通道,但是在线下不能连,这跟环境相关。这种配置每次打包的时候,生成交付件的时候,要提前判断出来,这是跟环境相关的。

EBjAVna.jpg!web我们需要多少环境?这是我们实际用的环境(见下图),有开发环境、项目环境、集成环境、预发环境、Beta环境、小蘑菇环境。我以线下环境为例进行讲解。

EnENnmr.png!web

一开始的时候,我们就一个线下环境、线上环境,中间会做网络隔离。实际情况是什么呢?对开发团队来说不是只有一个项目在并行,是多个项目的,这些项目都有质量保证的需求,这些需求都放在一个机房测试的话会有冲突的。我们会碰到测试的时候应用不行了,这会产生环境的冲突,这怎么解决呢?我们就建设项目环境,每个项目分不同的环境,这只允许核心的项目,一般的项目不会这么做,因为这是有代价的。

我们分了这么多环境,这些环境里只包括本次项目涉及到的变更应用,如果不涉及到变更应用就不会设置这个。我们做了一个改造,在分布式的服务化架构上,我们会优先支持本地调用。比如在项目1里有应用A、应用B、应用C,这些应用是本次项目需要变更的,这时候之间的相互调用都是在本环境内进行闭环的。但是如果是应用E、应用F、应用G,在本次项目中不包含的,这时候就依赖集成测试环境。这既保证了环境的隔离,又保证了环境的建设最小化原则。

多环境下的配置管理,有三种:多配置文件、PlaceHolder和AutoConfig方案。多配置文件就是一个环境建一个配置文件出来。最初的时候,我们是线下环境、预发环境和生产环境,有三个环境的时候,我们用这个方式,但是后来会有项目环境、开发环境,这种方式是搞不定的。AutoConfig方案有点复杂,但是有一些教程可以在网上找到。这个方案可以比较好地管理不同环境之间的配置,阿里在用这个方案,我们现在在调研这个方案。

后面会涉及到多环境发布的问题,这几个环境是我们必须经历的环境,即开发环境、集成环境、预发环境、Beta环境、生产环境。
这是单提机器上线部署的场景分解(见下图),这个单机的。如果靠人工去做,做一两台是可以的,但是几百台是搞不定的,所以我们要把过程串联起来。我们会把单机的动作做成自动化的过程,之后我们把这个过程再应用到线上去。

ZRBRjuU.jpg!web

这是发布和部署模式(见下图)。主流发布模式有三种:蓝绿部署、金丝雀发布和滚动发布。蓝绿部署在线上有两个环境,发布的时候先发布到绿的环境上,验证没有问题的时候,再切换蓝环境,解释起来挺复杂的,从管理上来说也是挺复杂的,用的时候,我感觉没有这样的场景需要我们这样去做。

neEBbmI.jpg!web我们做的是金丝雀发布和滚动发布。金丝雀发布就是从线上的环境里挑从两三台机器,先把版本升级发布,这几台机器在线上承载线上真实流量,它有没有问题会暴露出来。Beta发布完了,版本没有问题,就大面积往线上发布,这时候需要考虑一个问题,不可能线下的机器都停掉,会分批去发布。

线上部署案例,我分了8批,每批有8台。我们采取的方式是金丝雀的灰度发布再加滚动发布的分批形式。发布完后,我们会做另外的非功能性验证,验证性能和容量的下降,要看QPS有没有降,或者有没有出现新的错码。
关于DevOps和运维,我们今天讲了效率的部分,我觉得整个运维是比较大的,包括稳定、体验、安全、成本,稳定性方面没有时间去讲了。

qERJFne.jpg!webfY7N7rf.png!web

iyA7fu3.jpg!webJ3iymmi.jpg!web

长按关注V社北京

测试 技术 面试 DevOps

关注V社北京,关注测试,添加巨蜥小程序获取全量精品技术文章

iMb2MfR.jpg!web

关注我

每天进步一点点


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK