分布式系统:进程间通信

进程间通信概述

进程间通信(interprocess communication)主要讨论了分布式系统进程之间的通信协议的特征,数据报和流通信机制为通信协议提供了可互换的构造成分。UDP 的应用程序接口提供了消息传递(message passing)抽象,使得一个发送进程能够给一个接收进程传递一个消息。UDP 实现的是进程间通信的最简单形式,包含这些消息的独立的数据包称为数据报(datagram)。TCP 的应用程序接口提供了进程对之间的双向流(two-way stream)抽象,相互通信的信息由没有消息边界的一连串数据项组成。这些用于进程间通信的服务支持点对点通信,而且也能实现组播通信,也就是从一个发送者发送一个消息给一组接收者。消息传递接口(Message Passing Interface, MPI)是一个标准,为一组具有同步和异步支持的消息传递操作提供 API。

互联网协议 API

进程间通信的特征

一对进程间进行的消息传递由 send 和 receive 这两个消息通信操作来支持,它们均用目的地和消息定义。进程通信时由一个进程发送一个消息(字节序列)到目的地,在目的地的另一个进程接收消息。每个消息目的地与一个队列相关,发送进程将消息添加到远程队列中,接收进程从本地队列中移除消息。
进程之间的通信可以是同步的也可以是异步的,在同步(synchronous)形式的通信中,发送进程和接收进程在每个消息上同步。此时 send 和 receive 都是阻塞操作,发送进程发出一个 send 操作后将一直阻塞,直到发送了相应的 receive 操作为止。每次发送一个 receive 后,进程将一直阻塞,直到消息到达为止。

异步(asynchronous)形式的通信中,send 操作是非阻塞的,只要消息被复制到本地缓冲区,发送进程就可以继续进行其他处理。receive操作有阻塞型和非阻塞型两种形式:在不阻塞的 receive 操作中,接收进程在发出 receive 操作后可继续执行它的程序;在支持多线程的系统环境中,在一个线程发出阻塞型 receive 操作时,该进程中的其他线程仍然是活动的。非阻塞型的通信看上去更有效,但接收进程需要从它的控制流之外获取到达的消息,这涉及额外的复杂工作。

本地端口是计算机内部的消息目的地,用一个整数指定,一个端口只能有一个接收者但可以有多个发送者。进程可以使用多个端口接收消息,任何知道端口号的进程都能向端口发送消息。可靠通信需要满足有效性和完整性:

可靠通信 说明
有效性 如果一个点对点消息服务在丢失了“合理”数量的数据包后,仍能保证发送消息,则该服务就被称为可靠的。相反只丢失一个数据包就仍是不可靠的。
完整性 到达的消息必须没有损坏,且没有重复,有些应用要求消息要按发送方的顺序发送。

套接字

UDP 和 TCP 都使用套接字(socket)抽象,它提供进程间通信的一个端点,进程间通信是在两个进程各自的一个套接字之间传送一个消息。对接收消息的进程,它的套接字必须绑定到计算机的一个互联网地址和一个本地端口,发送到特定互联网地址和端口号的消息只能被一个对应的套接字相关的进程接收。进程可以使用同一套接字发送和接收消息,任意一个进程可利用多个端口来接收消息,但一个进程不能与同一台计算机上的其他进程共享端口。

UDP 数据报通信

由 UDP 发送的数据报从发送进程传输到接收进程,不需要确认或重发,如果发生故障则消息可能无法到达目的地。要发送或接收消息,进程必须创建与一个本地主机的互联网地址和本地端口绑定的套接字,服务器将把套接字绑定到一个服务器端口(server port)。客户客户将它的套接字绑定到任何一个空闲的本地端口,给该端口发送消息。Receive 方法除了获得消息外,还获得发送方的互联网地址和端口,用于允许接收方发送应答。

以下是一些数据报通信的机制设置:

数据报通信机制 说明
消息大小 接收进程要指定固定大小的用于接收消息的字节数组,如果消息大于数组大小,则消息在到达时会被截断
阻塞 send 操作将消息传递给 UDP 和 IP 协议后就返回,除非设置了超时,否则 receive 方法将一直阻塞直到接收到一个数据报为止
超时 发送进程可能崩溃或期待的消息已经丢失,阻塞的 receive 操作不适合无限制地等待下去,此时要在套接字上设置超时
任意接收 调用 receive 可以获得从任何来源发到它的套接字上的消息,并返回发送方的互联网地址和本地端口,允许接收方检查消息的来源

UDP 数据报存在下列故障,如果想获得所要求的可靠通信的质量,应用要自己提供检查手段,可以利用确认机制将一个有遗漏故障的服务构造为可靠传送服务。

UDP 数据报故障 说明
遗漏故障 可能是因为校验和错误或者在发送端或目的端没有可用的缓冲区空间,消息偶尔会丢失
排序 消息有时没有按发送方顺序发送

对某些应用而言,使用偶尔有遗漏故障的服务是可接受的,例如 DNS、VOIP 等。UDP 数据报没有与保证消息传递相关的开销,因此有时是一个很有吸引力的选择,它开销主要源自三个方面:在源和目的地存储状态信息、传输额外的消息、发送方的延迟。

TCP 流通信

TCP 流通信的 API 假设,建立连接时由客户进程向服务器进程发起请求,建立连接后两个进程是平等的。客户角色需要创建绑定到端口的流套接字,然后发出 connect 请求,在服务器的端口上请求与服务器连接。服务器角色需要创建绑定到服务器端口的监听套接字,然后等待客户请求连接。监听套接字维护到达的连接请求队列,当服务器 accept 一个连接,就创建一个新的流套接字用于与客户的通信,同时保持在服务器端口上的套接字用于监听其他客户的comnect 请求。客户和服务器的套接字对由一对流相连接,进程对中的任何一个进程都可以通过将信息写入它的输出流来发送信息给另一个进程,而另一个进程通过读取它的输入流来获得信息。当一个应用 close 一个套接字时,表示它不再写任何数据到它的输出流,输出缓冲区中的任何数据被送到流的另一端,并指明流已断开了。当进程退出或失败时,它的所有套接字最终被关闭,任何试图与它通信的进程将发现连接已中断。

以下是一些流通信的机制设置:

流通信机制 说明
消息大小 应用能选择它写到流中和从流中读取的数据量,如果有必要应用可以强制数据马上发送
丢失的消息 如果在一个超时时间段内,发送方没有接收到确认信息,则发送方重传该消息
流控制 如果对读取流的进程来说写人流的进程太快,那么它会被阻塞直到读取流的进程消化掉足够的数据为止
消息重复和排序 每个 IP 数据包与消息标识符相关联,接收方能检测和丢弃重复的消息,或重排没有按序到达的消息
消息目的地 建立连接后,进程不需要使用互联网地址和端口即可读、写流

以下是一些与流通信相关的问题:

流通信的重要问题 说明
数据项的匹配 两个通信进程需要对在流上传送的数据的内容达成一致
阻塞 如果在另一端的套接字队列中的数据与协议允许的数据一样多,则将数据写入流的进程可能被 TCP 流控制机制阻塞
线程 接受连接时通常是创建一个新线程进行通信,此时服务器在等待输入时能阻塞而不会延误其他客户

为保证完整性,TCP 流使用校验和检查并丢弃损坏的数据包,使用序列号检测和丢弃重复的数据包。为保证有效性,TCP 流使用超时和重传来处理丢失的数据包。因此即使底层有些数据包丢失,还是可以保证消息的传输。但是如果连接上的数据包丢失超过了限制,以及连接一对通信进程的网络不稳定或严重拥塞,则负责发送消息的 TCP 软件将收不到确认。这种情况持续一段时间之后,TCP 就会声明该连接已中断,此时就不能提供可靠通信了。这会造成下列后果:

  1. 使用连接的进程不能区分是网络故障还是连接另一端的进程故障;
  2. 通信进程不能区分最近它们发送的消息是否已被接收。

许多经常使用的服务都是使用保留的端口号,在 TCP 连接上运行的,例如:

基于 TCP 的服务 协议名称 说明
HTTP 超文本传送协议 用于Web浏览器和 Web 服务器之间的通信
FTP 文件传输协议 允许浏览远程计算机上的目录,以及通过连接将文件从一台计算机传输到另一台计算机
telnet telnet 利用终端会话访问远程计算机
SMTP 简单邮件传输协议 用于在计算机之间发送邮件

外部数据表示和编码

外部数据表示

消息中的信息由字节序列组成,因此不论使用何种通信形式,内存中的数据结构在传输前必须转换成字节序列,到达目的地后重构。在消息中传送的单个简单数据项可以是不同类型的数据值,不是所有的计算机都以同样的顺序存储整数这样的简单值,用于表示字符的代码集也可能不同。下列方法可用于使两台计算机交换数据值:

  1. 值在传送前先转换成一致的外部格式,然后在接收端转换成本地格式。如果两台计算机是同一类型,可以不必转换成外部格式。
  2. 值按照发送端的格式传送,同时传送所使用格式的标志,接收方会根据需要转换该值。

为了支持 RMI 或 RPC,任何能作为参数传递或作为结果返回的数据类型必须被序列化,令数据值以一致的格式表示。表示数据结构和简单值的一致的标准称为外部数据表示,通过编码和解码两个步骤完成。编码是将多个数据项组装成适合消息传送的格式的过程,将结构化数据项和简单值翻译成外部数据表示。解码是在消息到达后分解消息,在目的地生成相等的数据项的过程,也就是从外部数据表示生成简单值并重建数据结构。

常用的表示和编码方法

以下是三种常用的外部数据表示和编码的方法,在前两种情况下,编码和解码活动均由中间件层完成,XML 的编码和解码软件也对所有平台和编程环境可用。编码要求考虑组成组合对象的简单组件的表示细节,所以如果手工完成该过程,那么整个过程很容易出错。在前两个方法中,简单数据类型被编码成二进制形式,在 XML 中简单数据类型表示成文本,通常数据值的文本表示将比等价的二进制表示更长。另一个问题是被编码数据是否应该包括与其内容的类型有关的信息,CORBA 的表示只包括所传送的对象的值不包含它们的类型。序列化和 XML 都包括了类型信息,序列化把所有需要的类型信息放到格式中,XML 文档可以指向类型的外部定义集合,即名字空间(namespace)。

流通信的重要问题 说明
CORBA 在 CORBA 的远程方法调用中能作为参数和结果传送的结构化类型和简单类型的外部表示
对象序列化 涉及需要在消息中传送或存储到磁盘上的单个对象或对象树的序列化和外部数据表示
XML 定义了表示结构化数据的文本格式,用于在 Web 服务中被客户和服务器交换的消息中的数据

远程对象引用

远程对象引用仅适用于诸如 Java 和 CORBA 这样的支持分布对象模型的语言,与 XML 无关。客户调用远程对象中的一个方法时,就会向存放远程对象的服务器进程发送一个调用消息,这个消息指定哪一个对象具有要调用的方法。远程对象引用(remote object reference)是远程对象的标识符,用于指定调用哪一个对象,在整个分布式系统中有效。
通常在远程对象上有许多进程,因此远程对象引用必须以确保空间和时间唯一性的方法生成。即使在删除与给定远程对象引用相关的远程对象后,该远程对象引用也不能被重用。一种方法是通过拼接计算机的互联网地址、创建远程对象引用的进程的端口号、创建时间和本地对象编号来构造远程对象引用。在 RMI 的最简单实现中,远程对象仅在创建它们的进程中存在,并只在该进程运行时存活,此时远程对象引用可以作为远程对象的地址。

组播通信

有时候一个进程与一组进程通信可能是必要的,例如为了提供容错能力或为了提高可用性,将一个服务实现为多个不同计算机上的多个不同的进程。组播操作(multicast operation)是更合适的方式,这是一个将单个消息从一个进程发送到一组进程的每个成员的操作,组的成员对发送方通常是透明的。组播消息为构造具有下列特征的分布式系统提供了基础设施:

基于组播的分布式系统设施 说明
基于复制服务的容错 客户请求被组播到组的所有成员执行相同的操作,即使一些成员出现故障,仍能为客户提供服务
在自发网络中发现服务 使用组播消息找到可用的发现服务,以便在分布式系统中注册服务接口或查找其他服务的接口
通过复制的数据获得更好的性能 数据的副本有时可以放在用户的计算机上,每次数据改变,新的值便被组播到管理副本数据的各个进程
事件通知的传播 在发生某些事情时导致状态改变时,通知有关进程

IP 组播(IP multicast)在网际协议 IP 的上层实现,使发送方能够将单个 IP 数据包传送给组成组播组的一组计算机。组播组(multicast group)由 D 类互联网地址指定,组播组的成员允许计算机接收发送给组的 IP 数据包。组播组的成员是动态的,计算机可以在任何时间加入或离开,计算机也可以加入任意数量的组。IP 组播只能通过 UDP 可用,应用程序通过发送具有组播地址和普通的端口号的 UDP 数据报完成组播。在 IP 层当一个或多个进程具有属于一个组播组的套接字时,该计算机属于这个组播组。当一个组播消息到达计算机时,消息副本被转发到所有已经加人到指定组播地址和指定端口号的本地套接字上。

IPv4 组播有一些特有的机制,IP 数据包可以再局域网或互联网上组播,其中互联网上的组播利用了组播路由器,由它将单个数据报转发到其他成员所在网络的路由器上,再通过路由器组播到本地成员。在组播地址分配方面,D 类地址(224.0.0.0~239.255.255.255)作为组播通信的保留地址,组播地址可以是永久的,也可以是暂时的。剩下的组播地址可用于临时组,这些组必须在使用前创建,在所有成员离开的时候消失。

IP 组播上的数据报组播与 UDP 数据报有相同的故障特征,也就是说 IP 组播也会存在遗漏故障。从一个组播路由器发送到另一个路由器的数据报也可能丢失,这妨碍了另一端路由器的接收者接收消息。对局域网的组播而言,任何一个接收者都可能因为它的缓冲区已满而丢弃消息。还有一个问题是排序,在网络上发送的 IP 数据包不一定按序到达,此时组中的一些成员从同一个发送者处接收的数据报的顺序可能与其他组成员接收的顺序不一样。

网络虚拟化和覆盖网络

不断增加的大量不同类型的应用在互联网上并存,试图更改互联网协议来适应运行在其上的每一个应用是不实际的,而且大量持续增多的网络技术都是使用 IP 服务实现的。这两个因素促使了网络虚拟化,这个概念涉及在一个已有的网络之上构造多个不同的虚拟网络,每个虚拟网络被设计成支持一个特定的分布式应用。一种解决方案是,一个面向特定应用的虚拟网络能建在一个已有的网络上并进行针对性的优化,而不改变底层网络的特征。
覆盖网络(overlay network)是一个结点和虚拟链接组成的虚拟网络,位于一个底层网络(如 IP 网络)之上,能提供如下所示的一些独有的功能。覆盖网络使得不改变底层网络就能定义新的网络服务,同时鼓励了对网络服务进行实验和对服务进行面向特定应用的定制。覆盖网开发者能自由地重定义网络的核心元素,包括寻址的模式、所采用的协议和路由的方法,能针对操作环境的特定应用进行裁剪。实践上能定义多个同时存在的覆盖网(overlay),从而形成更开放和可扩展的网络体系结构。覆盖网的不足是引入了额外的间接层,增加了网络服务的复杂性。

  1. 满足一类应用需求的服务或一个特别高层的服务,例如多媒体内容的分发;
  2. 在一个给定的联网环境中的更有效的操作,例如在一个自组织网络中的路由;
  3. 提供一些额外的功能,例如组播或安全通信。

Skype 是一个在 IP 上提供语音电话服务(Voice over IP,VoIP)的对等应用,它在不修改互联网核心体系结构的前提下以应用特定的方式提供高级功能。Skype 基于对等基础设施,由普通用户的机器(称为宿主机)和超级结点组成,超级结点是有足够的能力完成其增强角色的普通 Skype 宿主机。超级结点基于一系列标准按需选择出来的,包括可用的带宽、可达性和可用性。Skype 用户通过一个众所周知的登录服务器进行认证,接着他们可以与一个选中的超级结点连接。超级结点的主要目的是完成对用户全局索引的搜索,整个搜索由客户所选中的超级结点进行协调,会涉及扩展到其他超级结点的搜索,直到找到所指定的用户。一旦发现了所请求的用户,Skype 就在双方之间建立一个声音连接,用 TCP 触发呼叫请求和呼叫终止,用 UDP 或 TCP 传输流或音频。

参考资料

《分布式系统概念与设计》[英]George Coulouris, Jean Dollimore, Tim Kindberg,Gordon Blair,金蓓弘,马应龙 译,机械工业出版社

posted @ 2024-03-13 14:12  乌漆WhiteMoon  阅读(117)  评论(0编辑  收藏  举报