作者:人月神话,新浪博客同名
今天我准备重新讲解下微服务的基础概念,关键组件和组件间关系等核心逻辑。这篇文章我会对我原来写过的微服务类文章内容进行大量重构,去掉里面比较技术化的内容,而转为一种非开发人员也容易理解的方式来讲解。
最近我思考比较多的一个词就是概念模型,不管新知识的学习,新事物的认知,新领域的快速切入还是面对新问题的快速分析和解决,认识和理解概念模型都是相当重要的一个步骤。
概念模型本身是我们认知事物核心框架和基础逻辑的自我可理解的最简模型。
这里面有几个关键点,其一是对事物形成基础认知,其二是最简和最容易模型,其三则是对我们自己最佳适用的模型。
每个人的知识积累和经验不同,最适用于他们的概念模型就是不一样的。因此对于有理论和实践经验积累的人,你可能并不需要用简单的方式阐述事物,有时候连比喻都不需要,而对于初次接触陌生领域的人来说,那么对核心逻辑的形象比喻就显得相当重要了。
一个事物只有在自己脑海里面形成了初步的概念模型的时候,才能够算对该事物有了初步的认识,接下来才谈得上如何层层剥茧和分解,深入到内部机理进行深入了解。这和我们在学习方法和模式里面谈到一开始的学习应该是不求甚解是一个道理。
只有搭建了大框架,理清主脉络,你才可能有目标和有兴趣深入。
但是实际我们仍然看到,包括很多人员头脑里面仍然是采用了SpringCLoud框架,采用了Http Rest接口服务集成或API网关就是微服务了。而对微服务架构思想的本质并没有形成完整的理解,这些都是我们在学习新知识,认识新事物时候必须要避免的。
我们先看下当前互联网上对微服务的主流定义。
微服务可以在“自己的程序”中运行,并通过“轻量级设备与HTTP型API进行沟通”。关键在于该服务可以在自己的程序中运行。通过这一点我们就可以将服务公开与微服务架构(在现有系统中分布一个API)区分开来。在服务公开中,许多服务都可以被内部独立进程所限制。如果其中任何一个服务需要增加某种功能,那么就必须缩小进程范围。在微服务架构中,只需要在特定的某种服务中增加所需功能,而不影响整体进程。
微服务不需要像普通服务那样成为一种独立的功能或者独立的资源。定义中称,微服务是需要与业务能力相匹配,这种说法完全正确。不幸的是,仍然意味着,如果能力模型粒度的设计是错误的,那么,我们就必须付出很多代价。
看完上面的图后,估计还是很难真正抓住微服务的关键点。
在我很早就谈到过,在理解和认识一个概念的时候,你一定要用和你已有的知识概念做对比,进行差异分析,你就很容易抓住要点在哪里。
而要了解微服务一样,你了解了和传统单体应用的差别,基本微服务核心就了解了。简单来说微服务本身就是将传统的单体应用大拆小,然后通过一种轻量高效的标准接口进行协同的架构模式。
为了更好的解释微服务,包括后面对微服务很多关键组件的解释,我们需要准备一个业务系统功能常见来进行举例说明,具体的背景如下。
当前我们准备构建一个SRM供应商关系管理业务系统,这个系统经过前期业务和需求分析,包括了供应商管理,物料管理,招投标,供应商绩效评估四个功能模块。当然在构建整个系统的时候还有类似底层的系统管理,流程引擎等技术模块组件。
我们要构建的SRM系统就是典型的单体应用,那么我们来看这个单体应用构建模式转变到微服务构建模式后究竟带来了哪些变化。如下图,我们从开发态和运行态去分析。
从这个图我们基本就把微服务核心的关键点看清楚了。即:
以上实际上就是我们经常谈到的微服务区别于单体架构最关键的几个点。在掌握了这个核心概念后你才清楚哪些不是微服务基本特征。比如微服务必须容器化部署,没有这个说法,微服务也可以传统方式部署。还有就是微服务开发必须前后端分离,实际上也没有这个说法,前后端不分离只要微服务间完全纵向解耦就是微服务架构。
如果按照上面的模块拆分进行独立的设计,开发和部署,完全是符合微服务架构的思想的。但是是否符合SOA和中台能力共享思想呢?
将数据提供和形成数据的流程分开形成分层
我再强调下SOA和中台里面的一个关键思想,即:
你要去找到你的核心业务能力提供,而不是马上去关心你的能力或最终数据是如何形成的。能力最终提供属于中台能力,能力如何形成的可以属于前台应用能力。
比如上面谈到的供应商,物料两个微服务,我们发现核心就是提供可共享的供应商和物料数据能力。但是这两个数据如何形成的? 一方面是可以直接在后台录入,一个方面还是可以是供应商自己进行供应商认证申请,我们审核通过后进入到供应商库。
那么供应商数据本身属于中台能力,供应商信息的申请流程可属于前台应用功能。
是否严格的逻辑层和数据库1对1对应?
这个是我今天想拿出来讨论的第二个问题,即很多人在进行微服务架构设计的时候往往走两个极端。或者是数据库不拆分就一个大库,或者就是数据库完全按微服务1对1拆分。那么我们上层规划的20个微服务,是否就一定有20个对应的数据库实例ID?
在数据库拆分细一定带来我们在设计实现时候两个问题
以上两个问题不仅仅是带来的开发工作量,而且更重要的是影响到数据一致性。
正是由于这个原因,我们提出一个微服务集的概念。
微服务集的意思可以理解为逻辑层仍然按照标准的微服务要求去构建,每个逻辑层都可以编译可独立部署的Jar包。但是对应微服务集里面的多个微服务可共用一个数据库。
而基于上面场景,供应商和物料本身关联业务场景相当多,放在一个数据库显然是更加适合。经过重新思考后,我们整体的逻辑架构变化为:
基于实际业务场景驱动,对微服务初步设计重构后体现为两点
在完成基本的拆分后,我们来看拆分完成后的三个微服务模块如何交互。
如果我们仍然把SRM看成一个大的应用,并且SRM系统的能力接口不需要对外暴露,不需要互联网App应用协同的时候。在这种情况下,走微服务架构体系里面的服务注册中心来完成接口交互。简单来说就是微服务间的接口消费调用是一种去中心化的架构模式。
我们以供应商申请微服务,需要在申请审核通过后,调用供应商管理提供的信息导入API接口将数据导入到供应商管理模块中来举例说明。
从图里面可以看到整个过程简单的三个关键步骤。
为何叫去中心化?
从上图整个过程可以看到,整个服务调用只有获取地址会和数据中心发生关系,实际获取到地址后即是接口的点对点调用,这个时候接口的数据流完全不经过注册中心。
那么获取地址的时候注册中心宕机了怎么办?
所以可以看到一般来说,获取的地址信息都会在本地微服务模块缓存,后续在调用的时候如果注册中心有故障,那么就访问本地缓存的地址信息。对于这点本身又需要稍微展开下分两个实现方式来进一步解释下。
其一,负载均衡的能力在注册中心
在这种情况下,我们每次消费接口,都必须调用注册中心服务来获取最终轮询出来的目标地址信息。只有在注册中心不可用情况下,我们才访问本地缓存。
其二,负载均衡的能力在本地微服务
在这种情况下,只需要获取注册中心的地址信息清单,同时在地址状态变更的时候被动获取注册中心的变更消息推送。那么后续所有接口访问都和注册中心无关。
微服务间交互是否一定是Http Rest接口?
多个微服务如果不对外提供能力,仅仅是内部接口交互,那么Http Rest接口并不是必须的。比如我们常说的Dubbo框架,可以采用更加高效的RPC接口进行交互,而且底层还可以走TCP协议。
但是一涉及到对外能力提供,涉及到主动网络防火墙问题时,一般只能走Http接口交互。
当然你可以理解为,同样一个接口实现,我们可以在内部交互的时候走高效的RPC接口模式,而仅仅需要对外暴露服务能力的时候将其发布为Http Rest接口。
对于一个应用里面的多个微服务需要统一对外暴露接口能力的时候,这个时候就涉及到OpenAPI能力开放平台或API网关,那么首先来解释下API网关。
如何给API网关一个定义?
简单来说API网关就是将所有的微服务提供的API接口服务能力全部汇聚进来,统一接入进行管理,也正是通过统一拦截,就可以通过网关实现对API接口的安全,日志,限流熔断等共性需求。如果再简单说下,通过网关实现了几个关键能力。
从这里,我们就可以看到API网关和传统架构里面的ESB总线是类似的,这些关键能力本身也是ESB服务总线的能力,但是ESB服务总线由于要考虑遗留系统的接入,因此增加了类似遗留系统适配,协议转换,复杂数据映射等能力。
微服务架构不再需要ESB,并且一定是去中心化的?
这是必须要搞清楚的一个问题。
首先看下微服务架构里面确实不需要传统ESB,但是需要一个ESB的轻量实现,即我们说的API网关。因为微服务架构里面都是标准的Http Rest接口,不再存在复杂的遗留接口适配,复杂协议转换等问题。但是我们常说的接口服务代理,统一的安全,日志,流控功能仍然需要。
同时微服务架构内部各个微服务模块间本身是去中心化的,但是当微服务架构里面各个微服务需要对外提供接口服务能力给外部应用使用时候,外部应用和微服务间由于增加了API网关又变成了一个中心化的架构。所以不要一提到微服务就去中心化,这个理解本身也是不对的。
对于API网关来说,核心就是实现两类能力,一个是对API全生命周期管理能力,包括了API接口的注册,接入,发布,测试,变更和版本管理,下线等。另外一个关键能力就是我们常说的安全,日志,流控方面的能力。
而这些能力最常见的实现方式就是通过插件进行拦截处理,如下:
如上图,API网关里面的关键对象注意包括了接入系统(微服务),消费系统,注册接入的API接口,发布的Proxy API接口,在代理和原始服务间有一个路由对象。只要有这些最基本的对象就可以实现最简单场景下的服务接入。
而其它所有的扩展可以看到都应该基于插件式方式的扩展,这些插件包括了安全认证类插件,流量控制类插件,日志监控类插件,转换类插件。
任何一个API接口和插件之间是一种多对多的关系。即一个API接口可以被作用多个插件,同时一个插件本身又可以应用在多个API接口上。插件本身就类似于AOP横切,对服务请求消息的输入和输出进行拦截,在拦截到信息后进行相关的安全或其他管控处理。
当然插件本身一定会损耗性能,在实现的时候需要考虑对服务运行数据,运行统计数据的缓存,特别是对于流控的实时计算过程。
业务场景需求引入网关
还是基于上面的案例,供应商申请流程我们希望开发一个APP应用给用户自己申请。这个APP供应商在公网就可以正常访问和登录使用。
前面谈到,API网关使用重要场景就是需要对外提供服务能力。这个对外可能是和外部其它系统集成,也可以是我们的应用本身会开发外部互联网使用的APP。
在这个时候API网关引入就变成了必须。
API网关本身也实现了外部应用和我们内部微服务间的安全隔离,比如我们把API网关还可以部署到整个基础设施架构的DMZ区等。
是否可以不用API网关?
当然,你也可以不用类似Kong等API网关产品,那么这个时候我们常说的一些共性的安全,日志,限流熔断能力无法实现。但是最基本的代理路由转发能力是必须的,因此你在前期可以使用类似Ngnix来实现请求转发并替代API网关的使用。
下面来看下API网关实现的几个关键功能。其中附带介绍下Kong网关的一些关键能力。
日志拦截和记录
对于日志拦截和记录是最常见的一个API网关功能,但是类似开源的API网关产品往往也仅仅是提供日志输入接口,如果需要对日志进行集中化存储和日志查询分析,仍然需要自己开发相关的功能来完成。
日志拦截简单来说三点
如果整个微服务里面日志产生量大,而且对历史日志的查询时间段也要求较长的情况下,建议将日志存在到分布式文件存储或分布式对象存储中。
可以看到日志信息本身复合服务实例ID+实例报文体这种对象存储结构。
比如我们可以基于Kong网关的扩展能力来自己开发日志记录存储和查询插件,对于Kong网关来说插件的定制化开发能力相当强。
一个是sysLog在配置后可以直接将Kong产生的日志写入到应用服务器的系统日志文件中。如果配置了file-log则是单独写入到你指定的file文件中。对于http-log则是对于http服务请求,可以详细的记录请求的输入和输出报文信息,但是具体是记录到哪里,需要通过config.http_endpoint配置。
安全功能
对于安全功能我们先简单谈下实际需要哪些安全能力。
最常见的就是接口服务访问控制安全能力,即API网关暴露的一个接口,必须通过安全认证通过后才能够访问接口。供应商信息导入API比如你授权给供应商申请流程微服务模块(SUP)使用。那么可以看到常见的一些方法。
但是对于方法1容易出现用户名密码泄漏或被截取;第2种方法容易出现IP伪造,或者对于容器云环境IP本身就是不断动态变化你很难去控制。
因此在这种常见下,我们出现了动态Token安全的处理方法。
简单来说就是你每次调用服务前,都先向API网关申请一个动态申请的Token码,然后在调用服务的时候连带上这个token码一起发送过去进行校验,只要校验通过才允许访问服务。
当然对于开源各类API网关产品基本也提供常见的各类安全能力。
比如当前网关提供basic-auth,key-auth、ldap-auth,hmac-auth多种认证插件。
限流熔断功能
对限流熔断的理解,首先本文谈到的服务限流和熔断,和常规我们说的限流和熔断有区别。
具体说明为:
其次,对于服务流控我们需要设置具体要监控哪些指标,注意这个指标监控是在单位时间里面的监控指标,即计算在单位时间的累计数据,当触发后即进行流控。具体包括:
对于运行时长更多是预警,而实际上直接限流和熔断不现实。因此主要的流控指标就是上面这些,基于以上指标本身又有两种操作,一种是限流,一种是整个服务熔断。而实际上可以看到。
限流熔断解除,最后,在还需要考虑的就是在实施了限流和熔断后如何解除的问题,在实际实现的时候,对于限流可以在规定时间后自动解除,而对于熔断最好还是人工恢复解除。
比如对CRM系统访问MDM的查询供应商服务进行限流后,在启动限流后的某个时间间隔后,比如2小时后,可以自动进行解除。这个时间间隔可以灵活配置。
而对于类似Kong网关当前提供的限流相对来说还是比较弱,即主要是控制某一个API接口服务在单位时间内最多只能够调用多少次,如果超过这个次数那么网关就直接拒绝访问并返回错误提示信息。
而在前面我讲限流和流量控制的时候经常说到,就是限流实际上一个是根据服务调用次数,一个是根据服务调用数据量,需要在这两个方面进行限流。而里面更加重要的反而是数据量的限流,因为大数据量报文往往更加容易造成内存溢出异常。
API全生命周期管理包括了API接口的定义,API快速开发的支持,API的注册和接入,API模拟测试和自动化测试,API文档自动生成,API版本和变更管理,API下线,API监控运维等一系列的功能,本部分后续单独文章说明。
基于上面的例子来分析,我们整体感觉进行微服务架构设计和开发并不困难。但是如果站在整体企业应用架构规划视角来看,你会发现有内容遗漏,即技术平台建设。
这也是我们经常在强调的,共性技术平台能力下沉是进行微服务开发的基础。
还是以上面的例子来进一步分析。
四个模块都需要用到系统管理和工作流引擎,那么我们在进行微服务拆分后,不可能在每个微服务里面还各自含有相同的4A系统管理和流程引擎等共性技术能力。
即共性技术能力下沉,然后共性技术服务能力给微服务使用是必须的。
对于系统管理和流程引擎本身也是一个或二个独立建设的微服务。
企业要进行微服务架构规划和建设,那么最基础的技术平台规划建设,将共性技术能力从传统遗留系统移出,作为微服务功能模块单独建设并能力共享,是基础的基础。
微服务架构思想实际上是包含了平台+应用思想,业务组件化服务化思想,SOA和云思想,包括当前主流的DevOps思想的一个融合,而不仅仅是简单的微服务架构。
因此企业在转型到微服务架构时候必须重新规划和建设技术中台能力,包括前面的遗留问题分析我们也看到共性技术能力下沉是微服务建设的基础。共性技术能力下沉后,微服务才能够只关心业务而更加轻量。
首先我们对整体规划建设进行拆分,主要应该包括以下关键的建设任务和内容:
底层私有云IaaS平台建设
在建设时候可以基于IaaS资源池进行并尽量去IOE架构。当前实际上对于数据库仍然会涉及到部分的Oracle数据库和集中存储,企业在选型和规划的时候要考虑去掉这部分潜在风险。
服务器资源可以考虑全部采用X86服务器并进行虚拟化,提供虚拟机资源作为计算能力。
容器化PaaS平台建设
对于PaaS平台建设当前可以基于轻量的Docker容器进行,并通过Kubernetes进行资源管理和动态调度。而如果规划建设DevOps支撑平台,即在DevOps平台建设过程中统一建设容器化PaaS平台,当然在DevOps平台中会进一步实现了持续集成和流水线作业能力,实现开发,运行和后期运维监控的一体化管理。
微服务开发框架和环境
在微服务架构实施中,还有一个重点就是制定微服务架构开发框架,标准和规范体系,以指导后续开发厂商按照统一的标准方法、工具和流程进行微服务组件模块和接口服务的开发,确保开发标准和规范一致性,也进一步确保了后续多个微服务模块在集成的时候不会出现问题。
把这些都谈后,再转回谈需要统一建设的技术平台部分:
4A平台和系统管理
这个是必须建设的内容,不仅仅是实现统一用户,统一认证和鉴权,统一组织,统一审计等内容。在微服务架构下,4A平台需进一步扩展传统业务系统中系统管理模块的内容,即能够实现到微服务模块内部的功能菜单和按钮级的操作授权,同时能够实现灵活定义的数据级授权和配置。
公共流程平台
这个公共流程平台也是必须,实现统一的类似内部多租户的流程引擎,实现流程的设计建模,运行,监控的全部统一化。各个业务组件模块仅仅是使用流程平台提供的能力。
技术服务平台
这个实际涉及到消息,缓存,文件,任务,日志,通知,分布式存储等诸多技术服务能力,可以根据企业需要来确定哪些要单独实现为独立的技术服务能力开放提供。这个没有明确的要求,但是根据实际项目实践来看,类似发送短信邮件的通知类服务,文件存储类服务往往都是必须要规划建设的。
监控运维平台
这个平台实际上包括了传统的IT网管监控,同时还包括了当前的APM业务性能监控两个方面的内容。同时两者内容本身又相互集成和融合。由于采用了容器化PaaS,实际上微服务开发商对底层资源的情况并不清楚,因此更加需要这样一个监控运维平台能够同时监控到业务性能和资源层性能,并实时预警。
对于微服务架构设计,要明白远远不是采用了类似SpringCloud微服务开发框架,或者说采用了Http Rest接口服务就是微服务架构,更加重要的还是业务能力的组件化或者叫微服务模块化,组件能力的接口服务化。对于微服务架构设计,可以思考的关键点如下:
基于业务交互分析划分合理的微服务组件模块
微服务模块划分是否合理将直接影响到后续微服务模块的开发集成和实施难度。
看到很多例子就是一个本来很小的业务系统居然会划分出20多个微服务模块,每个模块全部采用单独的容器部署。这个在互联网应用里面可能适合,但是在企业微服务架构转型里面一定不适合。
模块划分越细,模块间接口交互和集成就越复杂,后续微服务的运维管控治理就越难。
如何划分?一个传统的业务系统建议最多拆分为6到8个微服务组件,对于纵向流程工单驱动型由于本身耦合小可以划分的更细,但是其它类似核心业务数据驱动型都不要划分太细。
面向接口开发同时识别粗粒度的服务接口
微服务在架构设计阶段除了技术架构外核心就是两个事情
注意微服务模块间的接口要提前进行识别和定义,从顶向下面向接口开发,这本身也是传统架构设计就遵循的原则。一定不能是一开始不定义接口,后续各个模块开发到哪里了发现接口缺少再临时仓促定义,这个带来的最大问题就是接口粒度管理失控,后续运维也失控,导致大量的接口重复定义等。
如果你是采用Http Rest接口,那么你更要了解面向资源设计和领域建模的概念,怎样定义才算得上是面向资源的,而不是简单的随便定义Http API操作。
在架构设计阶段就完成数据库拆分设计
注意在微服务架构设计阶段一开始就应该完成数据库拆分,每个微服务模块对应独立的数据库。
一定要注意微服务一定不是简单的应用组件拆分,而是包括了后端的数据库也有拆分,这样才是完整意义上的微服务架构。同时拆分后的数据库间不应该有交互和集成,所有的交互和集成都应该通过应用组件层的API接口服务进行。只有这样才是完整意义上的微服务架构。
搞清微服务注册中心和微服务网关的区别并按需使用
在一个完整的微服务架构里面涉及到微服务注册中心和微服务网关,务必注意到两个组件的区别并按需使用。简单来说就是一个微服务架构应用内部所有的微服务模块组件之间的接口交互都只需要通过注册中心来完成即可,这种方式是性能最佳,去中心化的方式。当一个微服务架构应用需要和外部交互,或者说需要开放能力给外部业务系统使用的时候才需要将API接口服务接入到微服务网关或API网关。
做好开发团队划分和微服务模块划分之间的匹配工作
在微服务架构设计做好了微服务模块划分后,另外一个重点工作就是做好开发团队的划分和匹配工作。按道理这个不属于微服务架构设计的内容,但是属于整个研发过程和项目管理的内容。
开发团队的划分基本要做到和微服务模块划分匹配,能够完全隔离和松耦合是最好。
要明白,如果一个人负责多个微服务模块,那我们原来定义的微服务模块间的接口规则,交互规则,技术标准规范很难真正做到彻底执行。
即多个微服务模块间协同变成一个开发人员内部管理的事情,那么开发就容易怎么方便怎么来,而忽视了关键的架构规则和约束。也就是到最后你会发现,分配给一个人负责的多个微服务模块,本身一开始是松耦合的设计,但是最后完全变样为难以拆分的紧耦合关系。
面向产品集成和持续集成而设计
在微服务架构设计的时候,必须要考虑到产品集成和持续集成。对于持续集成可以参考标准的持续集成方法,也可以参考DevOps标准过程体系以实现持续集成和持续交付,当然在整个过程中可以和容器化PaaS平台融合,进一步实现持续交付过程的自动化。
另外在整个架构设计中的模块划分和接口设计的时候,还需要考虑到整个产品集成顺序,即一个大系统划分为了多个微服务模块,他们之间的构建顺序,集成顺序究竟是如何的?为了更好的实现产品集成,原则上应该是基于完整的业务流生命周期,模块之间更多的是由上游流程到下游流程进行逐层集成,同时尽量要避免双向集成导致后续集成测试很难进行集成和组装。
对于DevOps研发运维一体化,持续集成和持续交付,以及DevOps过程支撑平台如何和微服务架构设计开发,研发过程管理更好的协同,我后面会专门再写一篇文章进行描述。
面向业务和应用监控运维而设计
要注意在微服务架构下实际上是独立自治的微服务模块变多,接口变多,集成关系更加复杂,这些都直接导致了后续业务和应用监控更加复杂。很多企业在进行微服务架构转型的时候,由于后期的自动化监控运维能力跟不上导致最终转型中出现大量的问题无法解决,这些也是在架构设计时要考虑的。
即在进行微服务架构设计的时候,要基于DevOps的思想,将很多可监控,可运维需求作为关键的非功能性需求纳入到架构设计中,在微服务模块间的接口服务设计的时候都需要加入这些设计原则和关键属性,以方便后续进行业务监控和服务链监控,同时在业务出现问题的时候能够快速定位。