关闭

架构的本质是管理复杂性,微服务本身也是架构演化的结果

【文章摘要】设计系统的组织,其产生的设计和架构等价于组织间的沟通结构。

u=3968984218,931154490&fm=21&gp=0

为应对如今无线优先和全渠道用户体验的需求和挑战,我们该如何设计灵活的面向体验的微服务架构?它有哪些模式和最佳实践?携程,Netflix和SoundCloud这些知名互联网公司是如何实践面向体验的微服务架构的?在过去的2015年,大牛马丁福勒对微服务有哪些新的观点?

背景介绍

2007-2012年,我曾经就职于亿贝中国研发中心(eBay CDC)的开放API平台部门,亲历了当时世界第一大C2C电商平台的服务化和API化的过程,亿贝的经历让我对服务化和API这个技术领域产生了浓厚的兴趣;2013-2014年,我就职于携程旅游网框架研发部,有幸主导了携程服务化体系和无线API网关的建设,本分享基于我之前的实战经验,以及自己近期在业余时间对业界服务化最新进展的学习、思考和总结。

微服务各家玩法不尽相同,我发现一些术语的叫法各公司也是不同的,可以说微服务目前仍在激烈的演化中,这个领域还未成熟和标准化,所以今天的分享主要是我个人的视角和总结,目的是抛砖引玉,激发大家进一步探索和实践。

本次分享的主题包括:

1.微服务架构原理

2.用户体验适配层(Backend For Frontend)

3.携程无线微服务案例分享

4.Netflix微服务架构分析

5.SoundCloud微服务架构分析

6.微服务架构不是免费的午餐

总结

本次分享也是应聊聊架构群内一些朋友的要求,将之前零散分享的内容总结成文,本次分享过程中会贴出相关内容参考链接(其中有些来自SlideShare和Netflix techblog的链接需要翻墙访问),供有兴趣的朋友进一步学习。

一、微服务架构原理

微服务是个新概念,但它没有一个明确的定义,各家对微服务的描述不尽相同,本人更倾向于用一些架构原理来描述它,因为架构原理是相对抽象和稳定的,而具体实现可以千差万别。微服务原理和软件工程,面向对象设计中的基本原理相通,体现如下:

1.单一职责(Single Responsibility),一个服务应当承担尽可能单一的职责,服务应基于有界的上下文(bounded context,通常是边界清晰的业务领域)构建,服务理想应当只有一个变更的理由(类似Robert C. Martin讲的:A class should have only one reason to change),当一个服务承担过多职责,就会产生各种耦合性问题,需要进一步拆分使其尽可能职责单一化。

2.关注分离(Separation of Concerns),跨横切面逻辑,例如日志分析、监控、限流、安全等等,尽可能与具体的业务逻辑相互分离,让开发人员能专注于业务逻辑的开发,减轻他们的思考负担,这个也是有界上下文(bounded context)的一个体现。

3.模块化(Modularity)和分而治之(Divide & Conquer),这个是解决复杂性问题的一般性方法,将大问题(如单块架构)大而化小(模块化和微服务化),然后分而治之。

微服务架构同时还是一个组织原理的体现,这个原理就是康威定律(Conway’s Law),Melvin Conway在1968年指出:“Any organization that design a system(defined broadly) will produce a design whose structure is a copy of the organization’s communication structure”,翻译成中文就是:设计系统的组织,其产生的设计和架构等价于组织间的沟通结构。Dan North对此还补充说:“Those system then constrain the options for organization change”,简言之,这些系统在建成之后反过来还会约束和限制组织的改变。下面两个图进一步解释了这一组织原理:

431960759317724791

团队结构和系统架构不匹配

一般企业刚起步时,业务规模小,开发团队规模也小,所以通常开发出来的系统是单块的;随着业务的扩大,团队规模也会随之扩大,这个时候多团队组织架构和单块系统架构之间就会产生不匹配问题(沟通协调成本增加,交付效率低下等等),如果不对单块架构进行解耦和调整以适应新的团队沟通结构,就会制约组织生产力和创新速度。

246090108590984252

团队结构和系统架构匹配

把单块架构按照业务和团队边界进行拆分,重新调整为模块化分散式架构(微服务架构是一种方案),那么组织团队沟通结构和系统架构之间又能匹配起来,各个团队才能够独立自治地演化各自的子系统(微服务),这种架构的解耦和调整可以解放组织生产力和提升创新速度。

二、用户体验适配层(Backend For Frontend)

众所周知,随着无线技术的发展和各种智能设备的兴起,互联网应用已经从单一Web浏览器时代演进到以API驱动的无线优先(Mobile First)和面向全渠道体验(omni-channel experience oriented)的时代,如下图所示:

497273816686030223

从单一网站到API驱动的全渠道体验

应用架构的新挑战是:

1.用户接入形式的多样性,无线(手机、Pad),Web,互联网电视,第三方合作应用等等,各种用户设备的屏幕大小,操控体验方式各不相同,例如,手机设备的屏幕较小,能够展示的数据量小,交互方式以触控为主,也可通过条形码扫描器;

2.有些用户设备的带宽受限,同时应用的UI一般宿主在客户端,有些页面需要组合好几个后台业务服务的数据和功能,如果直接在客户端发起对多个后台服务的调用,势必造成大量网络开销影响性能,这个有点类似数据库查询中的n+1问题。

BFF(Backend For Frontend)是应对上述应用架构挑战的一种模式和最佳实践,2015年底,ThoughtWorks在其网站上刊登了一篇称为BFF@SoundCloud(SoundCloud是一个类似音频YouTube的网站)的文章[附录1],讲述SoundCloud如何利用BFF模式逐步将其单块Rails应用迁移改造为支持无线等多种用户体验的微服务架构。同期,ThoughtWorks的顾问Sam Newman,也就是《Building Microservices》那本书的作者,在SoundCloud等业界实践的基础上,写了一篇博客总结了BFF模式的原理、场景和用法[附录2],建议大家阅读。

BFF本质上是一个后端中间层,但是它的作用主要是适配前端不同用户体验(无线,桌面,智能终端等等),所以称为用户体验适配层,它的适配作用主要是:

  • 1.

    裁剪和格式化

    ,对后台的通用数据模型进行适当的裁剪和格式化,以适应不同的用户体验展示的需要;
  • 2.

    聚合编排

    ,对后台服务数据进行编排和预聚合,这样可以有效简化客户端逻辑和减少网络调用开销。

下图展示了一个无线BFF:

125031430733058771

Sam推荐理想情况下针对每种用户体验类型需要一个BFF(one BFF per user experience),例如Mobile BFF,Desktop BFF,这可以做到职责单一和关注分离(遵循有界上下文原则),但是BFF过多也会造成代码逻辑重复冗余的问题,需要权衡。UI和BFF理想是同一个团队负责,这样可以减少沟通协调成本,加快变更迭代速度,这是遵循康威定律的体现。下图展示了一种BFF和团队职责边界划分方案。

401415520263501545

Sam还指出,对于一些跨横切面的关注点(cross cutting concerns),例如路由,安全认证,日志监控分析,限流等等,通常可由独立的网关(Gateway)层负责(如Fig 6所示),由独立基础设施团队运维,置于BFF之前,这样在架构上可以做到职责单一和关注分离,让BFF开发人员专注于聚合裁剪等业务功能,无需考虑跨横切面功能。但是如果对运维成本和调用性能有额外考虑,跨横切面的功能也可以直接做在BFF一层。

401415520263501545

独立网关层负责跨横切面功能

三、携程无线微服务案例分享

携程网是一家旅游行业的互联网公司,其内部有约十几个大小不同的事业部(也称战略事业单位,Strategic Business Unit,SBU)组成,例如机票,酒店,度假等等。三四年前,为迎合无线互联网的趋势,和很多其它互联网公司一样,公司成立了一个独立的无线事业部(也是一个SBU),统一为整个公司开发无线应用。下面两个图分别是携程无线H5应用的首页(Fig 7),和最初的无线架构(Fig 8):

 

673513940016910859

Fig 7,携程无线H5首页

815672379806013642

Fig 8,最初的携程无线架构

架构底层是企业传统的SOA/ESB/DB服务,架构上层是用户的无线设备,中间是用户体验适配层BFF。携程针对两类不同的用户体验分别做了两个BFF:

1.Mobile App BFF: 针对iOS,Android等Native和Hybrid应用场景,采用定制的TCP协议和二进制消息以提升网络传输性能,

2.H5 BFF:针对HTML5浏览器应用场景,采用标准REST/JSON协议通讯。

最初,携程无线BFF是单块的(Monolithic),BFF由无线事业部集中开发,涵盖其它所有SBU(酒店、机票、度假等)的聚合裁剪逻辑。刚开始,携程无线应用相对简单,单块BFF有优势,例如开发、测试和部署集中简单,运维和集群扩容也比较方便。

但是随着时间的推移,特别是近两年,使用无线应用的用户数成倍增长,无线应用的功能也变得越来越复杂,康威定律逐渐发挥作用,无线SBU和其它业务SBU之间的沟通协调成本越来越高,相互之间还常常因沟通不畅而产生摩擦,交付效率越来越低。同时,单块BFF还具有代码逻辑耦合臃肿,集群故障概率高,技术栈绑死,阻碍快速创新等单块架构固有的缺陷。

2014年,携程对组织架构进行了一次调整,将原无线事业部拆分,将无线团队打散并安排到各个SBU业务事业部中。为配合组织架构的调整,公司的技术架构团队也将原来的单块BFF架构升级到如下的(Fig9)面向体验的微服务架构:

880839766083749746

 

新架构中,原来的单块BFF被拆分到各个SBU独立开发、测试、部署和运维。新架构中引入了一个API网关层(API Gateway),是服务解耦自治的关键,主要负责服务反向路由,同时负责限流容错、安全、日志、监控等跨横切面的公共逻辑。BFF解耦之后,携程微服务架构和组织业务架构进一步对齐,职责更明确,交付效率和创新速度明显加快。

四、Netflix微服务架构分析

Netflix是一家美国的在线影像租赁服务提供商,早在2012-2013年左右,Netflix就已经建立起了比较成熟的微服务架构体系。值得一提的是,Netflix还把它的整个微服务技术栈开源出来贡献给了社区,参考[附录3],其中包括知名的开源服务网关Zuul,服务注册发现框架Eureka,服务端框架Karyon,客户端框架Ribbon,容错组件Hystrix等等,可以说Netflix对微服务架构的发展起了重要的推动作用。下图展示了Netflix的微服务技术栈,来自Netflix参考应用rss reader[附录10],其中带粉红色标注的组件和Zuul都是开源的:

852900031224495295

下图是我对Netflix微服务技术栈的一个简化和抽象,可见整个微服务体系的骨架:

422876776492365649

Netflix的微服务体系可以简化为两层服务:

1.边界服务层(Edge Service Layer),本质上就是BFF,适配前端各种用户体验的API层,

2.中间层服务(Middle Tier Service),Netflix后端的各种微服务的统称。

Netflix的微服务体系由两个重要的基础设施支撑:

1.服务网关(API Gateway),是Netflix微服务的总入口,负责反向路由,安全,限流容错,日志监控等跨横切面的功能,

2.服务注册表(Service Registry),负责网关到边界服务,边界服务到中间层服务,以及后台服务之间的软路由和软负载。

关于Netflix微服务和API架构的更多内容,推荐参考SlideShare上的两个ppt:

1.Transforming the Netflix API[附录12]

2.Netflix’s Global Edge Architecture[附录13]

下面的一些图片是从上面两个ppt中截取出来的。

Netflix需要针对超过一千种的设备提供服务,这对他们的API层(也就是边界服务层或者BFF层)的设计提出了很大的挑战,为了应对这种挑战,Netflix的UI团队和API团队通力协作,由API团队提供通用的API运行时平台(有点类似PaaS for API的概念),UI团队则在API运行时平台上针对不同设备利用动态脚本开发不同的API端点,这种模式最大化了UI团队的效率和灵活性,如下图所示:

279718648559490477

Fig 12,UI和API团队协同开发API

Netflix的API运行时平台内部细节和运作方式如下图所示:

212427777394504923

Fig 13,动态脚本平台

Netflix的API运行时平台由API团队负责开发和运维,其中内置支持:

1.通用的调用后台服务的SDK;

2.支持并发调用多个后台服务的异步服务层(基于RxJava);

3.容错组件Hystrix。

UI工程师利用Groovy脚本根据前端设备展示的需要开发API脚本,通过SDK调用后台服务,对后台服务和数据进行聚合裁剪,开发完成的脚本通过端点管理器上传到API运行时平台上,最后激活该脚本则对应的API端点就能生效对外提供服务。Netflix API运行时平台也称为动态脚本平台(Dynamic Scripting Platform),更多细节可参考[附录4]和[附录11]。

Netflix应用采用前后分离架构,页面等静态资源置于CDN上,用户设备从CDN直接加载页面,交互时页面直接从后台边界服务层获取数据,如下图所示:

888182736768839118

下图是Netflix API在AWS上的部署架构:

361586876868199162

 

本文由

产品100

为你推荐并呈现

文章来源:微信公众号:聊聊构架(ID:archtime)

文章作者:杨波

 

友情提示:

若出处标注错误,请联系QQ:2977686517及时更正,感谢理解和支持!

0条评论 添加新讨论

登录后参与讨论
Ctrl+Enter 发表