2018年,每一个人都据说过微服务。但你知道怎么设计吗?前端
微服务是当今软件工程师的一个热门话题。让咱们了解如何使用微服务架构风格构建真正模块化、业务敏捷的IT系统。数据库
1、微服务概念编程
微服务体系结构由轻量级、松散耦合的服务集合组成。每一个服务都实现了单个业务功能。理想状况下,这些服务应该是具备足够的内聚性,能够独立地开发、测试、发布、部署、扩展、集成和维护。后端
正式定义 设计模式
“微服务架构风格是一种将单个应用程序开发为一组小型服务的方法,每一个小服务运行在本身的进程中,而且以轻量级机制(一般是HTTP REST API)通讯。这些服务是围绕业务能力创建的,而且能够由彻底自动化的部署机构独立部署。这些服务的集中管理只有最低限度,能够用不一样的编程语言编写并使用不一样的数据存储技术。”缓存
—— James Lewis and Martin Fowler安全
定义微服务的特性服务器
每一个服务都是一个轻量级、独立和松散耦合的业务单元。网络
每一个服务都有本身的代码库,由一个小团队管理和开发(主要是用于敏捷环境中)。架构
每一个服务负责一部分功能或者说业务能力,而且作得很好。
每一个服务均可觉得其用例选择最佳的技术栈(无需将整个应用程序绑定在一个框架中)。
每一个服务都有本身的DevOps计划(测试、发布、部署、扩展、集成和独立维护)。
每一个服务都部署在一个独立自给的环境中。
服务经过使用定义良好的API(智能端点)和简单协议如基于HTTP 的REST协议(哑管道)相互通讯。
每一个服务负责持久化本身的数据和保持外部状态(只有当多个服务使用相同的数据时,这种状况才在公共数据层中处理)。
白小白:
智能端点和哑管道,其实我一直认为“哑”管道不如“笨”管道或者“呆”管道更易理解。防呆设计是一种预防用户错误使用产品形成不良后果的设计理念,好比USB设计成一半有实体芯片,就是让用户能够不假思索的在插错后直接掉转方向再插。不让用户思考就是“呆”的含义。“哑”管道的“哑”其实就是体如今微服务的通讯过程尽可能简单,不要让通讯机制有“思考能力”,不在其中加入过多的处理机制,反例是SOA时代的ESB产品,ESB产品一般会包含复杂的设施用于消息路由,编排和转换,以及业务规则应用。反过来,智能端点的概念就容易理解了,也就是将与某服务相关的处理都限定在微服务的范畴以内,通讯过程当中的微服务端点是“智能”的,这也从一个方面体现了微服务“高内聚”的含义,有了高内聚,才能具有自治和独立性,从而能够支持“松耦合”的机制。
微服务的好处
微服务能够用于扩展大型系统,也为持续集成和交付提供了巨大的能力。
Scale Cube:用于可伸缩性的三维模型
(图片:Nginx博客)
独立缩放:《 The Art of Scalability》( http://t.cn/EAvlQ4o)这本优秀的书中所描述的Scale Cube概念,是微服务架构所支持的。在开发微服务以实现功能分解时,应用程序经过Y轴自动缩放。当服务调用量较高时,微服务能够经过克隆更多的CPU和内存,经过X轴进行扩展。为了在多台机器上分发数据,能够分离大型数据库(分库分表)转换成更小、更快、更容易管理的部件,从而实现Z轴的缩放。
独立发布和部署:使用微服务,Bug修复和特性发布更易于管理,风险更小。能够在不从新部署整个应用程序的状况下更新服务,并在出现问题时回滚或前滚更新。
独立开发:每一个服务都有本身的代码库,由一个小的焦点小组开发、测试和部署。开发人员能够专一于一种服务,而且只关注相对较小的范围。这将提升生产率、项目速度、持续创新能力和源码质量。
优雅降级:若是服务崩溃,其影响不会传播到应用程序的其余部分,并致使系统发生灾难性故障,从而体现某种程度的健壮性。
分散治理:开发人员能够自由选择技术栈,制定最适合其服务的设计标准和实现决策。团队没必要由于过去的技术决定而受到惩罚。
业务关切
独立的服务自己并不能造成一个系统。要使微服务体系结构真正成功,须要大量投资来处理跨系统的问题,例如:
服务复制:一种让服务易于扩展的基于元数据的机制
服务注册和发现:启用服务查找并查找服务端点的机制
服务监测和日志:收集来自不一样微服务的日志的机制,并提供一致的报告
弹性:服务在故障期间自动采起纠正行动的机制
DevOps:处理持续集成和部署的机制(CI和CD)
API网关:为客户端提供入口的机制
2、中间件与设计模式
API网关(全部客户端的单一入口点)
API网关风格的微服务体系结构(图片来自:Microsoft Azure Docs),是用于微服务的最多见的设计模式。API网关是一个中间层,具备最小化的路由功能,只是充当一个“哑管道”,里面没有业务逻辑。通常来讲,API网关容许客户端基于REST/HTTP调用托管的API。其余类型的微服务集成模式有:点对点风格(直接从客户端应用程序调用服务)和消息代理风格(实现异步消息传递)。
API网关充当全部客户端的单一入口点,API网关也做为一种边缘服务来将微服务做为托管API公开给外部世界。这听起来像是一个反向代理,但也有一些额外的责任,例如简单的负载平衡,认证和受权,故障处理,审核,协议转换,和路由机制。开发团队能够选择如下方法之一来实现API网关。
本身编程实现:具备更好的客户化和管控能力。
部署现有的API网关产品:节省初始开发时间,并使用高级内置功能(缺点在于:此类产品依赖于供应商,并不彻底免费。配置和维护一般是冗长而耗时的)
解释API网关行为的一些设计模式以下(请参阅微服务设计模式 http://t.cn/RKx8bhG).
网关聚合(http://t.cn/EAvT2jl):将针对多个内部微服务的多个客户端请求(一般是HTTP请求)聚合到单个客户端请求中,减小了使用者和服务之间的交互和网络延迟。
网关分流(http://t.cn/EAvTGmA):使单个微服务可以将一些共享的服务功能分流到API网关级别。这些跨服务功能包括认证、受权、服务发现、容错机制、QoS、负载平衡、日志记录、分析等。
网关路由(第7层路由,一般是HTTP请求 http://t.cn/EAvTMm4):使用单一入口端点将请求路由到内部微服务的端点,这样服务调用者就不须要自行管理多个独立的端点
请注意,API网关应该始终是一个高可用性和高性能的组件,由于它是整个系统的入口点。
事件总线(用于异步事件驱动通讯的、发布/订阅、中介通道)
微服务之间基于事件驱动的异步通讯实现最终一致性
(图片来源:microsoft.com)
应用程序的不一样部分在进行相互通讯时,不管消息的顺序(为处理异步的消息)或使用的语言(为了体现语言无关性),均可以使用事件总线来实现。大多数事件总线支持发布/订阅、分布式、点对点和请求响应消息传递。一些事件总线(如Vert.x)容许客户端使用相同的事件总线与相应的服务器节点进行通讯,这是全堆栈团队所喜好的一个很酷的特性。
服务网格(用于服务间通讯的外挂(Sidecar)机制)
服务网格风格的服务间通讯
(图片来源:微服务实践http://t.cn/EAAJWRi)
如何在应用程序中使用服务网格
(图片来源:http://t.cn/EAAizgn)
服务网格经过提供服务间通讯的辅助架构来实现外挂模式,包括弹性(容错、负载平衡)、服务发现、路由、可观察性、安全性、访问控制、通讯协议支持等功能。
服务网格在网络堆栈中的位置
(图片来源:http://t.cn/EAAizgn)
实际上,外挂实例部署在每一个服务的旁边(理想状况下是在同一个容器中)。他们能够经过服务自己的网络功能来进行通讯。服务网格的控制平面被单独部署,以提供中心功能,如服务发现、访问控制和可观察性(监视、分布式日志记录)。最重要的是,服务网格风格的设计模式容许开发人员从微服务代码中分离网络通讯功能并使服务只关注于业务功能。(来自:Netflix Prana, 微服务网格)
尽管上面的图片显示了服务之间的直接链接,可是处理服务间通讯的好方法是使用一个简单的事件总线做为中介,以保持最低级别的耦合。
在API网关级别上实现BFF模式和聚合器模式
(图:microsoft.com)
若是应用程序须要裁剪每一个API以适应客户端应用程序类型(Web端、移动端以及其余不一样平台),则能够经过聚合器(Aggregator)执行不一样的业务规则,也能够执行不一样的配置以根据客户端功能适配不一样的构建。这能够在API网关级别实现,也能够在服务级别并行实现。这种模式对于提供特定的用户体验很是有用。可是,开发团队应该足够当心,将BFF保持在可管理的范围内。
白小白:
“经过聚合器”,原文是“via a facade”,直译是“经过一个外观/门面”。门面模式(外观模式),是一种Java的设计模式,为子系统中的一组接口提供了一个统一的访问接口,引伸自一个前店后厂的生意模式,前面是门面,后面会有进料、生产、包装多个服务。用在这里是指将相关的服务经过聚合器聚合在一块儿,这个聚合器就是门面。服务调用者与门面交互而不是与一组服务交互下降了耦合性,但同时违反了面向对象设计原则开闭原则,开闭原则要求模块在扩展时能够不改动内部的代码,但显然当聚合器后端的某个服务发生变动时,须要在聚合器层面也发生变动,这也是文中说“开发团队应该足够当心”的缘由,由于违反了开闭原则,就会下降可复用性。
3、最佳实践
✅ 领域驱动设计:围绕业务领域进行服务建模。
为了处理大型模型和团队,能够应用领域驱动设计(DDD)。DDD经过将大型模型划分为不一样的有界上下文来明确他们之间的相互关系和子领域。这些有界上下文能够在应用设计级别转换为单独的微服务。(参见:领域驱动设计中的有界上下文 http://t.cn/EAAK4Xk)
✅ 分散数据管理(避免共享数据库):当多个服务使用一个共享数据架构时,会在数据层造成紧耦合。为了不这种状况,每一个服务都应该有本身的数据存取逻辑和独立数据存储。开发团队能够根据服务和数据性质的不一样自由选择最适合的数据持久性方法。
避免共享数据存储和访问机制
(图片来源:http://t.cn/RcLB5Kv)
✅ 智能端点和哑管道:每一个服务都拥有一个定义良好的外部通讯API,并尽可能避免泄露实现细节。通讯则始终使用简单协议,如基于HTTP的REST协议。
✅ 异步通讯:当跨服务使用异步通讯时,其余服务不会阻塞数据流。
同步消息和异步消息传递
(来源: http://t.cn/EAA9xRU)
✅ 避免服务耦合:服务应保持松耦合和高内聚。产生耦合的主要缘由包括共享数据库模型和严格的通讯协议。
✅ 分散开发:避免在多个服务/项目之间共享代码库、数据架构或开发团队成员。让开发者从源头上关注创新和质量。
✅ 将领域知识排除在网关以外:让网关处理路由和跨服务问题(如身份验证、SSL终端等)。
✅ 基于令牌的认证:不要在每一个微服务级别实现安全组件,由于这将须要组件与集中式/共享用户存储库对话并检索身份验证信息;而是考虑实现API网关级别的身份验证,使用普遍使用的API安全标准,如OAuth2和OpenID Connect。一旦从认证提供者得到令牌以后,就能够用于与其余微服务进行通讯。
使用OAuth2和OpenID Connect的微服务安全性
(来源:Kasun’s Blog http://t.cn/EAACGvY)
✅ 事件驱动性质:既然人能够成为对事件做出反应的自主主体,系统也能够。(参见:为何微服务应该是事件驱动的:自主性与权威性 http://t.cn/EAACWOx)
✅ 最终一致性:因为微服务的高内聚特性,很难在整个系统内实现很强的一致性。所以开发团队必须处理最终一致性。
✅ 容错:因为系统由多个服务和中间件组成,所以在某些地方可能很容易发生故障。对于这些薄弱环节,有一些实现模式,如断路器,防水舱,重试,超时,快速失败,故障转移缓存,速率限制,负载释放,能够将重大故障的风险降到最低。(参见:设计一种面向故障的微服务体系结构http://t.cn/RChKlg9)
✅ 产品工程化:把微服务工程化为一种产品,而不是做为一个项目,可让微服务更好的发挥做用。这意味着,不能仅仅考虑能用并且及时交付,而是要长期致力于卓越的工程化。
4、微服务实践
什么时候使用微服务
微服务架构最适合的应用场景:
具备高可伸缩性需求的应用
对交付速度要求较高的项目
具备丰富域或多个子域的业务用例
小型、跨功能的开发团队协做开发大型产品的敏捷环境(请参阅:微服务架构的真正成功故事 http://t.cn/EAANng7)
一些实现微服务的入门框架
Vert.x:轻量级,易于理解/实现/维护,多语言支持(支持多种语言),事件驱动,非阻塞,能够说,具有了以最少的硬件处理高并发需求时的最佳性能和可伸缩性,而且具有足够的开放性(与传统的限制性框架不一样,Vert.x只提供有用的组件,开发人员能够自由地创新并仔细构建他们的应用程序)
Akka:使人满意的性能,实现了Actor模型(一种并发模型),有利于响应式微服务和事件驱型微服务
Spring Boot/Spring Cloud:容易上手(采用熟悉范式),基于良好的旧Spring框架,有点重的框架,许多集成可用,大规模的社区支持
Drop Wizard:有利于RESTful Web服务的快速开发,它搭载了一些不错的Java工具和库,如Google Guava、Jetty Server、Logback、Hibernate Validator、Joda Time、Jersey和Jackson。
部署选项
容器:有利于执行DevOps目标(快速开发,缩短上市时间,无缝缩放)
云计算架构:有利于构建可靠和可伸缩的基础设施,为地理位置分散的用户服务。
无服务器架构:适合处理高度不稳定的流量。
维护本身的IT基础设施:对那些拥有足够能力和资源建设整个基础设施的组织来讲是件好事。
微服务的开发理念
自给系统:由独立系统组装软件(按业务垂直切分系统)
微前端:将单体应用的Web UI划分为独立的特性,这些特性能够做为独立的UI组件开发,并直接与微服务进行通讯。
须要搜索和学习的关键词
领域驱动设计(DDD)| 有界上下文(BC)| 聚合持久性(PP)| 命令和查询责任隔离(CQRS)| 命令查询分离(CQS)| 事件溯源(ES)| CAP定理 |最终一致性 |十二要素应用 |SOLID原则 |
5、参考架构
用于在线购物应用程序的微服务体系结构
(图片:microsoft.com)
此体系结构是由使用Microsoft技术的Microsoft开发人员提出的。在这里,API Gateway是针对不一样的Web和移动用户而定制的。对于数据层,数据存储技术是根据业务功能仔细选择的(关系数据库用于结构化数据,Redis用于临时数据缓存,MongoDB和Cosmos DB用于非结构化数据)。事件总线处理服务间通讯。撇开技术不说,这是基于微服务的应用最多见的集成模式。
一种非阻塞应用程序的微服务体系结构,该应用程序使用来自各类事件源(例如交通数据、天气指数、股票市场线索、社交媒体帖子、传感器输出)的大量输入数据流来向最终用户显示实时更新。这些输入数据流最初由使用Kafka实现的事件日志收集。它将数据保存在磁盘上,所以能够用于批处理调用(分析、报告、数据科学、备份、审计)或用于实时调用(运营分析、CEP、管理仪表板、警报应用程序)。上图中,使用Spark按指定的时间间隔,将持续的输入数据流划分为微批次,并输入到WSO2 Siddhi CEP引擎中。后者标识事件并使用MongoDB存储以非结构化形式存储数据。微服务调取这些数据并显示给最终用户。仔细观察这一设计, Vert.x事件总线可以建立与前端UI组件的链接,该特性仅用于有效地更新UI中的相关部分。撇开技术不说,这是基于事件驱动的非阻塞微服务应用程序的一个很好的架构。
用于订单管理应用程序的云原生泛渠道微服务体系结构(图片:ibm.com)这个设计的一个主要特色是,IBM架构师没有使用API网关,而是为每一个客户端通道(移动应用程序、Web应用程序、IOT设备、API使用者)提出了一个具备独立后端的边缘层。另外一个特色是将微服务层划分为业务逻辑层和基础层两个子层。基础层(即核心服务层)使用各类云原生服务(云数据存储、集成和索引Watson会话的Elastic搜索引擎)处理持久化和集成任务。业务逻辑层集成了基础层的数据,并提供了有意义的业务功能。这将是一个很好的架构,能够为地理上分散的大量用户群提供服务,并经过各类平台访问应用程序。