2.2 边缘计算架构设计原则
2.2.1 模型驱动
在边缘计算环境中,硬件与资源受限,导致需要差异化对待来自不同厂商的软硬件产品与服务;另外,极简运维又要求服务应标准化和模板化,尤其是服务快速部署和弹性运维是开展规模化边缘计算服务的前提。这就要求应对典型边缘计算场景、算力、带宽等资源进行标准化和模板化设计,实现快速复制和拓展。因此边缘计算系统应该是个模型驱动的系统。
介绍模型驱动前,需要介绍一下什么是模型。模型是对“事物”的一种抽象化表达,即从特定角度对系统进行描述,省略部分不重要的细节,聚焦感兴趣的特性。
模型驱动在软件开发领域有多种表达方式,比如MBD(Model Based Development,基于模型的开发)、MDD(Model Driven Development,模型驱动开发)、MDA(Model Driven Architecture,模型驱动架构)。模型驱动的核心是从模型中生成代码和其他开发过程中的组件,在解决领域问题的同时,提高生产效率。比如,发生需求变更时,软件设计不变或变更较少(模型不变)。与之对应的传统开发方式则是硬编码(即使用编程语言C、C++、Java、Python等编写代码)。但从本质上来说,只要是进行变更,就肯定需要某人/某个应用在某个地方进行某些修改,这样才能让变更真正生效。模型驱动的修改与硬编码方式的修改真正的差异在于谁负责修改、改什么(包括在哪修改)和影响多大。对于硬编码方式而言,所有变更都需要由原软件提供者来修改,且需要在实际产品代码上重新进行编译、发布、打包等操作,再经过商业交付流程提供给使用者。而使用者在此过程中只能等待,等待供应商提供修改后的版本,然后再经过入网测试、升级部署等流程才能在实际网络中使用。传统修改方式不仅代价大、周期长(一般以月为单位),而且多数情况下,产品升级还可能需要重启系统,影响较大。如果整个过程中发生任何问题,包括理解上的差异,很可能需要从头再来。
而对于模型驱动的架构,在进行变更时,平台开发者(比如边缘计算产品的供应商)不需要参与代码修改,平台本身也不需要停机,不需要进行重新编译、发布等开发过程,使用者通过修改外部(相对平台/边缘计算产品自身代码而言)的模型文件(TOSCA或YANG等)或插件(可能包括JavaScript、Python等动态语言)即可动态变更,这一开发过程可称为模型驱动的设计。当然,为了实现这一点,需要提前定义一些内容:模型的格式(模型文件应该如何描述)、模型生效的流程(模型如何加载、生效,如果中间出现错误如何处理等)。多数模型驱动的架构还会定义一些预定制的元模型或领域模型示例,以简化学习流程,加速在指定领域中的应用。
在本书中,模型驱动是指,系统支持在不修改自身框架代码的前提下,通过对模型进行组合/变更(新增、删除或修改),进而实现业务变更。上述这些一般通过修改某些脚本,或动态加载部分插件、驱动来实现。
注意
模型驱动并不意味着业务变更完全不需要修改代码,只是不需要修改系统自身的框架代码,即修改分成两部分:一部分是对平台的修改,尽可能少甚至不需要修改;另一部分是(在多数场景下)第三方(非系统开发人员)对模型进行组合与修改(也可能包括一些脚本的开发)。
1. 常见模型
常见模型包括信息模型、数据模型、对象实例(物理数据模型)以及元模型等,这些模型分别表示从现实世界到信息世界的不同层次的抽象。
□ 信息模型(Information Model,IM):包括业务模型和概念模型,是对现实世界中真实事物的描述,不涉及具体软件实现,是根据现实世界中具体事物定义出的抽象概念(对象名称),例如员工、合同、客户、网络、站点、设备等,也包括这些抽象概念之间的关系,比如站点中“包含”设备,而交换机“属于”某种设备等。
□ 数据模型(Data Model,DM):是对业务模型或概念模型的进一步分解和细化,包括所有的实体(抽象代表一类对象,员工代表所有具体的员工)和关系(实体间的关系)。需要确定每个实体的属性,定义每个实体的主键,指定实体的外键,需要进行范式处理。一般在软件设计中定义对应的数据/对象结构,比如员工包括工号—字符Char(8)、姓名—最长20个字符的可变字符串varchar(20)、年龄—数字integer、出生日期—日期date等。
□ 对象实例:用于在数据模型基础上定义每个具体的独立对象,比如某个具体员工A的工号是00123456,则员工A就是一个实例。
□ 元模型(Meta Data):即模型的模型,是模型驱动设计中更高层次的抽象。一般针对特定领域的模型定义抽象概念(元模型),并用其构建该领域中的具体数据模型。比如在网络领域,IPV4(形如10.10.10.10的32位的对象)或IPV6(形如:1:123::ABCD:0:1/96的128位的对象)就可视为元模型,用它们的组合可表示新的模型对象,比如VPN(每个接入点都可以是IPV4/IPV6的IP地址)。
目前很多领域都有自己特有的模型和模型语言。下面就一一介绍。
2. 常见模型语言
(1)XML
XML(eXtensible Markup Language,可扩展的标记语言),1998年2月由W3C(World Wide Web Consortium,万维网联盟)正式批准定义的标准且通用的标记语言。“标记”指计算机所能理解的信息符号,通过标记,计算机之间可以处理包含各种信息的文档。在定义这些标记时,既可以选择国际通用的标记语言,比如HTML(Hyper Text Markup Language,超文本标记语言),也可以使用像XML这样由相关人士自由决定的标记语言,这就是语言的可扩展性。XML是由SGML(The Standard Generalized Markup Language,标准通用标记语言)简化修改而来的。XML是一套定义语义标记的规则,这些标记将文档分成很多部件并对这些部件加以标注,即定义了用于定义其他与特定领域中有关的、语义的、结构化的标记语言的句法语言(元标记语言)。
直白解释就是,XML是一种规则,其把一个文档划分为不同的层次或部分,并对这些层次或部分做好标记。这个文档支持不同领域,比如文学、物理、化学、音乐等。不同领域的文档可定义特有的领域语言(也用XML定义)。XML文档的字符分为标记与内容两类。标记通常以<开头,以>结尾;或者以字符&开头,以;结尾。
XML有如下几个特征:
□ 内容与形式分离,XML的设计宗旨是传输数据和存储数据,而不是显示数据。
□ 良好的可扩展性,标签没有被预定义,需要自行定义标签。
□ 具有自我描述性。
□ 遵循严格的语法要求。
□ 便于不同系统之间进行信息传输,是W3C的推荐标准。
一个简单例子如下:
<student> <age>19</age> <name>John</name> <school> Wuhan University</school> </student>
以上XML脚本描述的是一个学生,记录了学生如下信息:年龄、姓名、学校。其中的<student>学生和<age>年龄等即为自定义标签(tag)。具体如图2-1所示。
(2)XML Schema
XML虽然可以描述一个对象(通过自定义标签),如上例所示,但对于计算机处理来说这是不够的,上述示例只能说是“语法正确”(术语称为well-formed XML),但不一定“合法”(术语称之为validating XML)。
比如年龄这个标签,在计算机处理中还需更进一步严格定义,数据类型是一个“数值”,而不是字符串。显然,说年龄是10(岁)是合法的(一个数值),而把年龄说成一个字符串“OK”或“非常大”,则是非法的。
为了约束一个字段或者说为了约束XML的类型,就有了XML Schema,它是一套W3C标准,即用于XML的模式定义语言,定义XML标记规范。
以下是一个对年龄进行约束的例子。年龄这个标签(XML也称为元素,element)有如下定义/约束:
□ value必须是整型(xs:integer);
□ 取值范围必须是7~50。
<xs:element name="age"> <xs:simpleType> <xs:restriction base="xs:integer"> <xs:minInclusive value="7"/> <xs:maxInclusive value="30"/> </xs:restriction> </xs:simpleType> </xs:element>
(3)YAML
YAML(Yet Another Markup Language,另一种标记语言)是一种以数据为中心的标记语言,是一种人性化的数据格式定义语言。数据组织主要依靠的是空白、缩进、分行等结构,相比XML其有如下优点:
□ 可读性好;
□ 和脚本语言的交互性好;
□ 使用实现语言的数据类型;
□ 有一致的信息模型;
□ 易于实现。
比如上面那个学生的例子,用YAML语言可表述为如下形式。
- student: name: John age: 19 school: Wuhan University friends: # YAML用缩进后的横杠‘-’表示列表项的多个取值 - 'mike' - 'Tom'
由于YAML有较好的可扩展性与可读性,且比XML编码效率更高,故在特定场景下具备明显优势。比如常用的动态语言(Python、Ruby等)就支持用YAML定义的数据结构与数据类型。一些常见的IT工具也使用YAML来定义模板,比如Heat、Cloud Formation、Saltstack、Puppet、Chef。
一个环境描述的Heat实例(包括对Nova、Database、Chef的定义)如下:
# Environment environment: environment_1000_stag name: Rackspace Cloud US - staging Providers: Nova: id: nova vendor: rackspace provides: - compute: Linux - compute: windows constraints: - region: ORD Database: id: Database vendor: rackspace provides: - Database: MySQL Chef: id: chef-Server vendor: opscode provides: - Application: http - Database: MySQL
(4)YANG
YANG是IETF在RFC 6020中定义的用于网络配置的数据模型描述语言,可支持NETCONF接口协议,实现网络配置的标准化,是一种DSL(领域特有语言)。
注意
NETCONF(Network Configuration Protocol)是一个网络配置管理协议,是由IETF标准组织定义的一套管理网络设备的机制。用户可使用这套机制增加、修改、删除网络设备的配置,获取网络设备的配置和状态信息。
YANG与XSD(XML Schema Definition)基本等价,也就是说YANG是一种Schema定义语言,而不是像XML或YAML一样用于数据的传输和存储。
从设备维护的角度,YANG将数据的层次结构模型化为一棵树,树中每个节点都有名称且有一个值或一个子节点集。YANG给节点提供了清晰简明的描述,同样提供了节点间的交互。相比XML Sechema,YANG语言定义的数据模型具有可读性好、简单易懂、可扩展的特点。当前YANG已在设备配置领域被普遍采用,IETF、ONF等标准组织都要求提交的模型用YANG来写。其他组织(如Openconfig、OpenDayLight等)也普遍支持YANG。
用YANG定义一个RPC(远程进程调用)的示例代码如下所示。
rpc activate-software-image { input { leaf image-name { type string; } } output { leaf status { type string; } } }
上述示例表示一个activate-software-image的远程调用方法,输入是一个string参数image-name,输出是string类型的status。
(5)TOSCA
TOSCA(Topology and Orchestration Specification for Cloud Applications)是一种数据建模描述语言,一种面向云计算环境中的应用拓扑和编排描述语言,由OASIS组织(https://www.oasis-open.org/)制定,目前支持YAML和XML实现。
TOSCA基本概念有两个—节点(node)和关系(relationship),且都可通过程序来扩展,同时TOSCA规范中也支持Plan(即Workflow工作流文件)。
节点预定义了很多基础类型,包括云基础设施中常用的计算节点、网络节点、数据库节点等。
关系定义了节点之间的关联关系,常见关系类型如下。
□ DependsOn(依赖):表示节点间的顺序依赖关系,一般影响实例化过程中的创建顺序,比如A节点依赖B节点,则在创建A对象前须先创建B。
□ HostedOn(运行):比如“MySQL数据库”与“计算机”的关系就是HostedOn的关系,即数据库运行在计算机上。
□ ConnectsTo(连接):表示连接关系。
TOSCA面向云计算环境中的应用拓扑和编排场景预定义了一些属性,因此一般认为较适合用于满足以下需求:
□ 自动化部署和管理软件。
□ 应用生命周期(安装、扩容、卸载等)管理方案的可移植性(注意:不是应用本身的可移植性)。
□ 组件之间的互操作性和重用性。
注意
OpenStack中的Heat子模块也是基于TOSCA标准的。
YANG、TOSCA都具备较强的扩展能力。笔者认为,语言本身没有本质区别,也不存在谁一定更适合某领域的说法,这更多是不同领域使用习惯的问题。而且IETF、OASIS等组织也都在不断扩展这两种语言。比如,NFV领域的VNFD就是用TOSCA来描述文件的(可以是YAML或XML格式),描述项包括安装软件过程中都有哪些组件、组件之间有什么依赖关系等。当然,实际运行时还需要TOSCA运行态环境来对TOSCA文件进行读取(分析文件的语法、语意)和解释执行(进行具体的软件安装、配置工作)。
下面看一个TOSCA描述文件(称为Service Template)示例。该示例包括一个名为my_Server的节点,类型是TOSCA.nodes.Compute,该类型预置了两个capabilities(能力)信息,一个是host,定义了硬件信息;另一个是os,定义了操作系统信息。
该示例代码如下:
TOSCA_definitions_version: TOSCA_simple_YAML_1_0 description: Template for deploying a single Server with predefined properties. topology_Template: node_Templates: my_Server: type: TOSCA.nodes.Compute capabilities: host: properties: num_cpus: 1 disk_size: 10 GB mem_size: 4096 MB os: properties: architecture: x86_64 type: Linux distribution: rhel version: 6.5
TOSCA脚本还可用于表达对输入、输出的建模。比如,以下代码就定义了一个TOSCA.nodes.DBMS.MySQL新节点类型。该类型允许接收root_password和port的参数。在requirements里定义了MySQL这个节点,该节点需要安装到db_Server节点上,这就是“关系”。
topology_Template: inputs: # 略 node_Templates: MySQL: type: TOSCA.nodes.DBMS.MySQL properties: root_password: { get_input: my_MySQL_rootpw } port: { get_input: my_MySQL_port } requirements: - host: db_Server db_Server: type: TOSCA.nodes.Compute capabilities: # 略