先悟透这三个理念,再来谈如何扩展你的架构

阅读数:1885 2016 年 5 月 29 日

话题:语言 & 开发架构

关于“微服务”大家应该并不陌生,最近”聊聊架构”的各位老师也做了不少分享,我也是微服务架构的热粉以及实践者。其实“微服务”的设计思想很好,它揭示了一种全新的思考方式以及系统设计思路。不过这次分享希望从另外一个角度,谈谈在架构实践中衍生出来的思想方法提炼,我把它们统称为“微智能”。

微智能设计思想

“微智能”这个概念起源于智能家居,是目前智能硬件领域的一股创新思想。早期的智能家居是“电气自动化”。比如电控窗帘是可以通过电气设备进行远程控制开关;第二代智能家居实现了“互联网化”,这时,电控窗帘就可以通过 WiFi,蓝牙等技术与互联网设备相连,于是智能手机就能远程操控窗帘。

重点是第三代智能家居提出了“微智能”的概念,强调通过传感器自动捕获环境信息,并结合人的使用习惯偏好,实现自主调控。这时,智能窗帘会根据时节,气温,光照等信息,再考虑主人的起床 / 午休 / 睡眠时间,甚至从日程安排中提取影响因素来决定窗帘的状态,而此时窗帘也呈现出更多的状态:打开面积,角度,透光度等等(之前是“开、关”两种状态)。

“智能”这个词,通常是相对人而言,智能家居通过体现“智”,更好的服务人的生活;那么作为同样服务人的生产和生活的软件系统是否可以借鉴这种思想?

Bingo,通过实践证明,“微智能”的思想完全可以移植到软件系统架构中。先明确一下定义,这里的“智能”并非“人工智能”(最近 AlphaGo 太火了,对 AI 感兴趣的同学,可以出门左转去看 Google 的 TensorFlow ),是指基于“自动化”手段形成“闭环反馈回路”或“自适应处理”的系统或组件。之所以叫“微智能”,是因为它可以有效地改善系统的”智商”,提升系统的自动化水平,使之更加“聪明”地工作,从而提升系统应急“灵敏”度,降低系统运维成本。

微智能设计思想体现以下几个特征:

  1. 自动发现:即真实地反映现实世界,尽可能利用“自动化”手段收集“输入”数据,这里的数据包括业务数据系统元数据。由于现实世界很复杂,变化快,要么人工整理慢,不及时,要么根本无法处理。

    当然,“自动发现”在互联网里并不新鲜,最经典的就是搜索引擎的爬虫,通过对网页的分析,不断抽取互联网中的信息,但爬虫是从业务层面体现“自动发现”,而“微智能”强调从系统架构,“微”指代系统或系统组件,“智能”体现系统或系统组件之间关联具备“自动发现”的机制。

  2. 自我维护:即形成“闭环”反馈回路,将“输入”或“中间”或“结果”数据反馈到系统中,叠加成新的“输入”或“中间”或“结果”数据。这里强调“闭环”,这是与传统“非闭环”的反馈系统的重要区别,在第二部分会着重说明。

    自我维护与自动发现是相互作用的,因为从真实世界获得的信息会失真,会过期,通过不断迭代地自动发现,使系统不断趋近真实。值得注意的是,由于反馈永远是滞后的,所以迭代的结果只是趋近真实,获得可接受的数据。

  3. 自动适应(适配):适配的涵义很广,从宏观方面,包括系统集成,任务调度,资源管控等,从微观方面,包括数据处理,格式转换,接口协商等。自动适应是基于自动发现,自我维护的延展,是落地“智能”效果的体现。根据自动发现的输入数据适配相应的处理;根据自我维护的反馈,不断调整以达到优化的适配效果。这也是与传统“处理”系统的重要区别,在第二部分会进行说明。

下图是微智能设计思想的关联图:

与传统处理系统比较

这里的传统“处理系统”是指不同时具备“微智能”设计思想特征的系统。一般从应用场景上区分,可分为三类:

  • 业务应用系统:为了完成具体的 Business 需求而建设的系统,在我看来,这类系统大致经历了几代:3T(Three Tier)架构,面向服务的架构(SOA),再到微服务架构。这类系统的特征是,通常输入数据的源头是人,是所有数字世界数据的源头,它通过系统Link 了几方人群形成协作,产生价值。

  • 基础系统:为了支持研发、测试、运维、资源管理等服务而建设的系统。比如 CI 系统、云平台、服务治理、监控系统、自动化测试系统。这类系统的特征是,输入数据的源头大多是系统以及基础设施,它Link 系统和基础设施支持运营。

  • 数据系统:收集并处理各种数据,为业务或运营输出指标型数据。如传统 BI、大数据平台。这类系统的特征是,输入数据来源大多是业务应用系统,输出数据也大多到业务应用系统或直接指导业务生产。

无论是哪一类系统,从抽象的模式上一般符合以下 2 种系统模型:反馈系统分布式处理系统。

1、反馈系统

先来说说“反馈系统”,这个词起源于通信领域,标准定义是将系统的后果或输出信息采集、处理, 然后送回输入端并据此调整系统行为的系统。由于信息流通构成闭合环路,它亦称为闭环系统

“闭环”是反馈系统的重要特征,这里的“闭环”是指系统架构层面,而非业务上的闭环体系(比如推荐系统)。但实际上在传统软件架构中,反馈系统并没有做到闭环。原因可能有以下几点:

  1. 业务需求简单,似乎没有构造闭环的必要,也不考虑业务需求变化快而带来的风险。

  2. 技术栈没有拉通,系统实现者只追求“当下可用”,也不考虑长期运维需求。

  3. 技术实现手段上没有创新,认为构造闭环“不可能”,受传统开发经验束缚。

以监控系统为例,实现对应用的访问监控(如 QPS、响应时间、错误码),传统做法是在应用中加入埋点代码,通过埋点代码收集监控指标数据。这样做的好处是,直接简单;缺陷是代码变更相互影响,代码规模膨胀后不易维护,容易留存“僵尸”代码。当然也有些改进做法,利用后期注入或劫持的方式,比如 JAVA 中可以通过 Weave Byte-Code,但实际上这只是解除了应用代码与监控代码的运行时依赖,在逻辑上监控代码还是依赖于应用代码变更。

如何解决上述问题呢?

首先目前目标,实质上要解决的是如何“自动”获得元数据。监控系统的元数据就是如何定义应用,以什么粒度定义应用的监控指标。通常来说,应用对外提供的服务可以作为合适的粒度。引入“微智能”的思想就是要自动发现应用的服务提取需要的元数据,并且能够在应用代码长期更新过程中,不断自我维护这些服务的元数据,从而构造一个“服务元数据的闭环”。第三部分应用与服务画像会分享这类案例。

2、分布式处理系统

接下来说说分布式处理系统,目前几乎所有软件系统都可以归类其中。标准定义是系统组件通过网络交换数据实现协作的软件系统。

但分布式处理,只强调了数据的交互方式是网络,对如何实施成分布式,数据交互的规则,如何进行协作等并没有清楚的定义。

在“如何进行协作”的问题上,目前存在 3 个问题:

1)配置静态绑定。

多数软件主要采用“中心化”架构和“分层”架构这两种架构模式。例如 3T 是一种分层架构实现:Web 层,逻辑处理层,数据层。处理方向是单向的:Web 层 -> 逻辑处理层 -> 数据层;例如 MongoDB Sharding 是一种中心化实现,将路由信息存放在 ConfigServer,依赖 MongoS 来实现对 Mongo 实例的访问。

以上两种架构在协作上都是依赖于配置的静态绑定。配置中会说明调用关系(IP、端口、URL 等);说明任务角色,当然这种任务角色通常还是静态的,是在软件架构阶段已经明确定义下来的,如 MongoS 就是做代理,ConfigServer 完成配置,Mongo 实例完成存储和查询。

配置静态绑定依赖于许多人工处理,所以当系统规模扩展时,会变得难以维护。改进做法是实现配置中心,让不同任务角色基于配置中心实现协作,这样确实一定程度减少了人工介入,实现了部分自我维护。

2)无法感知全网运行时变化

配置信息体现了协作的静态关联,即便实现配置中心,分布式任务角色仍然不能感知分布式处理系统的运行时变化。比如 3T 中,如果数据层出现了问题,导致数据不能存储或查询,逻辑层需要在执行出现异常后才能得知,通常的做法是切换到数据层其他节点。这种做法的缺陷是如果系统规模较大,容易出现短时多点故障,且可能重复出现,因为系统对这些异常是滞后处理的,系统不能自动调整或适配。

3)无法动态任务分配

这里的任务是指分布式任务,动态指的是编排任务过程的动态化(不是资源使用)。多数的系统由于执行流程是代码 Link,所以任务分配是固定不变的,特别是应用业务系统。近几年随着 Hadoop 兴起,出现了一些任务调度框架 / 平台,各家玩法不同,但大多可以归纳为如下模型:

目前的任务调度只解决了任务分配问题,但实际上任务的编排过程仍然依赖于配置静态绑定(比如任务依赖),所以不能算是“动态”分配。

微智能的思想可以帮助解决上面 3 个问题

1)配置中心化,配置的物理型数据来自自动发现,人只作为关键约束的输入源。关键约束包括资源约束、能力约束、时序约束、业务约束等。

2)运行时变化感知通过自动发现与自我维护建立全网共识数据,这些数据是约束判断的输入数据。

3)分布式任务角色与节点无关化,从物理看起来所有节点是对等的,根据全网共识数据自动匹配符合约束的节点,根据相关约束动态编排任务处理。

需要明确的是,微智能的思想并不是要取代传统处理系统架构,它是其延展,是对反馈,分布式处理的归纳与融合。第五部分的共识计算系统会解释这一点。

接下来的部分是结合实践,通过一些案例说明微智能思想如何落地,以及能够带来哪些积极改善。

应用与服务画像

关于服务化,有两个关键事项:服务注册与发现、服务监控。它们都需要服务的元数据,包括:服务 UUID、服务实例 URL、服务访问 Schema 等。

做法 1:人工梳理,人工配置到服务注册中心。缺陷是在系统大规模发展之后,服务单元的数量巨大,以及服务交互的关系变得异常复杂,人工已经很难精确梳理。

做法 2:运行时注册,即在应用的初始化代码中埋点,这样应用启动时,每个服务将自己的元数据提交到服务注册中心。优点是已经可以自动化地提交元数据了,缺陷是埋点代码依靠人工梳理,对于初建系统是 OK 的,遗留系统改造量大;强烈依赖实施者,实施者的疏漏或错会体现成系统错误;不易维护,由于实施者必须是系统研发人员,埋点代码变更可能跟不上应用代码变更。

而我们在实施服务治理过程中,采用了“微智能”设计,通过对应用进行剖析(Profiling)来获得服务的元数据以及应用的元数据这种剖析,又被称作画像。由于我们这边大部分都是基于 JEE 的 Web 系统,所以通过对应用服务器中间件的改进来获得这种 Profiling 能力,从而实现对应用 & 服务的画像。下图是 Profiling Intercept Framework 结构图:

基本原理是:

1、通过对应用服务器中间件进行扩展,最好是无缝扩展(不改或少改源码),获取介入应用启动以及 Servlet 启动的能力。像 Jetty,GlassFish 之类都是基于 Intercept Chain 架构,所以几乎可以无缝实现;而 Tomcat,Jboss 是早期层级架构,可以采用运行时劫持的方式。

2、通过实现不同的 ProfileHandler(画像处理器)来实现不同的画像。这个过程主要有 2 种方式:

  • 根据工业规范画像。JEE 的技术栈是较完整的官方协议规范(JSR)以及主流框架 Spring 等民间主流协议规范。这些协议规范都清楚地描述了应用、接口的形态、形式,甚至运行机制。

  • 根据环境上下文画像。JEE Web 程序运行都有特定的环境上下文,比如 Jar 包,classes,Java 运行时,工作目录,部署描述符等等。

我们目前针对自身需求实现了对 JEE Web 的应用全画像,包括应用基本信息(名称、root context、存储路径)访问 URL、Jar 包依赖 & 版本等;对服务接口实现了纯 Http、JAXWS、JAXRS、SpringMVC 等工业规范的画像,包括服务名、服务 UUID、服务 URL、服务方法入参 & 出参、服务类 & 方法关键注解等。这样就实现了“服务元数据的自动发现”。

由于 JEE Web 程序更新一定需要重启应用,所以每次重启应用都会进行重新画像,系统将收集到的画像与之前画像比较,就能清楚的分析出应用 & 服务到底做了哪些变更,从而形成了“服务元数据的自我维护”。两者结合就构成了“应用与服务画像的闭环反馈”。

关于应用与服务画像的技术难点,对这个感兴趣的同学可以线下交流,在此次分享不作详述。

自解析数据交互

服务之间调用实际是消息传递处理的过程。一般的调用发生可能只涉及两方系统间,但在实际实践中系统间的复杂集成是很常见的。由于流程处理的复杂性,在一次调用中,会触发多方系统的调用共同完成同一个流程。

一个实际案例是,需要在 VPN 登录过程中实现短信验证。这里涉及到三方系统:VPN 系统(厂商支持不能修改,负责 VPN 验证),短信系统(负责接收短期发送请求 & 发送短信),员工信息服务(能够提供员工手机号)。

由于 VPN 是厂商提供,作为安全考虑不能将员工手机号预先交予,而提供给 VPN 的是视为公开信息的员工 ID,那么 VPN 对短信进行服务调用后,原本为手机号的字段变成了员工 ID,短信系统需要调用员工信息服务来获取员工手机号。

传统的做法是直接将三方系统进行接口对接,这样做虽然能满足眼前需求,但缺陷是:

  1. 如果产生类似需求,短信系统还需要变更,也需要额外维护新需求的代码。

  2. 如果有多个类似 VPN 的调用方,又存在多个类似员工信息服务的协助方,作为服务方的短信系统就会集成一大堆只符合单一需求的代码。

抽象一下如下图所示:

根据“微智能”思想,我们把这个过程变成了这样:

基本原理是:

  1. 在原有服务的基础上,定义一套扩展 Schema,称为自解析数据 Schema。这套 Schema 描述了需要进行协议转换的元数据,包括协助方 URL,协议转换 Schema 关键字,通信技术类型,返回处理提取关键字等等。

  2. 实现一个可扩展的自解析数据执行引擎。它需要能够解析自解析数据 Schema;它的调用实现也是依据工业规范,比如 Http、JAXWS、JAXRS,因此具有通用性;它能够对协助方调用结果进行初步判断(状态、异常等),能够根据自解析数据 Schema 实现返回信息的提取。

这样一来,服务方无需对每种需求进行单独地代码集成,实现了“服务调用的自动适配”;同时形成了“服务调用的闭环”,因为自解析数据 Schema 的实例传播是调用方与协助方完成的,服务方不用参与。

共识计算系统

共识计算系统是“彻底”的微智能系统,是完全基于“自动发现,自我维护,自动适应”理念设计的。共识计算系统就是微智能思想的基本架构模型

解释一组概念:

  • Node:共识计算网络中的每个运行进程,就是一个节点,它们是对等的,没有任务角色之分,Node 是计算的基本单位,也是信息协调的基本单位

  • Feature:是一种计算能力,依赖一组配置。Node 与 Feature 的关系,好比人与人的能力,在社会网络中的节点就是以人为单位的,每个人身上有不同的能力,能力可以获得,更新或失去。

  • Group:是由某些 Node 构成的,一个 Node 可以存在于多个组中,一个 Group 允许被其他 Group 包含,则等同于该 Group 的 Node 也被包含。Group 是信息协调的二级单位,Group 与计算没有必然联系。Node 与 Group 的关系,好比人与社会组织,每个人可以属于多个社会组织,社会组织可能是物理方式或是虚拟方式协调社会信息。

  • 共识信息:在共识计算网络中可以被任何 Node 查询和分享的信息。共识信息可能包含统一的 Schema 也可能是一组 Schema。这好比人类社会中的公开信息,任何人都可以查询和分享。

各类 Feature 解析:

  • 心跳服务:是共识信息的主要收集者,它收集全网或 Group 内所有 Node 的状态信息或感知信息。例如 Node 所在 Host 的 IP,具备哪些 feature,对外提供哪些服务 & 服务元数据等等。

  • 心跳 Client: 共识信息收集执行者。

  • 感知 Feature:是一组 Feature 的统称,也是共识信息的收集者。它们需要外部的感知实现的支持,作为共识信息中系统与上下文环境的收集者。

  • 感知实现:依据特定场景设计的收集执行程序。

  • Feature 变更服务:允许任何 Node 安装,更新或卸载 Feature 的服务。

  • 配置变更服务:Feature 的运行都需要配置支持,允许任何 Node 的任何 Feature 变更配置。

  • NotifyMgr:允许任何 Node 发送特定的 Notify 信息,这些信息也是共识信息组成。比如通知某个上下文环境变化。

  • JobTracker,TaskTracker,JobProxy:是一组用来实现任务动态编排 & 调度的服务。

  • 业务 Feature:是用来实现业务计算或处理的服务。

在宜信的服务治理系统中,我们应用了共识计算系统的架构。

它提供了 8 种能力,如下图左侧所示:

就“基于策略的管控”的能力,这里主要谈谈服务 SLA 智能协商与计算动态编排是如何运用共识信息。

1. 服务 SLA 智能协商

SLA 是从性能,容量,级别三个方面约定服务质量,同时 SLA 通常还会描述服务降级约定。通常的做法就是设置服务能力上限,无法达成就进行服务降级。但是静态的 SLA 是滞后于响应的,服务降级只保证服务方,对调用方没有保证。

如果服务之间能够动态协商实际有效的 SLA,不但能够更大限度保证高可用,还使得调用方甚至整个调用链能够控制风险,有效利用资源。

基本原理是:

1) 从共识信息中获得服务状态(可用)、资源消耗(CPU、内存)、最近服务质量(响应时间、QPS),从而不断反馈到服务发现中,调用方每次获得“最佳”服务节点。

2)如果某系服务节点发现“不良”状况(共识信息不断更新获取),服务节点可以感知调用风险,也可以调整自身的服务质量 SLA,并反馈到共识信息。

3)在 1)中的调用方如果发现调用服务的 SLA 发生改变,也可以反馈到共识信息,从而逐级改变整个调用链的 SLA。

4)人工可以配置相关约束,保证调用链的 SLA 是可控的,收敛的。

5)当某些服务节点的历史区间资源消耗有限时,其闲时资源可以被其他服务节点复用,当然这里需要虚拟化技术的配合。

6)反过来,当某些服务节点资源不够用时,也可以反馈到共识信息,一方面保证 SLA 不再调整,另一方面可以申请新资源以供使用,这里也需要虚拟化技术的配合。

2. 计算动态编排

基本原理是:

1)通过 JobProxy 提交一组任务原语,主要描述一组任务处理,每个任务处理包括数据源、需要什么 Feature、自解析数据 Schema、并行处理策略、定时执行策略、终止策略等。这组任务处理可能是一次执行也可能是周期性执行。

2)具备 JobTracker 的节点能够感知全网 Node 的业务 Feature,根据任务原语,以及相关 Node 状态,资源等共识数据,决定最终的执行序列,并在执行过程中监测执行状态(来自 TaskTracker 的反馈)。所以,每次执行序列可能会指定不同的 Node 来完成,在执行过程中也可能变更执行序列,直到不能产生所需执行序列或触发终止策略的约束。

3)具备 TaskTracker 的节点在收到 Task 原语后,调用对应的业务 Feature 完成 Task 执行,无论成功失败都反馈执行状态到共识信息中。

总结

本文主要是诠释一下“微智能”在软件系统中的思想体现,它指基于“自动化”手段形成“闭环反馈回路”或“自适应处理”的系统或组件。

“微智能”设计具备三个特征:自动发现自我维护自动适应

它相比传统反馈系统而言,形成了系统架构层面的闭环反馈;相比分布式处理系统而言,具备更多演进特点(动态配置,全网状态感知,计算动态编排)。

案例“应用服务画像”描述了如何构造“服务元数据的闭环”;案例“自解析数据交互”描述了如何构造“服务调用的闭环”以及“服务调用的自适应”。

最后通过宜信服务治理系统来解析“共识计算系统”是如何“彻底”地落地“微智能”设计思想的,并着重讲解了服务 SLA 智能协调和计算动态编排的原理。

嘉宾介绍

张真,目前就职宜信技术研发中心,高级架构师。主要负责基础系统架构演进与优化,服务治理,监控平台,微服务建设,DevOps 平台,自动化测试框架以及电子签约,短信,邮件等应用系统。

一直都从事分布式系统的研发,早年就职于 IBM 中国研发中心,负责 IBM WebSphere 应用服务器包括传统 WAS,下一代轻量级 JEE 应用服务器 Liberty 等的设计与开发,及应用服务器对云计算,移动平台的支持,并为银行、电商客户提供技术咨询和服务。

个人也比较喜欢参与开源社区贡献,如 Cloud Foundry、Apache CXF、Apache Wink 等。目前主要关注微服务架构实施,微智能设计思想应用,虚拟化技术应用,共识计算研究,十分欢迎和大家广泛的,深入的交流。

互动问答

问题:Nginx 并发请求上限怎么估算?

其实 NG 并发上限与 NG 的后端系统直接相关,后端系统就是反向代理或负载均衡的节点。如果 NG 只是负责反向代理或负载均衡,需要先评估每个单点后端系统在生产环境配置下的并发性能,NG 的理论上限是能够挂的后端系统节点性能之和;如果在 NG 上做了扩展,则需要测试单点 NG 在生产配置下的实际并发性能。

问题:实现这种微智能体系,宜信都使用了哪些具体的技术或者框架呢?

微智能设计本身与具体的技术或框架无关,宜信技术研发中心大部分的系统是 JAVA 系统,目前服务治理系统是按照微智能设计思想实现,底层实现都是自研,当然像 ZooKeeper、MongoDB、OpenTSDB 等也有在特定领域使用。

问题:我个人理解微智能可以比喻为电子线路中的(锁相环机制,可以根据输出结果自动调整偏移量,反馈到输入端),微服务是业务的垂直切分。但是现在微服务和微智能怎样结合的,是否有落地方案呢?方案成熟度如何?谢谢!

在宜信的服务治理系统中,从分享的架构图可见,其实共识计算的每个节点就是一个微服务,所以它不仅仅是实现业务拆分,也实现了服务画像,服务监控,服务 SLA 动态协商,计算动态编排(实际可以看成是微服务的动态编排,JobProxy 实际等效于微服务的 API 网关)。

问题:共识计算机系统如果发现某个服务有变更就会更新相应的服务画像?但是对于多版本的服务怎么处理呢?

这是个好问题。首先服务画像是落地到一个具体的服务实例上,比如某个 Host 上的 Tomcat 实例上某个 WebApp 的某个服务。所以只有当这个服务实例被更新时才产生新的画像,我们是可以区分每个服务实例的画像。因此就算存在多个版本的服务也能够被识别,在服务发现时,通过共识信息的约束判断来确定调用方是否可以使用这个实例,这样在运行时多个服务版本是可以共存。此外,这些画像也便于我们追溯整个服务的变迁历史,从而发现问题提取经验,为服务重构或新服务上线做指导。

问题:我想问下,针对这个系统,业务数据怎么保证最终一致性?

这个问题比较大,我尝试回答一下。首先共识计算系统与业务处理没有直接关系,共识计算系统中的任务动态编排是基于任务原语,任务原语的逻辑正确性直接决定了最终任务执行结果。而动态任务编排只是为了达成计算执行的任务分配,资源协调。如果要保证数据最终一致性,需要在任务原语中增加数据的一致性约束检查,当然也可能需要额外扩展代码来完成。

问题:微智能的实现看起来更加“智能”了,但是会不会同样引来了一些问题呢?比如实现更加复杂、运维难度更大等?微智能在什么场景使用更加合适?

这也是个好问题。首先微智能就是要解决运维问题,希望系统更加聪明地工作。从架构设计上来看,只要体系微智能设计思想的架构都算是微智能,没有具体限制。共识计算系统是一种微智能设计思想的落地,从每个单点的 Node 来看,其实很“单纯”,只要具备前面提到一组基础 Feature,都可以落地成共识计算的 Node,只是由于系统基于共识信息带来了一分部“执行不确定性”,不过这也正是“智能”的体现。当然,任何事物都是双刃剑,在初创系统阶段,并不建议使用整套的共识计算系统,可以从需求出发看什么地方可以去落地微智能的设计思想;当系统规模扩展,交互复杂起来时,可以考虑逐步引入较彻底的微智能设计。


感谢郭蕾对本文的审校。

给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ@丁晓昀),微信(微信号:InfoQChina)关注我们。