容器技术在工业自动化中的适用性
工业自动化系统的操作系统级虚拟化:我们到达了吗?
摘要
虚拟化正在进入实时嵌入式系统领域。特别是工业自动化系统,可以从虚拟化技术中受益:在不同类型的硬件和规模上灵活整合应用程序、延长遗留代码的使用寿命,或解耦软件和硬件生命周期。然而,此类系统需要轻量级的虚拟化技术,以便在处理实时数据的同时保持实时行为。本文旨在研究基于容器的操作系统级虚拟化技术在工业自动化系统中的适用性。为此,我们深入探讨了容器在实现工业自动化应用程序的灵活整合和轻松迁移方面的能力,以及容器技术在满足工业自动化系统基本要求方面的准备情况,即基于实时数据执行及时控制操作。此外,我们通过微基准测试对容器引入的性能开销进行了实证研究,这些微基准测试捕捉了目标工业自动化应用程序的特征。
CCS概念
- 计算机系统结构 → 实时操作系统;嵌入式系统;
关键词
虚拟化;操作系统级虚拟化;容器;实时应用;工业自动化系统
1. 引言
工业自动化系统(IAS)在实现工厂的控制、监控和监管功能方面起着关键作用,允许出于个人或课堂教学目的制作本作品全部或部分内容的数字版或印刷版副本,但前提是不得以盈利或商业利益为目的制作或分发这些副本,且所有副本必须包含此声明及首页上的完整引用信息。对于本作品中由非美国计算机协会(ACM)拥有版权的组成部分,必须尊重其版权。允许注明出处的摘要使用。如需其他方式复制或重新发布,或将作品上传至服务器或进行列表分发,必须事先获得特定许可和/或支付费用。请向Permissions@acm.org申请许可。
SAC 2016,2016年4月4日至8日,意大利比萨 c©2016美国计算机协会。ISBN 978‐1‐4503‐3739‐7/16/04… $15.00 DOI:http://dx.doi.org/10.1145/2851613.2851737
生产过程或变电站。由于此类系统在功能和规模上的扩展需求日益增加,导致必须安装和管理大量额外的设备。此外,这些设备上运行的应用程序通常与硬件紧密耦合,并且通常依赖于遗留代码。然而,工业自动化系统在业务需求上侧重于降低资本和维护成本、减少工厂占地面积以及利用最新硬件和软件技术。虚拟化技术可以在应对当前挑战的同时,帮助满足这些需求。
虚拟化技术广泛应用于企业或云环境中,旨在集中管理任务、提高可扩展性、提供隔离以及实现不同平台之间的轻松迁移。虚拟化将软件与硬件解耦,有助于在相同物理设备上整合多个系统。其中,硬件虚拟化(例如 [1])是所有虚拟化技术中应用最广泛的。然而,它可能引入显著的性能开销([10]),尤其是在处理需要高时间精度以满足实时截止时间(例如毫秒级)和低延迟(例如数十微秒)的实时数据的应用程序时。这类应用程序在IAS领域中十分典型。
为了从虚拟化中受益,工业自动化系统需要一个轻量级虚拟化框架。操作系统级虚拟化(例如 [11])原则上可以通过将应用功能及其依赖关系封装到称为容器的虚拟环境中来满足这一需求,从而在共享的操作系统内核上实现运行时隔离。容器不仅可以灵活地在不同类型的硬件和规模上整合自动化功能,还可用于延长遗留代码的使用寿命。
操作系统级虚拟化已在许多领域(例如[8],[4])被评估,尤其是与其主要对应技术硬件虚拟化进行对比,但工业自动化系统(IAS)领域除外。本文通过两个方向研究操作系统级虚拟化在IAS领域的适用性。首先,我们分析如何使用Docker——一种典型的基于Linux的容器框架——来灵活整合自动化平台。在此过程中,我们还评估了针对典型的工业自动化系统应用时的技术成熟度。其次,我们通过实验评估容器给具有实时要求的IAS应用程序带来的性能损耗。

2. 相关工作
容器技术的应用在各个领域中正变得越来越普遍。
Boettiger [3] 阐述了使用 Docker 实现可重复和可复用研究的动机。Dua 等人 [5] 应用 Docker 实现平台即服务(Platform‐as‐a‐Service),并与现有的虚拟机进行比较。Bernstein [2] 提出了类似的概念。Zheng 和 Thain [15] 展示了使用 Docker 的工作流应用,表明启动和删除大量容器会导致显著的开销。
学术界和工业界的多项研究致力于进一步提升容器环境的可用性和管理能力。Stubbs 等人 [13]专注于应用 Docker 实现微服务架构,为此提出了服务发布、发现、监控和自愈机制。Gerlach 等人 [7,6] 描述了使用容器编排科学工作流的方法。Shan 等人 [12]研究了基于操作系统级虚拟化的应用程序间通信。Brightwell 等人 [4] 探讨了利用虚拟化构建超大规模高性能计算(HPC)系统的方法。Joy [8]的研究量化了虚拟机与 Docker 容器之间的性能差异,结果证明了操作系统级虚拟化相比虚拟机具有极小的开销。此外,Kang 等人 [9]研究了虚拟化存储,以进一步提高在多核系统上大规模容器的可扩展性。
现有的相关研究均未涉及本研究关注的实时应用程序。
3. 工业自动化系统
工厂、生产过程或变电站的控制、监控和监管功能由工业自动化系统实现。这些系统由多个设备组成,这些设备以分层方式互连。数据采集和执行由安装在接近进程处的现场级设备实现。控制级设备根据从现场级设备获取的信息执行本地控制,并向这些设备发送控制命令。工厂级的监控、监管和控制由监控控制设备完成。
工业自动化系统的基本特征是其功能需要处理实时数据,并对事件的检测与响应具有实时截止时间要求。运行这些功能的设备必须能够处理实时数据,并以确定性方式执行功能。例如,电机驱动控制应用具有典型的周期时间达到1毫秒或更短,例如 250 µ秒。
由这些功能处理的实时数据可以周期性或非周期性传输,并在本地通信网络上提供使用。例如,在变电站自动化系统中,采样值(SV)用于以4千赫兹(50赫兹电力频率)或4.8千赫兹 (60赫兹电力频率)的速率周期性地传输电压和电流采样,而通用面向对象变电站事件(GOOSE)消息则用于在事件发生时快速交换控制和状态信息。因此,对网络流量的低延迟访问对于工业自动化系统中的运行至关重要。
此外,当事件顺序重要时,工业自动化系统的设备可以实现时间同步。事件顺序基于时间戳来确定。同样重要的是处理顺序,通常基于静态 time-driven schedules(例如 [14])进行,以确保满足实时截止时间。因此,timing accuracy 对此类系统的正确运行至关重要。
4. 操作系统级虚拟化
虚拟化技术是一种众所周知的技术,可用于在同一平台 consolidate 不同的应用程序,并允许共享使用底层资源。硬件虚拟化就是一种已在许多领域实际应用的虚拟化技术。在这种技术中,管理程序可在给定的主机操作系统上(类型2管理程序)或无需主机操作系统的情况下(类型1管理程序),实现客户操作系统(OS)在所谓的虚拟机 内的运行。而操作系统级虚拟化则使用容器 来隔离用户空间,同时共享主机操作系统内核。
图1展示了两种虚拟化类型之间的主要区别。硬件虚拟化在应用程序与硬件之间引入了更多的层次,主要是为了允许在相同硬件上运行不同的客户操作系统。相比之下,容器需要共享一个操作系统(例如Linux)。然而,在操作系统级虚拟化环境 中运行的应用程序并不局限于特定的容器。事实上,容器代表具有本地API、库和设置的虚拟环境,但应用程序仍可使用主机操作系统提供的常规系统调用。这使得整个系统更加轻量。
容器可以从模板构建,这些模板可以在同一台或不同的物理机器上的不同容器之间共享、扩展和重用(只要内核兼容性得到保障)。由于容器没有独立的操作系统,其启动和关闭时间非常短,这使得容器适用于轻量级和动态环境。因此,我们可以将完整应用容器化,或将它们分布到不同的容器中。
5. 机遇与挑战
操作系统级虚拟化框架(如Docker)通过三种主要功能实现在同一平台上应用程序的灵活整合:(1)容器模板或镜像以及一整套管理工具,(2)隔离与运行时管理,(3)虚拟网络。第一种功能在很大程度上依赖于操作系统级虚拟化框架本身,而第三种功能则是Linux内核提供的、并由操作系统级虚拟化框架所利用的特性。本节我们的重点是第二种能力,因为它直接影响实时应用在虚拟化环境下的行为表现。而第三种功能即虚拟网络也是我们研究的重点之一,将在第6节.2中进一步探讨。
容器可以将应用程序环境与其他应用程序以及主机隔离开来。在Linux上,容器通过 namespaces(内核级概念)实现这一点。容器在库依赖关系和环境设置方面隔离应用程序环境的同时,也隔离了容器化应用程序使用系统资源的方式。这得益于 control groups或 cgroups(另一组内核级概念),因此容器也可以实现性能隔离。
我们通过探讨以下两点来质疑容器在实现性能隔离以及普遍意义上的隔离方面的有效性:(i) 容器内容 (the content of a container) 和 (ii) 容器对系统资源的使用 (the usage of system resources by containers)。为此,我们考虑容器内虚拟环境可能意味着的两种潜在视角或解释:面向子系统的视图 (the sub-system oriented view) 和面向设备的视图 (the device-oriented view)。
5.1 面向子系统的整合
工业自动化系统的一个 sub-system在逻辑上可以由一组应用程序或一组设备组成。图2展示了在同一单个设备上整合相同子系统的两种可能方式。左侧显示了容器封装 virtual applications的情况,而右侧则显示了封装 virtual devices的容器。我们假设这两个应用程序都在进行某种局部计算(使用 LFx函数),在做出全局决策(使用GFx函数)之前靠近实际过程执行。

对于虚拟应用和虚拟设备,容器可以在隔离的环境中运行多个进程(包括库、二进制文件和环境设置)。此类环境类似于虚拟机环境。
然而,这种观点存在一个重要陷阱。假设每个进程都需要一个CPU核心亲和性,并且每个进程自行设置其亲和性。此外,假设容器内的功能通过某种实时中间件执行,并依赖于静态的时间驱动调度,例如FASA内核[14]的情况。
陷阱源于不同容器中的进程由于对系统的独立视图,可能会以相同的方式使用相同的资源。这会导致资源利用率低下以及可能违反实时执行假设。
另一个陷阱是关于平台间的可移植性。一个容器在某些平台上可能被分配到CPU核心0和1,而在另一平台上则可能被分配到核心3和4。当主机上的配置发生变化时(例如在迁移过程中),容器内部运行时需求的不明确可能导致容器化应用进程出现未定义的行为。
这些陷阱的出现是因为容器并未对系统资源(如CPU或内存)进行虚拟化。事实上,即使通过cpuset控制组限制容器仅在部分CPU核心上运行,容器中看到的/proc/cpuinfo内容与主机相同。也就是说,容器内部并不存在虚拟CPU核心的概念。
5.2 面向设备的整合
此视角关注的是 single device的整合,无论该设备是运行完整应用还是部分应用。在此视角下,容器将单个应用程序或系统模块封装为单个进程。此类模块可被视为 micro-services,能够为多个应用程序提供服务。事实上,这种视角对应于 Docker对应用程序进行容器化的方式,尽管在功能上并不限制定义前一节所述类型的虚拟环境。

图3展示了一个面向微服务的平台示例,其中一组本地功能 (LF)和一个全局功能(GF)在各自的容器中运行,并使用相同的通信栈(CS)(在另一个容器中执行)。该通信栈 (CS)允许这些功能通过特定的自动化系统协议与设备所处的网络进行通信。
封装单个进程的容器在运行时管理以及可移植性方面具有优势。然而,并不总是能够将应用程序或其模块限制为单个进程。即使可以做到这一点,容器之间的通信机制仍不明确。Docker 假定模块之间通过网络连接。但是,在对实时应用进行模块化时,通常的做法是在主机上通过内存速度的进程间通信(IPC)来集成模块([14])。
容器默认为容器化进程提供独立的(IPC)命名空间。Docker容器还可以让容器共享主机或其他容器的IPC命名空间。虽然这在一定程度上违背了隔离性,但该功能可以支持将实时应用程序模块容器化,同时保留其IPC接口。然而,这其中也存在一些陷阱。
考虑图3中通过IPC进行通信的CS和GF容器。假设这两个容器共享主机的IPC命名空间,并且在启动时,容器内的进程使用 System V IPC进行IPC通道设置,这意味着shmget例程首先需要使用一个键来访问共享内存段。这可以通过两种方式实现,但都可能遇到陷阱:
- 密钥被两个进程所共知。这种情况必须谨慎处理,因为缺乏进程间通信命名空间隔离可能导致密钥冲突。
- 进程使用基于 ftok 例程的键解析,该例程将文件系统路径 (例如 /dev/null)映射为一个键。即使两个容器使用相同的路径,这种方法也是有缺陷的,因为该例程在不同容器内会返回两个不同的键,因为它们具有不同的(虚拟)文件系统。
解决这些问题的一种方法是提供第三个容器来管理一个与主机隔离但在各容器之间共享的IPC命名空间。该容器还可以管理分发给各个容器的密钥。
6. 开销评估
我们通过实验评估了容器对IAS应用程序性能的影响,特别是考虑了第3节中介绍的主要特性。
实验设置包括一台配备 Intel Xeon E5‐2660 v2 2.20GHz 处理器 (10 核超线程)、64GB内存 和 Intel I350 千兆网络控制器四端口的 HP Z820 工作站。Linux 系统使用的是 Ubuntu 14.04 LTS、64位,并打上了实时内核补丁 3.14.12‐rt9。所有容器实验均使用 Docker 1.5.0 并基于最新的 Ubuntu镜像 运行。由于实时应用通常需要对操作系统功能和资源进行特权访问,例如设置 实时优先级或配置 CPU 亲和性,因此实验中使用的所有容器均以 ‐‐privileged=true 参数运行。
我们在评估中保持与应用逻辑无关,对于每种类型的需求,即 timing accuracy和 virtualnetworking performance,我们使用了特殊的微基准测试,这些测试将在接下来的两节中结合我们的评估结果进行说明。

6.1 实时性能
实时应用的性能主要集中在它们的周期性行为上,即能够在预定义的时间间隔(通常为毫秒级)以确定性时延执行应用逻辑的能力。
为了评估容器对时间精度(或抖动)的影响,我们使用了 cyclictest微基准测试,该测试旨在捕捉实时环境(在本例中为应用了实时补丁的Linux)在时间精度方面的性能。cyclictest背后的基本思想由以下伪代码体现,该代码基于周期性睡眠循环来维护抖动统计:
while(true) {
wakeup_time = now() + 10e6;
sleep_until(wakeup_time);
jitter = now() - wakeup_time;
/* keep statistics of the jitter */
}
我们在主机上直接运行了 cyclictest,周期为1毫秒,该设置记为 ct-host,同时也在Docker容器内运行,记为 ct-docker。每次实验包括运行多个 cyclictest进程,参数为:‐q ‐nN ‐l120000 ‐aX ‐pYY,其中X表示运行的核心,YY表示不同的实时优先级,即:10、40、60、80和99(RT)。此外,我们还尝试了两种不同类型的环境:
- Idle environment :这用于观察容器的直接且不受干扰的影响。
- Non-idle environment :此设置模拟了一个更真实的环境,其中存在其他可能影响时间精度的应用程序。就我们的目的而言,我们使用 trafgen 工具生成接近一个网络端口1 Gbps链路速度的网络流量。
两种环境的结果如图4所示,为抖动的箱线图。结果显示了每种实时优先级设置以及每种环境类型的结果:空闲环境下的ct‐host(idle)和 ct‐docker(idle),其余为非空闲环境下的结果。
在空闲环境中,ct‐host 和 ct‐docker 表现出基本相同的行为。两者的亲和性均设置为核心0。中位数位于 2‐3 µs,最低和最高四分位数也基本相同。尤其是优先级10和40存在异常值,但实时操作系统功能无论是在主机上直接使用,还是在容器内使用,其效率和效果都相似。
非空闲环境用于观察容器如何隔离运行时从而影响性能。首先,当亲和性设置为核心0(即网络流量生成器也在其上运行的核心)时,ct‐host 和 ct‐docker 再次表现出相似的行为(参见 图4中的 ct‐docker 和 ct‐host (#0)|net(#0))。在这两种情况下,具有实时优先级10和40的进程受到了影响,因为来自用于流量生成的网络端口的硬件中断在启用了实时补丁的 Linux 系统中被关联到更高的实时优先级50。这些中断之前也被固定到核心0。然而,通过将容器移动到另一个核心,这种干扰便简单地消除了(参见 ct‐docker (#1)|net(#0)),而无需为 cyclictest 显式重新设置不同的亲和性。该配置实现了与相应空闲环境类似的抖动水平。
6.2 网络性能
当多个应用程序或应用功能(这些程序或功能原本需要通过网络接收或发送数据)被整合到同一平台时,容器提供了虚拟网络以替代物理网络。因此,了解虚拟网络构造给应用程序带来的开销非常重要。
我们专注于二层网络,这类网络通常被自动化系统所采用,这些系统与其控制的流程非常接近。此类网络上的通信通常由特定领域的标准或协议规定,联网设备具有按照协议处理通信的通信栈。
对于我们的评估,通信协议的类型无关紧要。我们使用了一种能够接收通过以太网发送的数据流的通信栈。最重要的是操作系统内核在将数据从网络驱动程序传递到用户应用程序(即通信栈)时对系统造成的负载。
数据流由一个模拟器生成,该模拟器能够以可配置的速率产生可配置数量的组播数据流。我们报告的结果基于一种场景:10个同步的数据流,每个以每秒5000帧的速率发送,每帧大小为150字节。我们的测试平台包括第6节开头所述的服务器,该服务器运行堆栈的不同变体(直接在主机上或在容器内),以及另一台机器上的流模拟器,两者均连接到一台千兆交换机。

我们用作微基准测试的通信栈通过环形缓冲区和零拷贝机制从一个网络接口捕获网络数据包。网络数据包在接收时由网卡进行硬件时间戳标记,使我们能够计算通信栈侧将数据包传递到该接口的延迟。此延迟记为 NIC handling latency,是我们测量以了解虚拟网络影响的指标。
容器可以通过多种选项进行网络连接。默认选项已在新容器中提供。基本上,Docker在安装时会定义一个名为 docker0的Linux NAT桥接。对于每个新容器,都会创建一个veth对,其中一端位于容器的网络命名空间内(即其eth0 接口),另一端添加到docker0中。我们将此选项标记为 veth。
另一种选项是直接将某个网络接口传递给容器。该选项标记为 phys,允许容器直接且独占使用一个网络端口。
我们使用了以下配置来评估虚拟网络对通信栈(CS)中延迟的影响。单栈配置包括:
- host :CS 直接在主机上运行,并将亲和性设置为核心0。数据流通过主机上的 eth0 接收。
- phys :与 host相同,但CS在名为 cs0的容器内运行,数据通过 eth1接收,并传递给cs0以供独占使用。
- veth :与 phys相同,但 cs0内的CS使用默认容器 eth0。数据流通过 eth0在主机上接收, eth0被添加到 docker0,使得数据被传输到所有连接到它的容器。
我们还在单独的容器中运行了多个栈的配置 cs i,并使用 i ∈ 1..8 将它们全部连接到 docker0。所有配置的结果均在图5中用箱线图表示。1x到8x标签代表在给定实验中同时运行栈的容器数量。
host和 phys之间的差异本应显现容器带来的开销。然而,正如我们在上一节中所看到的,这种开销基本上可以忽略不计。尽管如此,我们仍可以观察到使用虚拟网络时 veth和 phys之间存在明显差异。 phys的中位数保持在 7 µs左右,而 veth的中位数则高出三倍。两者的波动情况相似,这意味着veth引入的开销是一个恒定因子。
由于虚拟网络带来的开销随着容器数量的增加呈线性增长,且在从4个容器增加到5个容器时出现明显跳跃。图5还显示了使用htop工具观察到的CPU负载:(i)当栈运行时由中断请求处理对 eth0施加的负载,(ii)每个栈平均施加的负载,以及(iii)当没有栈运行、仅有空闲容器时由中断请求处理对 eth0施加的负载。开销的增加(包括跳跃现象)与栈的CPU负载增加相关。由于每个栈(在每个容器中)的数据被复制到不同的环形缓冲区,我们将该跳跃归因于缓存效应。然而,docker0网桥本身也会产生负载,该负载随着网络流量被分发到越来越多的连接接口而呈线性增加。
7. 结论
在本文中,我们研究了基于Linux容器的操作系统级虚拟化在工业自动化系统中的适用性。我们重点关注了此类系统在实时行为和实时数据方面的主要需求。
我们的主要结论是,容器技术能够满足这些要求,并且可以为构建和维护工业自动化系统提供一种新方法。为此,容器提供了以下优势:(i) modularity 在系统打包和隔离部署方面的方式,(ii) flexibility 以适应从虚拟测试到实际生产环境等各种类型的环境,(iii) portability 借助“一次构建,随处运行”的原则,这对于延长遗留代码的生命周期以及应对硬件过时问题尤为重要,以及(iv) near-native performance:容器本身对实时应用几乎没有带来任何性能开销,但在多个容器需要访问共享资源时需格外注意。
确实,容器技术为工业自动化系统带来了巨大的前景。然而,该技术在当前阶段尚未解决某些问题。正如我们在第5节中所展示的,在将容器用于实时应用时会出现多个陷阱。显然,需要一个框架来暴露运行在容器内部的实时应用的运行时需求,并强制实施容器到资源的优化分配(从容器外部进行)。这一挑战可以通过在最初实现实时应用的方式上加以缓解,即通过 decoupling the application logic(i.e., what is executed) from the deployment logic(i.e., how it is executed)。
此外,为了充分利用容器,将实时应用模块化为微服务级别是未来的发展方向。然而,我们需要一个 middleware来集成这些微服务,该集成方案必须同时考虑通信需求以及运行时和性能隔离需求。
更多推荐
所有评论(0)