CORBA 与 DSA:分道扬镳还是携手共进?
在分布式系统编程领域,有两种重要的技术值得深入探讨,它们分别是 CORBA(Common Object Request Broker Architecture)和 DSA(Distributed Systems Annex)。下面将详细介绍这两种技术,并对它们进行比较。
分布式语言的运用
传统上,人们可能会定义像 IDL(Interface Definition Language)这样的新语言来实现分布式系统。但另一种思路是对现有编程语言进行扩展,使其具备分布式特性。分布式对象范式为分布式系统编程提供了更面向对象的方法。分布式对象是抽象数据类型的扩展,它允许在类型接口中提供的服务被调用,而无需考虑实际服务的执行位置。当与继承和多态等面向对象特性结合时,分布式对象为分布式应用程序营造了更具动态性和结构化的计算环境。
例如,Ada 95 包含了分布式系统附件(DSA),它定义了多个扩展,允许用户完全用 Ada 编写分布式系统。用户可以使用包来定义分布式对象上的远程过程调用或远程方法调用。Ada 95、Java/RMI 和 Modula - 3 的分布式系统模型非常相似,它们都用语言的子集替代了 IDL。这种语言能透明地支持远程过程调用和远程对象方法调用。
使用这种语言编写的程序通常与使用相同语言编写的程序进行通信。不过,这种限制也带来了一些好处,因为语言不受所有宿主语言可用的最小公共特性子集的约束,所以能提供更强大的功能。在 Ada 95 中,用户定义远程服务的规范并实现它们,就像实现普通的非分布式服务一样。Ada 95 环境会对其进行编译,生成存根文件和骨架文件,这些文件会自动包含对实际服务体的调用。由于语言环境能完全控制开发过程,创建对象、获取或注册对象引用以及使对象骨架适应用户对象实现等操作都是透明的。
DSA 与 CORBA 的比较
DSA 概述
Ada 分布式系统附件为分布式系统编程提供了解决方案。Ada 应用程序可以被分区,以便在计算机网络上执行,这样类型化对象可以通过远程子程序调用进行引用。在被归类为远程调用接口(RCI)或远程类型(RT)的库单元中声明的远程调用子程序可以是静态绑定或动态绑定的,这使得应用程序可以使用以下经典范式之一:
-
远程子程序
:对于程序员来说,远程子程序调用类似于常规子程序调用。使用子程序访问类型的运行时绑定也可用于远程子程序。
-
分布式对象
:可以定义特定的访问类型来指定远程对象。当对由远程访问指定的对象调用原始调度操作时,会在创建该对象的分区上透明地执行远程调用。
-
共享对象
:数据可以在活动分区之间共享,提供类似于共享内存、共享文件系统或数据库的存储库。无入口受保护对象允许对共享对象进行安全访问和更新。此功能与分布式对象的概念相互独立,分布式对象只能通过导出的服务进行访问。
一个 Ada 95 分布式应用程序是一组在一台或多台机器上并发执行的分区;每个分区由一个或多个编译单元组成,这些编译单元共同构成一个可执行二进制文件。
下面是 DSA 架构的 mermaid 流程图:
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(Processing Node 1):::process -->|Network| B(Processing Node 2):::process
A -->|Data| C(Storage Node):::process
B -->|Data| C
A1(Unit_2):::process --> A
A2(Unit_3):::process --> A
B1(Unit_2):::process --> B
B2(Unit_3):::process --> B
C1(Unit_1):::process --> C
C2(Data_1):::process --> C
C3(Data_3):::process --> C
CORBA 概述
CORBA 是一项由行业支持的工作,旨在通过 CORBA 接口定义语言(IDL)对分布式对象范式进行标准化。IDL 的使用使 CORBA 比其他任何客户端/服务器中间件更具自描述性。CORBA 的主要特性包括接口定义语言、语言映射、存根、骨架和对象适配器、ORB(Object Request Broker)、接口存储库、动态调用、ORB 协议和 CORBA 服务。
IDL 用于指定模块、常量、类型和接口。对象接口定义了客户端可以调用或访问的操作、异常和公共属性。CORBA 仅基于分布式对象提供模型。在某些方面,它可以与 Java 相比较,因为 Java 只提供面向对象的编程模型,而忽略了经典的结构化编程模型。
IDL 翻译器会在宿主语言(如 C++、C、Java、Ada 95)中生成客户端存根和服务器骨架。语言映射规定了如何在宿主语言中实现 IDL 实体。根据宿主语言可用的特性,映射的难易程度会有所不同。当 IDL 特性在宿主语言中未定义时,映射会提供一种标准化但复杂的方式来模拟缺失的特性。
下面是 CORBA 架构的 mermaid 流程图:
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(Client - language A):::process -->|IDL specification| B(IDL Stubs):::process
B -->|Requests| C(ORB):::process
C -->|Requests| D(IDL Skeleton):::process
D -->|Requests| E(Object Implementation - language B):::process
F(Dynamic Invocation):::process --> C
G(CORBA Bus):::process --> C
接口定义语言
-
DSA 中的 IDL
:在 DSA 中,IDL 是 Ada 95 的子集。用户在编译时识别接口包。一些库级包通过编译指示进行分类:
- 远程调用接口(RCI) :使用此编译指示分类的库单元可以声明要远程调用和执行的子程序。这种 RPC 操作是静态绑定的操作。在这些单元中,客户端和服务器不共享内存空间。动态绑定调用与 Ada 解引用子程序(远程子程序访问 - RAS)和对类宽操作数进行调度(类宽类型的远程访问 - RACW)的能力集成。这些远程访问类型可以在 RCI 包中声明。
- 远程类型(RT) :与 RCI 单元不同,使用此编译指示分类的库单元可以定义分布式对象及其远程方法。它们还可以定义上述远程访问类型。在 RT 单元中定义的子程序不是远程子程序。与 RCI 单元不同,RT 单元不必只放在一个分区上,它们的行为类似于常规单元。
- 共享被动(SP) :在此类库单元中声明的实体将被映射到共享地址空间(文件、内存或数据库)。当两个分区使用这样的库单元时,它们可以通过读写公共变量进行通信,这对应于共享变量范式。在这些单元中声明的无入口受保护对象提供对共享数据的原子访问,类似于事务处理。
在 RT 或 RCI 单元中,禁止使用变量,并且仅在提供其编组子程序的情况下才允许使用非远程访问类型。在远程方法或子程序调用中引发的任何异常都会传播给调用者。在 RCI 单元中,额外的编译指示
All Calls Remote
可以强制远程过程调用通过通信子系统路由,即使是本地调用也是如此,这有助于在接近分布式情况的非分布式环境中调试应用程序。编译指示
Asynchronous
允许静态和动态绑定的远程调用异步执行。异步过程不会等待远程调用完成,而是让调用者继续其执行路径。该过程必须仅具有输入或访问参数,并且在远程过程执行期间引发的任何异常都会丢失。
所有这些分类单元都可以是通用的。这些通用包的实例可以分类,也可以不分类。如果不分类,单元将失去其分类属性。每个分类编译指示都有非常具体的依赖规则,一般规则是
RCI ≻ RT ≻ SP ≻ Pure
,这意味着远程类型包声明只能依赖于其他远程类型、共享被动和纯单元。
以下是一个完整的 DSA 示例代码:
-- (b) Generic remote unit
with Storage; use Storage;
generic
package Factory is
pragma Remote_Call_Interface;
procedure Notify (Q : Integer);
pragma Asynchronous (Notify);
end Factory;
-- (c) First generation worker
with Types, Storage; use Types, Storage;
package One_Worker is
pragma Remote_Types;
type G1_Worker is
new Worker with private;
procedure Assign
(W : access G1_Worker;
Q : Integer;
N : Notify);
private
-- Declaration not shown
end One_Worker;
-- (d) Shared memory data
package Storage is
pragma Shared_Passive;
protected Queue is
procedure Save (Q, R : Integer);
procedure Load
(Q : in Integer;
R : out Integer);
private
-- Declaration not shown
end Queue;
end Storage;
-- (e) Second generation worker
with Types, Storage; use Types, Storage;
with One_Worker; use One_Worker;
package Another_Worker is
pragma Remote_Types;
type G2_Worker is
new G1_Worker with private;
procedure Assign
(W : access G2_Worker;
Q : Integer;
N : Notify);
private
-- Declaration not shown
end Another_Worker;
-- (f) Several DSA features
with Storage; use Storage;
package Types is
pragma Remote_Types;
type Notify is
access procedure (Q : Integer);
pragma Asynchronous (Notify);
type Worker is
abstract tagged limited private;
procedure Assign
(W : access Worker;
Q : in Integer;
N : in Notify) is abstract;
type Any_Worker is
access all Worker'Class;
pragma Asynchronous (Any_Worker);
private
-- Declaration not shown
end Types;
-- (g) Static and unique workers pool
with Types; use Types;
package Workers is
pragma Remote_Call_Interface;
procedure Free (W : in Any_Worker);
procedure Hire (W : out Any_Worker);
end Workers;
-- (h) Remote unit instantiation
with Factory;
package One_Factory is new Factory;
pragma Remote_Call_Interface (One_Factory);
- CORBA 中的 IDL :在 CORBA 中,IDL 是一种描述性语言,它支持 C++ 语法来声明常量、类型和操作。从 IDL 描述中,翻译器可以生成客户端头文件和服务器实现骨架。
IDL 文件首先定义一个模块,它提供一个命名空间来收集一组接口,这是引入层次结构的一种方式,其指定形式类似于
<module>::<interface>::<operation>
。Ada 95 绑定将此元素映射到一个(子)包。
#include
语句使任何其他命名空间可见。
模块可以定义接口。接口定义了客户端可以在对象上调用的一组方法,还可以定义异常和属性。异常类似于 C++ 异常,可以附加一个数据组件;属性是一个组件字段。对于每个属性,实现会自动创建
Get Attribute
和
Set Attribute
子程序,对于只读属性仅提供
Get
。接口可以从一个或多个接口派生(多重继承)。
Ada 95 绑定将此元素映射到一个包或子包。对于客户端存根,实现会自动在与接口名称匹配的包中创建一个名为
Ref
的标记类型(它派生自
CORBA.Object.Ref
或在另一个接口中定义的另一个
Ref
类型)。对于服务器骨架,实现会自动在名为
Impl
的包中创建一个名为
Object
的标记类型(它派生自实现定义的私有标记类型
Object
),
Impl
是一个以接口名称命名的包的子包。
方法由唯一名称(不允许重载)及其签名(其形式参数的类型)定义。每个参数可以是
in
、
out
或
inout
模式,其含义与 Ada 中的同名模式类似。方法可能引发的每个异常也必须作为方法签名的一部分进行声明。
oneway
属性可以应用于子程序,使其具有最多一次语义,而不是默认的恰好一次语义。这使得方法不能有输出参数、返回值或引发异常。假设调用者在发送输入参数后恢复执行是不可移植的。
大多数 CORBA 数据类型可以直接映射到预定义的 Ada 类型,但
any
和
sequence
除外。
any
可以指定任何 CORBA 类型,它被映射到具有读写操作的流类型。
sequence
包含给定类型的项目列表,在 Ada 中使用一对冗长的通用包表示。需要注意的是,CORBA 字符串类型被映射到 Ada 95 的无界字符串类型。IDL 不提供无约束数组的等效物。
Ada 95 映射提供了特殊机制来实现两个难以映射的 CORBA 特性。首先,它提供了多重继承的翻译。如前所述,Ada 95 包定义了一个从第一个接口派生的类型,并扩展其原始操作列表以实现从其他接口的继承(此解决方案与混入类似)。另一个对 Ada 程序员来说不自然的 CORBA 特性来自前向声明。在 Ada 中,两个包规范不能相互
with
,但在两个 IDL 接口之间可能会出现这种情况。为了解决这个问题,映射建议创建 “前向” 包,这可能会导致一种非常不直观的情况,即客户端存根不
with
其通常的接口包,而是
with
“前向” 包。
当使用 CORBA 开发分布式应用程序时,可能会出现两种情况。在服务器端,程序员负责 IDL 文件。他必须理解 Ada 95 语言映射,以便尽可能避免具有非平凡实现的结构,如前向声明和多重继承。在服务器和客户端,程序员都必须处理生成的代码。良好理解映射有助于在 IDL 文件和生成的代码之间来回切换,以便全面了解分布式应用程序。根据宿主语言的不同,理解这种映射可能是一项繁琐的任务。
IDL 接口信息可以在线存储在一个名为接口存储库(IR)的数据库中。CORBA 规范描述了接口存储库的组织方式以及如何从中检索信息。接口存储库允许客户端发现它在编译时不知道的方法的签名,然后可以使用该知识和方法参数的值来构造完整的请求并调用该方法。允许在运行时构造方法调用请求的一组函数是动态调用接口(DII)。
IR API 允许客户端探索存储库类以获得模块定义树。从这棵树中,客户端提取定义常量、类型、异常和接口的子树。从接口子树中,客户端可以选择一个操作及其参数列表(类型、名称和模式)和异常。
客户端有三种发出请求的方式。与静态情况一样,他可以发送请求并等待结果;也可以进行单向调用并丢弃结果。对于动态请求,还提供了第三种机制:客户端可以发送请求而不等待结果,稍后异步获取结果。
DII 在服务器端有一个对应的部分,称为动态骨架接口。这两种机制都很强大,但使用起来非常复杂和繁琐。在某些方面,它们也违反了 Ada 95 的哲学,因为没有保留强类型。大多数用户将继续使用静态调用。
通信子系统
通信子系统是分布式系统的关键要点之一,它提供基本服务,如将消息从分布式程序的一部分传输到另一部分的能力。这些基本服务随后被更高级别的服务用于构建功能齐全的分布式系统。
有时很难界定通信子系统和外部服务的界限。此外,在 CORBA 中被视为服务的东西在 DSA 中可能被视为纯粹的内部服务。
在 DSA 中,编译器在分布式方面未完成的所有工作都属于分区通信子系统(PCS)。例如,确定将被远程调用的包所在的分区是 PCS 的责任。
PCS 的入口点在 DSA 中定义明确,并在
System.RPC
包声明中进行了描述。通过查看这个包,可以注意到没有与远程子程序调用中止相关的内容,尽管附件规定如果这样的调用被中止,必须向远程分区发送中止消息以取消远程处理。这意味着 PCS 负责检测对其入口点之一的调用已被中止,并必须在没有编译器帮助的情况下发送这样的中止消息。
PCS 的另一个有趣特性是它对未知异常的处理方式。当远程子程序调用执行引发异常时,异常会传播回调用者。然而,调用者可能对异常声明没有任何可见性,但仍可以使用
when others
子句捕获它。但如果调用者不捕获它并让它向上传播(可能在另一个分区中),情况就会变得复杂。
综上所述,DSA 和 CORBA 在分布式系统编程中各有特点。DSA 基于 Ada 95 语言扩展,提供了与语言紧密结合的分布式编程能力,而 CORBA 通过 IDL 实现了跨语言的分布式对象通信。在选择使用哪种技术时,需要根据具体的应用场景、编程语言偏好以及系统的复杂度等因素进行综合考虑。
CORBA 与 DSA:分道扬镳还是携手共进?(续)
技术点分析与对比
语言层面对比
| 对比项 | DSA | CORBA |
|---|---|---|
| IDL 性质 | Ada 95 的子集 | 独立的描述性语言 |
| 绑定方式 | 静态绑定或动态绑定,通过 Ada 自身能力集成 | 依赖语言映射将 IDL 实体映射到宿主语言 |
| 多重继承处理 | 无特殊处理 | Ada 95 映射提供特殊机制实现 |
| 前向声明处理 | 无此问题 | Ada 95 映射通过创建“前向”包解决 |
从语言层面来看,DSA 与 Ada 95 紧密结合,利用语言自身特性实现分布式编程,而 CORBA 的 IDL 更具通用性,但在映射到宿主语言时可能会遇到一些复杂问题。
接口定义对比
- DSA 接口 :通过编译指示对不同类型的接口进行分类,如 RCI、RT 和 SP,每种类型有不同的功能和使用规则。接口定义与 Ada 95 的语法和特性紧密相关,便于 Ada 程序员理解和使用。
- CORBA 接口 :使用模块和接口的层次结构,接口可以定义方法、异常和属性,支持多重继承。Ada 95 绑定会自动生成特定的标记类型,增加了代码的复杂性,但也提供了更灵活的对象引用和操作方式。
以下是 DSA 和 CORBA 接口定义的 mermaid 对比流程图:
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
subgraph DSA
A(RCI):::process -->|静态绑定| B(远程子程序):::process
C(RT):::process -->|定义| D(分布式对象):::process
E(SP):::process -->|共享| F(共享对象):::process
end
subgraph CORBA
G(Module):::process -->|包含| H(Interface):::process
H -->|定义| I(Methods):::process
H -->|定义| J(Exceptions):::process
H -->|定义| K(Attributes):::process
end
通信子系统对比
- DSA 通信子系统(PCS) :负责编译器未处理的分布式相关工作,如确定远程调用包的分区位置。入口点明确,但对远程调用中止和未知异常的处理需要自身额外处理。
- CORBA 通信子系统 :通过 ORB 实现消息传输,IDL 翻译生成的存根和骨架文件与 ORB 交互。提供动态调用接口(DII)和动态骨架接口,增加了通信的灵活性,但使用复杂。
实际应用场景分析
DSA 适用场景
- 基于 Ada 95 开发的系统 :如果项目已经使用 Ada 95 进行开发,DSA 可以无缝集成到现有代码中,利用 Ada 95 的强类型和结构化编程优势,实现分布式功能。
- 对系统安全性和可靠性要求高的场景 :DSA 的强类型检查和异常处理机制可以保证系统的稳定性,无入口受保护对象对共享对象的安全访问和更新功能,适用于航空航天、国防等对安全性要求极高的领域。
CORBA 适用场景
- 跨语言开发的分布式系统 :CORBA 的 IDL 可以支持多种宿主语言,如 C++、Java、Ada 95 等,适合不同团队使用不同语言开发的大型分布式项目。
- 需要动态发现和调用服务的场景 :接口存储库和动态调用接口(DII)允许客户端在运行时发现和调用未知的服务,适用于服务频繁变化或需要灵活扩展的系统。
操作步骤总结
使用 DSA 开发分布式系统的步骤
-
定义接口包
:根据需求使用编译指示将库单元分类为 RCI、RT 或 SP。
-
示例代码中,
Factory包使用pragma Remote_Call_Interface分类为 RCI 包。
-
示例代码中,
-
实现子程序和对象
:在相应的包中实现远程子程序、分布式对象或共享对象。
-
如
One_Worker包定义了G1_Worker类型和Assign子程序。
-
如
- 编译和部署 :使用 Ada 95 编译器编译代码,生成存根文件和骨架文件,将分区部署到不同的机器上。
使用 CORBA 开发分布式系统的步骤
-
编写 IDL 文件
:定义模块、接口、方法、异常和属性。
-
例如,定义一个包含
HelloWorld接口的 IDL 文件。
-
例如,定义一个包含
-
生成代码
:使用 IDL 翻译器根据语言映射生成客户端存根和服务器骨架文件。
- 如使用 Ada 95 绑定生成相应的 Ada 代码。
-
实现服务
:在服务器端实现接口定义的方法,在客户端调用这些方法。
-
服务器端实现
HelloWorld接口的具体方法,客户端调用该方法获取服务。
-
服务器端实现
- 配置和部署 :配置 ORB 和相关环境,将服务器和客户端程序部署到不同的机器上。
总结与展望
DSA 和 CORBA 作为两种不同的分布式系统编程技术,各有其优势和适用场景。DSA 与 Ada 95 紧密结合,提供了简洁、安全的分布式编程方式;CORBA 通过 IDL 实现了跨语言的分布式对象通信,具有更高的灵活性和通用性。
在未来的分布式系统开发中,开发者可以根据项目的具体需求选择合适的技术。同时,随着技术的不断发展,可能会出现将两者优势结合的新方法,以满足更复杂、多样化的分布式应用需求。例如,在某些对安全性要求高且需要跨语言交互的系统中,可以探索如何在 DSA 的基础上引入 CORBA 的部分特性,实现更强大的分布式功能。
总之,无论是 DSA 还是 CORBA,它们都为分布式系统编程提供了重要的技术支持,在不同的领域发挥着重要作用。开发者需要深入理解它们的特点和差异,才能在实际项目中做出更合适的选择。
5845

被折叠的 条评论
为什么被折叠?



