为应对如今无线优先和全渠道用户体验的需求和挑战, 我们该如何设计灵活的面向体验的微服务架构? 它有哪些模式和最佳实践? 携程, Netflix 和 SoundCloud 这些知名互联网公司是如何实践面向体验的微服务架构的? 在过去的时间, 大牛马丁福勒对微服务有哪些新的观点?
微服务各家玩法不尽相同, 我发现一些术语的叫法各公司也是不同的, 可以说微服务目前仍在激烈的演化中, 这个领域还未成熟和标准化, 所以今天的分享主要是我个人的视角和总结, 目的是抛砖引玉, 激发大家进一步探索和实践
本次分享的主题包括:
微服务架构原理
用户体验适配层(Backend For Frontend)
携程无线微服务案例分享
Netflix 微服务架构分析
SoundCloud 微服务架构分析
微服务架构不是免费的午餐
总结
本次分享也是应架构群内一些朋友的要求, 将之前零散分享的内容总结成文, 本次分享过程中会贴出相关内容参考链接(其中有些来自 SlideShare 和 Netflix techblog 的链接需要翻墙访问), 供有兴趣的朋友进一步学习
一微服务架构原理
微服务是个新概念, 但它没有一个明确的定义, 各家对微服务的描述不尽相同, 本人更倾向于用一些架构原理来描述它, 因为架构原理是相对抽象和稳定的, 而具体实现可以千差万别微服务原理和软件工程, 面向对象设计中的基本原理相通, 体现如下:
单一职责 (Single Responsibility), 一个服务应当承担尽可能单一的职责, 服务应基于有界的上下文(bounded context, 通常是边界清晰的业务领域) 构建, 服务理想应当只有一个变更的理由(类似 Robert C. Martin 讲的: A class should have only one reason to change), 当一个服务承担过多职责, 就会产生各种耦合性问题, 需要进一步拆分使其尽可能职责单一化
关注分离 (Separation of Concerns), 跨横切面逻辑, 例如日志分析监控限流安全等等, 尽可能与具体的业务逻辑相互分离, 让开发人员能专注于业务逻辑的开发, 减轻他们的思考负担, 这个也是有界上下文(bounded context) 的一个体现
模块化 (Modularity) 和分而治之 (Divide & Conquer), 这个是解决复杂性问题的一般性方法, 将大问题(如单块架构) 大而化小(模块化和微服务化), 然后分而治之
微服务架构同时还是一个组织原理的体现, 这个原理就是康威定律(Conways Law),Melvin Conway 在 1968 年指出: Any organization that design a system(defined broadly) will produce a design whose structure is a copy of the organizations communication structure, 翻译成中文就是: 设计系统的组织, 其产生的设计和架构等价于组织间的沟通结构 Dan North 对此还补充说: Those system then constrain the options for organization change, 简言之, 这些系统在建成之后反过来还会约束和限制组织的改变下面两个图进一步解释了这一组织原理:
Fig 1, 团队结构和系统架构不匹配
一般企业刚起步时, 业务规模小, 开发团队规模也小, 所以通常开发出来的系统是单块的; 随着业务的扩大, 团队规模也会随之扩大, 这个时候多团队组织架构和单块系统架构之间就会产生不匹配问题(沟通协调成本增加, 交付效率低下等等), 如果不对单块架构进行解耦和调整以适应新的团队沟通结构, 就会制约组织生产力和创新速度
Fig 2, 团队结构和系统架构匹配
把单块架构依照业务和团队边界进行拆分, 重新调整为模块化分散式架构(微服务架构是一种方案), 那么组织团队沟通结构和系统架构之间又能匹配起来, 各个团队才能够独立自治地演化各自的子系统(微服务), 这种架构的解耦和调整可以解放组织生产力和提升创新速度
二用户体验适配层(Backend For Frontend)
众所周知, 随着无线技术的发展和各种智能设备的兴起, 互联网应用已经从单一 web 浏览器时代演进到以 API 驱动的无线优先 (Mobile First) 和面向全渠道体验 (omni-channel experience oriented) 的时代, 如下图所示:
Fig 3, 从单一网站到 API 驱动的全渠道体验
应用架构的新挑战是:
用户接入形式的多样性, 无线(手机 Pad),Web, 互联网电视, 第三方合作应用等等, 各种用户设备的屏幕大小, 操控体验方式各不相同, 例如, 手机设备的屏幕较小, 能够展示的数据量小, 交互方式以触控为主, 也可通过条形码扫描器;
有些用户设备的带宽受限, 同时应用的 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 本质上是一个后端中间层, 但是它的作用主要是适配前端不同用户体验(无线, 桌面, 智能终端等等), 所以称为用户体验适配层, 它的适配作用主要是:
裁剪和格式化, 对后台的通用数据模型进行适当的裁剪和格式化, 以适应不同的用户体验展示的需要;
聚合编排, 对后台服务数据进行编排和预聚合, 这样可以有效简化客户端逻辑和减少网络调用开销
下图展示了一个无线 BFF:
Sam 推荐理想情况下针对每种用户体验类型需要一个 BFF(one BFF per user experience), 例如 Mobile BFF,Desktop BFF, 这可以做到职责单一和关注分离(遵循有界上下文原则), 但是 BFF 过多也会造成代码逻辑重复冗余的问题, 需要权衡 UI 和 BFF 理想是同一个团队负责, 这样可以减少沟通协调成本, 加快变更迭代速度, 这是遵循康威定律的体现下图展示了一种 BFF 和团队职责边界划分方案
Sam 还指出, 对于一些跨横切面的关注点 (cross cutting concerns), 例如路由, 安全认证, 日志监控分析, 限流等等, 通常可由独立的网关(Gateway) 层负责(如 Fig 6 所示), 由独立基础设施团队运维, 置于 BFF 之前, 这样在架构上可以做到职责单一和关注分离, 让 BFF 开发人员专注于聚合裁剪等业务功能, 无需考虑跨横切面功能但是如果对运维成本和调用性能有额外考虑, 跨横切面的功能也可以直接做在 BFF 一层
Fig 6, 独立网关层负责跨横切面功能
三携程无线微服务案例分享
携程网是一家旅游行业的互联网公司, 其内部有约十几个大小不同的事业部 (也称战略事业单位, Strategic Business Unit,SBU) 组成, 例如酒店, 度假等等三四年前, 为迎合无线互联网的趋势, 和很多其它互联网公司一样, 公司成立了一个独立的无线事业部(也是一个 SBU), 统一为整个公司开发无线应用下面两个图分别是携程无线 H5 应用的首页(Fig 7), 和最初的无线架构(Fig 8):
Fig 7, 携程无线 H5 首页
Fig 8, 最初的携程无线架构
架构底层是企业传统的 SOA/ESB/DB 服务, 架构上层是用户的无线设备, 中间是用户体验适配层 BFF 携程针对两类不同的用户体验分别做了两个 BFF:
Mobile App BFF: 针对 iOS,Android 等 Native 和 Hybrid 应用场景, 采用定制的 TCP 协议和二进制消息以提升网络传输性能,
H5 BFF: 针对 html5 浏览器应用场景, 采用标准 REST/JSON 协议通讯
最初, 携程无线 BFF 是单块的 (Monolithic),BFF 由无线事业部集中开发, 涵盖其它所有 SBU(酒店度假等) 的聚合裁剪逻辑刚开始, 携程无线应用相对简单, 单块 BFF 有优势, 例如开发测试和部署集中简单, 运维和集群扩容也比较方便
但是随着时间的推移, 特别是近两年, 使用无线应用的用户数成倍增长, 无线应用的功能也变得越来越复杂, 康威定律逐渐发挥作用, 无线 SBU 和其它业务 SBU 之间的沟通协调成本越来越高, 相互之间还常常因沟通不畅而产生摩擦, 交付效率越来越低同时, 单块 BFF 还具有代码逻辑耦合臃肿, 集群故障概率高, 技术栈绑死, 阻碍快速创新等单块架构固有的缺陷
2014 年, 携程对组织架构进行了一次调整, 将原无线事业部拆分, 将无线团队打散并安排到各个 SBU 业务事业部中为配合组织架构的调整, 公司的技术架构团队也将原来的单块 BFF 架构升级到如下的 (Fig 9) 面向体验的微服务架构:
新架构中, 原来的单块 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 都是开源的:
下图是我对 Netflix 微服务技术栈的一个简化和抽象, 可见整个微服务体系的骨架:
Netflix 的微服务体系可以简化为两层服务:
边界服务层(Edge Service Layer), 本质上就是 BFF, 适配前端各种用户体验的 API 层,
中间层服务(Middle Tier Service),Netflix 后端的各种微服务的统称
Netflix 的微服务体系由两个重要的基础设施支撑:
服务网关(API Gateway), 是 Netflix 微服务的总入口, 负责反向路由, 安全, 限流容错, 日志监控等跨横切面的功能,
服务注册表(Service Registry), 负责网关到边界服务, 边界服务到中间层服务, 以及后台服务之间的软路由和软负载
关于 Netflix 微服务和 API 架构的更多内容, 推荐参考 SlideShare 上的两个 ppt:
Transforming the Netflix API[附录 12]
Netflixs Global Edge Architecture[附录 13]
下面的一些图片是从上面两个 ppt 中截取出来的
Netflix 需要针对超过一千种的设备提供服务, 这对他们的 API 层 (也就是边界服务层或者 BFF 层) 的设计提出了很大的挑战, 为了应对这种挑战, Netflix 的 UI 团队和 API 团队通力协作, 由 API 团队提供通用的 API 运行时平台(有点类似 PaaS for API 的概念),UI 团队则在 API 运行时平台上针对不同设备利用动态脚本开发不同的 API 端点, 这种模式最大化了 UI 团队的效率和灵活性, 如下图所示:
Fig 12,UI 和 API 团队协同开发 API
Netflix 的 API 运行时平台内部细节和运作方式如下图所示:
Fig 13, 动态脚本平台
Netflix 的 API 运行时平台由 API 团队负责开发和运维, 其中内置支持:
通用的调用后台服务的 SDK;
支持并发调用多个后台服务的异步服务层(基于 RxJava);
容错组件 Hystrix
UI 工程师利用 Groovy 脚本根据前端设备展示的需要开发 API 脚本, 通过 SDK 调用后台服务, 对后台服务和数据进行聚合裁剪, 开发完成的脚本通过端点管理器上传到 API 运行时平台上, 最后激活该脚本则对应的 API 端点就能生效对外提供服务 Netflix API 运行时平台也称为动态脚本平台 (Dynamic Scripting Platform), 更多细节可参考[附录 4] 和[附录 11]
Netflix 应用采用前后分离架构, 页面等静态资源置于 CDN 上, 用户设备从 CDN 直接加载页面, 交互时页面直接从后台边界服务层获取数据, 如下图所示:
下图是 Netflix API 在 AWS 上的部署架构:
注: 最新的 Netflix 开源项目 Falcor[附录 5]表明 Netflix 同时也采用基于 Node/JS 技术的裁剪适配层, 目的是给前端 UI 团队更大灵活性和自主权 Facebook 有一个类似的项目 GraphQL[附录 16]
五 SoundCloud 微服务架构分析
SoundCloud 是一家音频分享网站, 有点类似音频界的 YouTube, 最近 SoundCloud 在 SlideShare 上分享了他们的微服务架构和实践
Fig 16,SoundCloud 微服务架构一
上图是从 SoundCloud 的一个 ppt 截取的微服务层次结构图, 和 Netflix / 携程类似, 两个主要层次是:
边界服务层(Edge Layer), 相当于 BFF, 针对不同场景体验的适配层, 例如第三方集成的 Public API, 嵌入页面场景的 Api-embedded, 无线场景的 Api-mobile 和桌面应用场景的 Api-v2
微服务层(Microservices),SoundCloud 后台微服务的统称, 例如 messagesstatslikes 服务等等
下图是从 SoundCloud 另一个 PPT 截取的微服务架构图
Fig 17,SoundCloud 微服务架构二
有两点值得关注:
SoundCloud 将 Geoip 限流安全认证等跨横切面功能和 BFF 做在同一层, 没有像 Netflix / 携程一样做在独立的网关层, SoundCloud 的这一做法有性能优势, 但同时也增加了 BFF 层的复杂性;
SoundCloud 将后台微服务又分为两层, 最底层的基础服务层 (Foundation Service Layer) 和中间的增值服务层(Value-added Service Layer), 这种分层方式是 SoundCloud 根据自己的需要提出的一种逻辑划分
关于 SoundCloud 微服务架构的更多内容, 请参考 SlideShare 上的两个 PPT:
BFF Pattern in Action: SoundClouds Microservices[附录 14]
Microservices@SoundCloud[附录 15]
六微服务架构不是免费的午餐
上面分享的三家公司都是体量比较大的互联网公司, 他们的业务量和团队规模决定他们很难不采用微服务架构, 但是对中小型规模的公司来说, 这三家的架构未必是可以直接照搬的, 个人认为, 解决问题的 scope 不同, 所采用的架构一般也不同, 不能盲目照搬
在业界对微服务架构热情高涨之际, 马丁福勒在 2015 年陆续写了几篇文章, 让人们更客观理性地看待微服务, 建议大家进一步阅读:
微服务架构先决条件[附录 7]
马丁说, 你必须长足够高, 才可以考虑使用微服务, 这里的高就是指基本的研发能力, 包括:
快速的环境提供 (Rapid Provisioning) 能力, 理想有基于云的环境提供能力
基本的监控 (Basic Monitoring)能力
快速的应用发布 (Rapid Application Deployment) 能力
DevOps 文化
在没有建立起这些能力之前, 勿轻易跟风采用微服务架构, 上面分享的三家公司, 都是在具备这些基础研发能力的基础上才开展微服务的
微服务的附加成本[附录 8]
马丁指出, 当业务不复杂, 团队规模不大的时候, 单块架构比微服务架构具有更高的生产率(productivity), 原因在于建立微服务架构需要额外的开销来支持和管理微服务, 从而降低生产率; 但是随着业务复杂性的增加和团队规模的扩大, 单块架构比微服务架构的生产率下降更趋明显, 当复杂性达到一个点, 微服务架构的生产率会优于单块架构, 原因在于微服务的松散耦合自治特性减缓了生产率的下降趋势
注: 马丁在上图的右下角提出了一个很有意思的观点, 团队的技能是比单块或者微服务架构的选择更重要的因素说白了, 如果团队能力不行, 不管用单块还是微服务, 还是难于管理复杂性
反过来, 如果团队能力强, 不管用单块还是微服务, 都能找到好的管理复杂性的手段, 所以说团队的技能才是管理复杂性的关键
单块优先(Monolith First)[附录 9]
马丁说, 他不建议企业应用一开始就直接上微服务架构, 原因一方面是支持微服务架构需要额外的开销来管理分布式复杂性, 另一方面是刚开始系统复杂度和领域边界是不清晰的, 你不知道该如何正确的切分微服务, 所以这种方案常常具有很高的失败风险
马丁建议企业应用走单块优先的架构思路, 先轻装上阵, 赢得时间探索系统的复杂性和领域边界, 当复杂性增加时, 拆出部分微服务, 随着团队对服务边界更加清晰和服务管理能力的提升, 持续拆分出更多微服务, 最终演化出微服务架构
上面分享的案例中, 像携程 / SoundCloud 都是从单块架构起步, 随着业务和团队规模的增长不断调整其架构, 最终演化出微服务架构, SoundCloud 从单块到微服务演化经历可参考[附录 1]
七总结
1 微服务架构是一种支持演化的自适应的架构, 微服务架构本身也是演化的结果, 架构演化的主要驱动因子是:
经济达尔文: 从长远看, 只有那些能更好满足客户需求的企业才能生存简单讲就是业务驱动, 业务要求架构灵活易于变更和扩展, 易于升级替换, 发布快速, 高可用能应对不可预测的流量模式, 能支持多样的用户设备和体验, 这样才能加快业务创新的速度, 赢得客户和竞争优势;
无线智能设备和云等技术的进步和发展;
康威定律, 即企业的业务组织和系统边界要尽可能对齐, 以业务领域和微服务为边界的产品型跨职能团队能更敏捷地响应市场需求
2 系统架构的首要目标是管理复杂性, 遵循良好的架构原理, 如单一职责有界上下文关注分离模块化和分而治之, 是管理复杂性的有效手段在企业应用成长到一定规模以后, 微服务架构是管理复杂性的一种行之有效的架构风格
3 企业要不要用微服务, 取决于你的业务复杂度和团队规模, 一般 Monolith First 业界大型互联网企业的微服务架构可以参考和学习, 但是不能照搬, 解决问题的 scope 不同, 采用的架构也不同
4BFF(Backend For Frontend)是应对当前多种用户体验的一种模式和最佳实践, BFF 的主要作用是针对不同的用户体验对后台服务和数据做聚合裁剪适配用户体验适配层, BFF,API Orchestration Layer,Edge Service Layer,Device Wrapper Layer 是相似概念
5Client -> API Gateway -> BFF -> Downstream Microservices, 是面向体验的微服务的标准参考架构
62016 年的参考应用架构如下图所示, 引用自 ThoughtWorks 的文章<技术栈复杂度飙升给管理者们的启示>>[附录 6], 特点:
企业后台采用微服务架构, 微服务可以采用不同的编程语言和不同的存储机制;
企业前台采用 BFF 模式对不同的用户体验 (如桌面浏览器, Native App, 平板响应式 Web) 进行适配;
企业后台采集各种数据, 集中存储, 再进行大数据建模分析和预测, 计算出来的数据再以微服务方式反哺给前台页面(例如商品推荐)
附录
很多不错的文章, 有兴趣的同学可以参与翻译
- BFF@SoundCloud https://www.thoughtworks.com/insights/blog/bff-soundcloud
- Pattern: Backends For Frontends http://samnewman.io/patterns/architectural/bff/
- Netflix Open Source Software Center http://netflix.github.io/
- Netflix Dynamic Scripting Platform http://techblog.netflix.com/2014/03/the-netflix-dynamic-scripting-platform.html
- Falcor, A Javascript library for efficient data fetching https://github.com/Netflix/falcor
6 技术栈复杂度飙升给管理者们的启示 http://www.neucloud.cn/article/1399_The-inspiration-of-the-technology-stack-complexity-surge-to-managers.html
7 微服务架构先决条件 http://martinfowler.com/bliki/MicroservicePrerequisites.html
8 微服务的附加成本 http://martinfowler.com/bliki/MicroservicePremium.html
9 单块优先(Monolith First) http://martinfowler.com/bliki/MonolithFirst.html
- Introducing the first NetflixOSS Recipe: RSS Reader http://techblog.netflix.com/2013/03/introducing-first-netflixoss-recipe-rss.html
- Optimizing the Netflix API http://techblog.netflix.com/2013/01/optimizing-netflix-api.html
- Transforming the Netflix API http://www.slideshare.net/benjaminschmaus/bschmaus-apiworldtransformingnetflixapi
- Netflixs Global Edge Architecture http://www.slideshare.net/MikeyCohen1/edge-architecture-ieee-international-conference-on-cloud-engineering-32240146
- BFF Pattern in Action: SoundClouds Microservices http://www.slideshare.net/grandbora/bff-pattern-in-action-soundclouds-microservices
- Microservices @ SoundCloud http://www.slideshare.net/grandbora/microservices-soundcloud
- GraphQL A data query language and runtime http://graphql.org/
互动环节
问题: 微服务与 SOA 的区别是什么?
我觉得两者体现相通的架构原理: 单一职责, 有界上下文, 关注分离, 分而治之区别在于微服务粒度更细, 同时融入了近几年一线互联网公司的一些最佳实践, 是服务化的新提法
问题: API 网关的反向路由的设计思路能具体说明一下吗?
携程的 API 网关基于 Netflix 的 Zuul 开源组件对外暴露一个域名 api.ctrip.com, 根据第一级目录做反向路由
api.ctrip.com/hotel,api.ctrip.com/flight,api.ctrip.com/vacation 每一级目录, 如 hotel, flight, vacation 对应一个后端 BFF 集群的域名, 也就是说 Gateway 里头有一张映射表, 这张表示是可以动态配置的, 可以动态路由, 灰度, 蓝绿部署都可以通过这张映射表做出来
问题: 分布式数据一致性问题在实践中是怎么解决的? 最终一致性方案中的 event-driven 和 event sourcing 或其他方案实践中是怎么选型的? 有没有推荐的参考框架或方案?
来源: http://geek.csdn.net/news/detail/256481