王作敬
作者王作敬·2018-12-05 13:50
管理信息系统总监·银河证券

微服务间是协同关系,某个微服务不依赖于其他微服务而独立存在

字数 3507阅读 6407评论 0赞 6

作者:汪照辉 王作敬


在微服务规划和微服务构建阶段我们一直在思考微服务之间的关系该怎么来描述。在讨论微服务之间关系的时候我们经常会用“服务依赖”,但是我们觉得并不是很合适。“服务依赖”可能会让我们在规划和拆分微服务时误入歧途。因此我们没有把服务间的关系定义为依赖关系,经过长时间的思考和推敲,我们称之为“协同关系”。微服务之间是平等的,虽然一些微服务需要调用其他微服务来共同完成业务逻辑,但每个微服务都是独立的。每个微服务都可以不依赖于其他微服务独立存在、独立部署、独立运行。就像人类社会之每个人之个体,都是独立的。虽然通过家庭关系、亲戚关系、社团关系、政治关系等联系在一起,但每个人之于社会来说,是独立的,具有完全行为能力。这也让我们在微服务规划和构建阶段就需要考虑微服务的容错性,而不是依赖性,一个微服务出现异常,理论上不应该影响到其他微服务的正常运行。微服务间是协同关系,某个微服务不依赖于其他微服务而独立存在。

一、 微服务层次划分

在微服务设计和构建阶段,首先我们提取了基础组件服务,以及公共业务组件服务。但通常情况任何一个业务应用系统都会有很多业务处理流程,每个业务处理流程完成特定的功能。每个业务流程又是由许多流程处理节点组成,每个节点完成一个操作,每个操作又会涉及数据的输入输出。到这里我们已经遇到了应用、流程、操作、数据。我们需要关注的是数据从哪里来,在哪里产生新的数据,最终流向哪里。产生新数据的地方是核心节点,需要重点关注。比如客户开户流程中,重点是客户信息、账户信息生成的地方。以主数据思想来看,客户、账户是主数据,客户、账户可以分别构建为“客户微服务”和“账户微服务”。客户开户流程构建为“客户开户业务微服务”,负责完成客户开户功能(当然还会涉及风险等级评估、营业部、客户经理等,暂简化考虑);最后由客户开户流程、客户基本信息管理流程、客户交易等流程共同构成“客户服务应用微服务”。基于这些考虑,我们定义微服务为三个层次:应用微服务(或叫应用服务,比如“客户服务中心”提供众多客户服务能力,类似于应用系统了,“微”相对而言只是称呼)、业务微服务和原子微服务。
wg6zmuso3ms

wg6zmuso3ms

但是有时候有些原子微服务其实还是很庞大的,比如客户微服务,客户可能有基本信息、扩展信息、联系信息(不同的联系方式)、关联信息(关联人、关联机构)、地址信息(多个联系地址)、证件信息(多个证件信息)等,可能需要把微服务拆分为几个“子微服务”,子微服务依赖于其原子微服务。他们之间是紧耦合的关系,可能是为了业务便利性或功能实现便捷等原因进行了拆分。比如客户大多数时候只需要基本信息,在维护联系信息的时候才会用到联系信息,在做关联分析的时候才会用到关联信息等。因此我们把“客户微服务”拆分为了若干个“客户子微服务”。
我们不把子微服务作为原子微服务的原因是基于主数据思想来考虑的。为了更好的理解和拆分、构建微服务并用于实际的业务中,把主数据实体作为微服务拆分和设计的基准,并明确这样的粒度标准和规范。

二、 服务间协同

我们定义微服务之间关系为协同关系,怎么协同是个问题。首先每个服务的每个操作所花费的时间是不一样的,但对于终端用户来说,用户体验却是取决于延迟最大、响应最慢的那个操作的。这也符合木桶原理,桶里能装的水量取决于最短的那块木板。
要多装水,提高响应速度,降低延迟,就需要考虑其他的方式,比如提前准备好数据放置于内存,或者主动推送数据而不是等待请求到来等方式。总的来说可以分为主动和被动数据准备方式。
fnw29a99b1t

fnw29a99b1t

(此图仅是思维导图示意,并非实际业务)

(一) 被动数据准备

通常情况下我们实现服务之后部署,然后等待业务请求的到来,然后处理请求,返回结果。大多数情况下也是没有问题的,但遇到并发量大、负载压力过大、处理延时增加时,可能会导致前端获得响应非常慢。当然可以通过限流等措施保证服务不会崩溃,但部分客户体验就会变差。目前实现方式可以是自动弹性扩展服务实例,实现负载均衡,保证负载和延时在一个合理范围内。

(二) 主动数据准备

主动方式不用等待客户请求到来,而是实时推送数据给客户,这需要事件处理平台的支撑。终端用户端需要实现事件监听或回调机制。我们觉得微服务复杂的地方在于不同场景实现方式可能是不一样的,甚至一些场景可能需要采用混合的方式实现。主动数据准备可以应用在需要返回大量数据,等待时间比较长的场景,也可结合内存数据网格等技术来实现。以此来降低延迟,提高响应速度,提升客户体验。

(三) 最短链路原则

这其实是非常让我头疼的问题。开发员(特别外包人员)才不管调用链路多长,他关心的是把功能实现了就ok了,等出问题后就推说为服务设计的问题。所以我们不得不提出最短链路原则。业务微服务和应用在实现的时候一定要考虑最短调用链路,优化最短链路。服务化是一个持续改进的循环过程,不是一蹴而就、一步到位,再说一步到位了也就体现不出开发人员的价值了。所以不要怕麻烦,需要逐步完善。

三、 由问题到方案

微服务协同可能是微服务整个管理治理体系中最繁杂的事情。需要虑版本问题、容错、注册、扩展和负载均衡等。

(一) 版本管理

微服务之间的协同最先遇到的问题可能就是版本问题,微服务是持续改进的,所以微服务版本是不断变化的。我们不可能保留和运维所有版本,所以只能保留最新或者最稳定的一个或几个版本。一个微服务若有多个版本,分别被不同的微服务调用,微服务多了就成了一团乱麻。
微服务的第一个版本管理问题是测试。不同的微服务版本如何快速构建相应场景的测试环境是需要认真考虑的。比如使用测试挡板工具或API网关等实现不同版本不同测试域的快速构建。
另一问题是生产运维。也许你已经习惯听到灰度发布要求,或者金丝雀发布。一个业务应用中的微服务可能是不同的版本。既然是不同版本,那就看作是一个新的微服务,不纠结于版本问题。

(二) 容错

服务间协同,不管主动或被动方式,需要考虑容错问题。在服务协同调用出现异常的情况下,能返回合适的数据呈现给客户是赢得高满意度的关键。我们不建议出错的事情返回一个“error”,比如客户做产品查询,网络意外导致查询失败,这种情况下可以使用缓存数据或备份数据返回给客户。并及时启动相应流程确保下次查询或主动更新查询结果。
当然不同场景容错处理措施是不一样的。这需要根据实际的业务和条件来决定。

(三) 微服务注册

微服务注册会和微服务实例数有关,是每个微服务实例都注册一个接口?还是一个微服务的每个实例都注册一个接口,实例间实现负载均衡?这和下一个要探讨的微服务弹性问题相关,在此就不再赘述。

(四) 扩展和负载均衡

微服务弹性是微服务生产就绪的一个条件,这通常需要容器基础设施平台来支撑。为了更好的理解这两个问题,我们分为业务层和容器层,业务层是微服务概念,不考虑微服务实例,容器层部署微服务实例;业务层微服务对外提供唯一的接口,容器层实现微服务实例的弹性及请求的负载均衡处理。

四、 构建一个稳定的可重用层

微服务最终会以接口API的形式呈现。我们希望微服务实现逻辑的变化最好不影响接口,保持接口不变,甚至某些非兼容性的更改对外也可以是同一个接口呈现。这就要求我们考虑实现的接口层应该稳定,不管内部怎么变化,对外的接口API没有变化。通过稳定接口层的映射对外提供标准API。
目前可以通过API网关来构建一个稳定的接口层。无论微服务实现逻辑如何变化,比如从表中查询逻辑替换为“分表”或者“分库”或者“分区域数据中心”的实现,通过API网关对外的接口都没有变化。这样我们就有了一个相对稳定的API接口层,所有使用这些API的服务或应用对API提供者的变化是无感的。
myylk65g8ar

myylk65g8ar

当然还有非兼容性的版本更新需求。所有非兼容性的版本我们都把它当作是一个新的微服务,在API网关层映射为API新版本,不影响原版本的正常运营。

五、 构建开放接口集市

微服务越来越多,API也越来越多,很难靠人来管理协调服务间的协同关系。这就需要通过一个API门户来实现自服务能力,即API接口集市。API集市提供所有开放可用的API定义和使用说明,客户可以根据需要来选择合适的API实现自己的业务逻辑服务。
在API集市,通常需要考虑开发接口对应服务的级别,我们建议区分为原子微服务和业务微服务,要尽可能避免业务链路的无意识增长。通常情况下,在API集市开放原子微服务接口、或者进行接口分级,并在接口说明中介绍此接口所调用的其他API接口。
构建稳定的接口层和开放接口集市的目的是提升微服务之间协同的自服务能力,减少第三方协调的时间成本,提升快速的响应能力。

如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!

6

添加新评论0 条评论

Ctrl+Enter 发表

作者其他文章

相关文章

相关问题

相关资料

X社区推广