- 可伸缩性
- 可用性
- 弹性
- 独立,自治
- 去中心化管理
- 故障隔离
- 自给自足
- 通过DevOps持续交付
应用所有这些原理带来了一些问题与挑战。让我们来讨论这些问题以及它们的解决方案。
1.分解模式
a.按业务功能分解
问题
微服务就是应用单一职责原则使服务松耦合。然而,将一个应用程序分解开来必须拥有逻辑性。如何将应用程序分解成小的服务呢?
解决方案
一种策略是根据业务功能分解。一个业务功能就是一个业务创造价值的方式。业务的功能集取决于业务类型。例如,保险公司的业务包括销售,市场,保险,索赔处理,记账,审计等等。每个业务功能都可被视为一个服务,只不过是面向业务而不是面向技术的。
b.按子域分解
问题
按业务功能分解是一个良好的开端,但是你可能会“邂逅”不易分解的“上帝类”。这些类会在多个服务中出现。例如,Order
类会用于订单管理,取订单,订单配送等。这些该怎么分解呢?
解决方案
对于“上帝类”,领域驱动设计(DDD)疾驰来援。它使用子域及有界上下文概念来解决这个问题。DDD将整个领域模型打破,分成子域。每个子域都有一个模型,模型的范围被称为有界上下文。每个微服务都会围绕有界上下文开发。
注意:找出子域并不是一个容易的任务,需要对于业务逻辑的理解。像业务功能一样,子域需要分析业务及组织结构并分析不同的专业领域才能找出。
c.绞杀者模式(Strangler Pattern)
问题
目前,我们讨论的都是分解未开发的应用。然而,我们80%的工作是重构已开发应用,它们都是一些大块头的一体化应用。应用上面的设计模式会非常困难,在它们还在使用时将它们分解开来是一项艰巨的任务。
这不禁让我想到一则笑话:
一位著名心脏外科医生的摩托车引擎坏了,送到修理部去修理。修理工熟练地将引擎拆下来,修好后又装上。他对医生说:“引擎是摩托车的心脏,咱们两都是修理心脏的,可收入的差距为什么这么大?”医生想了想,对修理工说:“你修车的时候别熄火试试”。
解决方案
使用绞杀者模式。绞杀者模式就像藤蔓缠绕杀死一棵树。在web应用中,这个方式工作的很好,对于每一个URI请求,服务可以被分解成多个域并作为单独的服务来部署。方式是每次处理一个域。这在一个URI空间上产生了两个单独的应用。最终,新的应用绞死了原有应用,最后你就可以“砍掉”一体化应用。
2.集成模式
a.API网关模式
问题
当应用被分解成小服务以后,有几个问题需要解决:
- 如何调用多个微服务生产者。
- 在不同的通道上(桌面,手机以及平板电脑)需要同一个后台响应不同的数据,因为UI可能不同。
- 不同的消费者可能需要不同的数据格式。谁来做数据转换?
- 如何处理不同的协议,有些协议微服务生产者可能不支持?
解决方案
API网关有助于解决微服务实现导致的许多问题,不限于以上提出的那些。
- 一个API网关是对任意微服务调用的单一入口点。
- 可以作为一个代理服务,将请求导向正确的微服务。抽象提供者细节。
- 将一个请求辐射至多个服务并将结果聚合返回给消费者。
- 通用型API不能解决所有消费者的需求,这个解决方案可以为每种客户端类型提供细粒度的API。
- 可以做协议转换,例如AMQP转为HTTP。
- 可以为微服务卸下认证/授权的职责。
b.聚合模式
问题
在API网关模式中,我们已经讨论了聚合数据的问题。这里我们会全面地再说一下。将业务功能分解为小的逻辑代码块以后,有必要思考一下如何让每个服务返回的数据协作。这个任务不能留给消费者,因为这样的话它们可能需要了解生产者的内部实现。
解决方案
聚合模式是关于如何将不同服务的数据聚合,并将它们返回给消费者的。这可以用两种方式实现:
- 一个复合微服务调用所有需要的微服务,合并并转换数据。
- API网关也可以将请求分到多个微服务,并聚合数据。
推荐的做法是,如果有应用业务逻辑就选择第一种,否则,就选择第二种。
c.客户端UI组合模式
问题
当服务被分解成业务功能与子域后,用户不得不从多个微服务获取数据。在一体化的世界,通常只需要一个请求就能取到所有数据,然后就可以刷新或提交UI界面。现在不再是这样了,我们需要知道如何去做。
解决方案
使用微服务,要像骨骼那样设计UI,让它包含多个页面节点。每个节点会请求对应的微服务获取数据。真称为针对服务的组合UI。像AngularJS和ReactJS这样的框架可以很容易实现这种模式。这就是单页面应用(SPA),允许应用刷新页面的一个区域而不是整个页面。