聊聊 RPC
每个分布式系统都离不开多进程的通信问题,包括本机上多进程之间的IPC通信和基于**的远程通信技术,后者是分布式系统架构中的核心和关键基础技术之一,就远程通信而言,抛开各种专用系统的远程通信协议如 NFS、FTP、SNMP、**TP、POP3不说,各种通用的远程通信技术也在不断发展和变化,比如从最古老的RPC远程通信技术到曾经风靡一时的SOAP( Web Service)协议,再到后面红极一时的HTTP REST。如今,由于移动互联网和大数据时代的兴起,支持多语言与高性能传输的各种 RPC架构再次成为热点技术。
IPC通信
从严格意义上来说,一个系统由多个独立的进程组成,而且进程之间有数据交互的逻辑,那么,不管这几个进程是否被部署在一台主机上,这样的系统都可以叫作分布式系统。IPC( Inter-Process Communication)就是为了解决单主机上多进程之间的通信问题而诞生的一种古老技术。由于进程与操作系统是密切相关的,因此操作系统的不同会导致IPC的具体实现也各有不同,但不管是 Windows系统还是Linux系统,都支持以下几种进程间的通信技术。
命名管道(Named Pipe或FIFO)不同于匿名管道之处,在于它提供了一个路径名与之关联,以FIFO的文件形式存在于文件系统中。这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信(能够访问该路径的进程及FIFO的创建进程之间),因此,与FIFO不相关的进程也能交换数据。值得注意的是,FIFO严格遵循先进先出(first in first out)的原则,对管道及FIFO的读总从开始处返回数据,对它们的写则把数据添加到末尾。它们不支持诸如寻址等文件的定位操作。
Socket API原本是为**通信设计的,但后来在Socket 的框架上发展出一种IPC机制,就是UNIX Domain Socket。UNIX Domain Socket也提供面向流和面向数据包两种API接口,类似于TCP和UDP。虽然普通的TCP Socket也可用于同一台主机的进程间通信(通过loopback地址127.0.0.1),但UNIX Domain Socket 在同一台主机上的传输速度是TCP Socket 的两倍,这是因为UNIX Domain Socket不需要经过**协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层的数据从一个进程**到另一个进程,所以速度更快。
UNIX Domain Socket用于IPC通信的具体编程方式与普通的TCP Socket编程没有太大的差别,性能又高,还很容易从单机通信扩展为多主机间的通信,所以这种方式逐步代替了管道的方式。
共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式。两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同一块内存区域,所以必然需要某种同步机制,互斥锁和信号量都可以。
采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的**。对于像管道和套接字这种方式,需要在内核和用户空间进行4次数据**,共享内存则只**两次数据:一次从输入文件到共享内存区;另一次从共享内存区到输出文件。实际上,进程之间在共享内存时始终保持共享区域,直到通信完毕。这样,数据的内容一直被保存在共享内存中,并没有写回文件。共享内存中的内容往往是在解除映射时才写回文件的。因此,采用共享内存通信方式的效率是非常高的。
Linux内核支持多种共享内存方式,例如mmap()系统调用、Posix共享内存及系统共享内存。目前主流的做法是通过 mmap()实现共享内存,当多个程序调用mmap()映射到同一个文件时,它们实际访问的必然是同一个共享内存区域对应的物理页面。
本文给大家讲解的内容是架构解密从分布式到微服务:带大家聊聊RPC——IPC通信