分布式系统中的进程标识

【Proteus仿真】基于74LS148+74LS279+74LS48的四路抢答器 阅读详情

陈硕 (giantchen_AT_gmail)

Blog.youkuaiyun.com/Solstice

昨天跟朋友聊天,谈到了分布式系统中如何为进程取标识符(process identifier),写篇博客简单总结一下我的观点。

本文假定一台机器 (host) 只有一个 IP,不考虑 multihome 的情况。同时假定分布式系统中的每一台机器都正确运行了 NTP,各台机器的时间大体同步。

“进程 process”是操作系统的两大基本概念之一,指的是在内存中运行的程序。在日常交流中,“进程”这个词通常不止这一个意思。有时候我们会说 “httpd 进程”或者“mysqld 进程”,指的其实是 program,而不一定是特指某一个“进程”——某一次 fork() 系统调用的产物。一个“httpd 进程”重启了,它还是“一个 httpd 进程”。本文讨论的是,如何为一个程序每次运行 的进程取一个唯一标识符。也就是说,httpd 程序第一次运行,进程是 httpd_1,它原地重启了,进程是 httpd_2。

本文所指的“进程标识符”是用来唯一标识一个程序的“一次运行”的。每次启动一个进程,这个进程应该被赋予一个唯一的标识符,与当前正在运行的所有进程都不同;不仅如此,它应该与历史上曾经运行过,目前已消亡的进程也都不同(这两条的直接推论是,与将来可能运行的进程也都不同)。“为每个进程命名”在分布式系统中有相当大的实际意义,特别是在考虑 failover 的时候。因为一个程序重启之后的新进程和它的“前世进程”的状态通常不一样,凡是与它打交道的其他进程(s)最好能通过它的进程标识符变更来很容易地判断该程序已经重启,而采取必要的救灾措施,防止搭错话。

 

本文先假定每个服务端程序的端口是静态分配的,在公司内部有一个公用 wiki 来记录端口和程序的对应关系(然后通过 NIS 或 DNS 发布)。比如端口 11211 始终对应 memcached,其他程序不会使用 11211 端口;3306 始终留给 mysqld;3690 始终留给 svnserve。在分布式系统的初级阶段,这是通常的做法;到了高级阶段,多半会用动态分配端口号,因为端口号只有 6 万多个,是稀缺资源,在公司内部也有分配完的一天。本文只考虑 TCP 协议,不考虑 UDP 协议,“端口”都指的是 TCP 端口。

另外,我们假定在一台机器上,一个 listening port 同时只能由一个进程使用,不考虑古老的 listen() + fork() 模型(多个进程可以 accept 同一个端口上进来的连接),关于这点陈硕已经写的很多,见《Linux 新增系统调用的启示 》《多线程服务器的适用场合 》。

错误做法

在分布式系统中,如何指涉(refer to)某一个进程呢,或者说一个进程如何取得自己的全局标识符 (以下简称 gpid)?容易想到的有两种做法:

  • ip:port (port 是这个进程对外提供网络服务的端口号,一般就是它的 tcp listening port)
  • host:pid

而这两种做法都有问题。为什么?

如果进程本身是无状态的,或者重启了也没有关系,那么用 ip:port 来标识一个“服务”是没问题的,比如常见的 httpd 和 memcached 都可以用它们的惯用 port (80 和 11211)来标识。我们可以在其他程序里安全地引用(refer to)“运行在 10.0.0.5:80 的那个 http 服务器”,或者“10.0.0.6:11211 的 memcached”,就算这两个 service 重启了,也不会有太恶劣的后果,大不了客户端重试一下,或者自动切换到备用地址。

如果服务是有状态的,那么 ip:port 这种标识方法就有大问题,因为客户端无法区分从头到尾和自己打交道的是一个进程还是先后多个进程。在开发服务端程序的时候,为了能快速重启,我们一般都会设置 SO_REUSEADDR,这样的结果是前一秒钟站在 10.0.0.7:8888 后面的进程和后一秒钟占据 10.0.0.7:8888 的进程可能不相同——服务端程序快速重启了。

比方说,考虑一个类似 GFS 的分布式文件系统的 master,如果它仅以 ip:port 来标识自己,然后它向 shadows (不是 chunk server)下达同步指令,那么 shadows 如何得知 master 是不是已经重启呢?发指令的是 master 的“前世”还是“今生”?是不是应该拒绝“前世”的遗命?

 

如果考虑改成 host:pid 这种标识方式会不会好一点?我认为换汤不换药,因为 pid 的状态空间很小,重复的概率比较大。比如 Linux 的 pid 的最大值是 32768 (/proc/sys/kernel/pid_max),一个程序重启之后,获得与“前世”相同 pid 的概率是 1/32768。或许有读者不相信重启之后 pid 会重复,因为 pid 是递增的,遇到上限再回到目前空闲的最小 pid。考虑一个服务端程序 A,它的 pid 是 1234,它已经稳定运行了好几天,这期间,pid 已经增长了几个轮回(因为这台机器时常会启动一些 scripts 执行一些辅助工作)。在 A 崩溃的前一刻,最近被使用的 pid 已经回到了 1232,当 A 崩溃之后,某个守护进程启动一个脚本(pid = 1233)来清理 A 的 log,然后再重启 A 程序;这样一来,重启之后的 A 程序的 pid 碰巧和它的前世相同,都是 1234。也就是说,用 host:pid 不能唯一标识进程。

 

那么合在一起,用 ip:port:pid 呢?也不能做到唯一。它和 host:pid 面临的问题是一样的,因为 ip:port 这部分在重启之后不会变,pid 可能轮回。

我猜这时有人会想,建一个中心服务器,专门分配系统的 gpid 好了,每个进程启动的时候向它询问自己的 gpid。这错得更远:这个全局 pid 分配器的 gpid 由谁来定?如何保证它分配的 gpid 不重复(考虑这个程序也可能意外重启)?它是不是成为系统的 single point of failure?如果要对该 gpid 分配器做容错,是不是面临分布式系统的基本问题:状态迁移?

还有一种办法,用一个足够强的随机数做 gpid,这样一来确实不会重复,但是这个 gpid 本身也没有多大额外的意义,不便于管理和维护(比方说根据 gpid 找到是哪个机器上运行的哪个进程)。

正确做法

正确做法:以四元组 ip:port:start_time:pid 作为分布式系统中进程的 gpid,其中 start_time 是 64-bit 整数,表示进程的启动时刻(UTC 时区,muduo::Timestamp)。理由如下:

  • 容易保证唯一性。如果程序短时间重启,那么两个进程的 pid 必定不重复(还没有走完一个轮回:就算每秒创建 1000 个进程,也要 30 多秒才会轮回,而以这么高的速度创建进程的话,服务器已基本瘫痪了。);如果程序运行了相当长一段时间再重启,那么两次启动的 start_time 必定不重复。(见下文关于时间重复的解释)
  • 产生这种 gpid 的成本很低(几次低成本系统调用),没有用到全局服务器,不存在 single point of failure。
  • gpid 本身有意义,根据 gpid 立刻就能知道是什么进程(port),运行在哪台机器(ip),是什么时间启动的,在 /proc 目录中的位置 (/proc/pid) 等,进程的资源使用情况也可以通过运行在那台机器上的监控程序报告出来。
  • gpid 具有历史意义,便于将来追溯。比方说进程 crash,那么我知道它的 gpid,就可以去历史记录中查询它 crash 之前的 cpu/mem 负载有多大。

如果仅以 ip:port:start_time 作为 gpid,则不能保证唯一性,如果程序短时间重启(间隔一秒或几秒),start_time 可能会往回跳变(NTP 在调时间)或暂停(正好处于闰秒期间)。关于时间跳变的问题留给下一篇博客《〈程序中的日期与时间〉第二章:计时与定时》,简单地说,计算机上的时钟不一定是单调递增的。

 

没有 port 怎么办?一般来说,一个网络服务程序会侦听某个端口来提供服务,如果它是个纯粹的客户端,只主动发起连接,没有主动侦听端口,gpid 该如何分配呢?根据陈硕在《分布式系统的工程化开发方法 》一文中的观点“在程序里内置 http 服务器”,分布式系统中的每个长期运行的、会与其他机器打交道的进程都应该提供一个管理接口,对外提供一个维修探查通道,可以查看进程的全部状态。这个管理接口就是一个 TCP server,它会侦听某个 port。

使用这样的维修通道的一个额外好处是,可以自动防止重复启动程序。因为如果重复启动,bind 到那个运维 port 的时候会出错(端口已被占用),程序会立刻退出。更妙的是,不用担心进程 crash 没来得及清理锁(如果用跨进程的 mutex 就有这个风险),进程关闭的时候操作系统会自动把它打开的 port 都关上,下一个进程可以顺利启动。

 

进一步,还可以把程序的名称和版本号作为 gpid 的一部分,这起到锦上添花的作用。

TCP 协议的启示

我在《分布式系统的工程化开发方法 》中提到“从 TCP 协议能学到什么?”,今天讲的这个 gpid 其实也是由 TCP 协议启发而来。TCP 用 ip:port 来表示 endpoint,两个 endpoint 构成一个 socket。这似乎符合一开始提到的以 ip:port 来标识进程的做法。其实不然。在发起 TCP 连接的时候,为了防止前一次同样地址的连接(相同的 local_ip:local_port:remote_ip:remote_port)的干扰(称为 wandering duplicates ,即流浪的 packets),TCP 协议使用 seq 号码(这种在 SYN packet 里第一次发送的 seq 号码称为 initial sequence number, ISN)来区分本次连接和以往的连接。TCP 的这种思路与我们防止进程的“前世”干扰“今生”很相像。内核每次新建 TCP 连接的时候会设法递增 ISN 以确保与上次连接最后使用的 seq 号码不同。相当于说把 start_time 加入到了 endpoint 之中,这就很接近我们后面提到的“正确的 gpid”做法了。(当然,原始 BSD 4.4 的 ISN 生成算法有安全漏洞,会导致 TCP sequence prediction attack,Linux 内核已经采用更安全的办法来生成 ISN。)

从 VL02N 拣配到 ABAP 自动化,读懂 SD_DELIVERY_UPDATE_PICKING 的位置和风险 文章摘要:SAP SD模块中,SD_DELIVERY_UPDATE_PICKING函数模块用于处理出库交货单的拣配确认,更新交货项目的拣配数量。该函数适用于未启用WM/EWM的传统SD流程,能确保拣配状态与标准交货处理逻辑同步,比直接修改数据库更安全。但在S/4HANA Cloud等新环境中,应优先使用API_OUTBOUND_DELIVERY_SRV等公开发布接口。使用该函数时需注意参数完整性和按交货单整体处理的原则,避免逐项提交导致的数据不一致问题。(149字) 阅读详情

相关推荐

从原理图到PCB:基于Allegro的8槽PXIe背板高速设计实战

本文详细介绍了基于Allegro软件进行8槽PXIe背板高速设计的完整实战流程。从理解规范、原理图设计、PCB布局规划,到高速PCIe差分对与精密时钟的布线艺术,再到电源与地处理以及最终的设计验证与生产文件输出,系统性地阐述了确保背板信号完整性、电源完整性和系统稳定性的关键技术与工程实践。

weixin_28312391的博客 205

计算机网络核心(2)

五、HTTP 简介 HTTP 即超文本传输协议,是属于应用层的协议,是一个基于请求与响应模式的无状态的应用层的协议,常基于 TCP 的连接方式。 HTTP 目前正处于多个版本共存的情况,包括仍被广泛采用的 1.0, 主流最为广泛的 1.1, 还有应用较少、NB 吹的最大的 2.0. 1.1 相交于 1.0 最明显的区别是引入了 keep-alive 这项长连接技术,2.0 虽然更合理、更先进,但其...

Arvin的博客 1051

A股历史数据免费下载终极指南:4000+个股数据一键打包获取

本文提供了获取A股历史数据的完整免费方案,重点介绍了Tushare Pro、AkShare等开源金融数据API的使用方法。通过详细的Python脚本示例,指导读者如何自动化批量抓取、清洗、存储4000多只个股的历史行情数据,并分享数据质量校验与性能优化技巧,助力量化研究与市场分析。

ooo22的博客 2236

分布式操作系统 - 3.分布式进程管理

东北大学 分布式操作系统笔记

wdn blog 1333

【干货】S7-PLCSIM Advanced V3.0 无法启动实例( Error Code:-30,LicenseNotFound)问题解决方法

【干货】S7-PLCSIM Adavanced V3.0 无法启动实例( Error Code:-30,LicenseNotFound)问题解决方法

handinvv的博客 5万+

<202505高项>《【VIP合集】 软考高项(第四版)十大知识域、五大过程组、ITTO输入输出工具、项目绩效域》

软考高项(第四版)十大知识域、五大过程组、ITTO输入输出工具、项目绩效域

Else 的博客 1854

BackTrack5 学习笔记5 扫描 Nmap

本系列文章来自《高度安全环境下的高级渗透测试》一书学习笔记。一、NmapNmap 可以用来扫描一个网络、监控服务、帮助列出网络主机等。Nmap能够提供操作类型、开放端口等信息。Nmap脚本引擎可以扩展Nmap的功能。 之前文章简单介绍过其使用: http://blog.youkuaiyun.com/xundh/article/details/466423571. NMap家族 ZenMap Neat:基于n

猿来这样-谢厂节的博客 3221

TI毫米波雷达人体生命体征(呼吸、心跳)信号提取算法(IWR6843ISK+DCA1000EVM)

本篇内容介绍的算法主要为传统的提取算法,但可实现在1m内呈现良好的检测效果,能够提取出非常可观的呼吸和心跳波形,但在超出1m的距离后便不适用这个算法了。远距离检测呼吸和心跳始终是这个领域一个很大的挑战。要实现远距离检测可在提取相位信号、分离呼吸和心跳信号上进行改进处理,例如线性解调提取相位、改进的VMD分离呼吸和心跳算法。

m0_61934621的博客 3万+

进程协作之分布式互斥

进程协作 进程协作分类: 分布式互斥:如何保证临界资源的互斥利用 选举:如何保证从多个并发进程中选举出一个进程扮演协调者 事件排序;组通信中的排序组播:如何就一组进程间发生的事件的顺序达成一致 分布式死锁:要求一组进程对共享资源进行公平的源自访问,不出现死锁,不出现饿死 同步器:在异步网络中模拟时钟的嘀嗒(tick,round) 有序组播 FIFO排序:如果一个进程发multicast(g, m),然后发multicast(g, m’),那么,每个传递m’的正确的进程将在m’前传递m 因果排序:如果 m

u012413204的博客 897

SAP FICO实操:如何修改已发生业务数据的成本中心公司代码(附RKACOR06程序运行指南)

本文详细解析了SAP FICO系统中使用RKACOR06程序修改已发生业务数据的成本中心和公司代码的实操方法。通过实战案例分享,提供从前期准备到后期验证的全流程指南,帮助企业应对组织架构重组或财务核算体系调整时的数据迁移挑战,特别适用于跨公司代码的成本中心划转场景。

weixin_27303545的博客 189

stable diffusioncontrolNet 预处理器/模型的下载及安装使用教程

首先说明,controlNet 的模型 不同于stable diffusion 模型,这一点一定要区分清楚。下面提供多个ControlNet 预处理器+ 专用模型的百度网盘下载链接,都是由群友整理贡献,但各自包含的版本不同,大家可自行选择。推荐下载紫色链接内的模型,fp16版文件更小,稍微新一些的controlnet插件还添加了对control-lora的支持(注意,要求controlnet插件的版本比12月16号新(1.1.423以上)才能正常识别),推荐下载;

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 3385

python笔记:进程和线程—分布式进程

一、分布式进程Process可以分布到多台机器上,而Thread最多只能分布到同一台机器的多个CPU上。Python的multiprocessing模块不但支持多进程,其中managers子模块还支持把多进程分布到多台机器上。一个服务进程可以作为调度者,将任务分布到其他多个进程中,依靠网络通信。由于managers模块封装很好,不必了解网络通信的细节,就可以很容易地编写分布式多进程程序。二、举例实...

zyckhuntoria的博客 488

uniapp - 解决报错 canvasToTempFilePath: fail canvas is empty 画布为空错误,生成海报相册、二维码、条码、裁剪/拼合操作图片报错,加了this还是报错

uni-app,h5移动端网页,微信小程序,支付宝小程序,Android安卓,苹果ios,app,nvue,canvasToTempFilePath:失败画布为空,报错,canvasToTempFilePath:failcanvasisempty,不支持2d,还是报错,this,加上this还是报错,vue3没有this怎么办?海报,保存到手机相册,生成二维码,显示条码,图像裁切,图片处理,canvas报错,无法解决,还是fail,依然报错,传了this也不好使,Uniapp小程序,如何解决这个问题

🏆 前端领域优质创作者 4708

AI搜索实战:从RAG原理到工具评测与落地实现

大模型训练数据存在知识断层,无法回答实时信息,这让“联网搜索”成为AI应用落地的重要能力。其底层依赖检索增强生成(RAG)技术,通过查询理解、文档检索、内容重排与答案生成,让模型基于外部实时数据给出可溯源的回答。RAG不仅支撑了Perplexity、秘塔AI搜索等工具,也是AI Agent调用搜索API、实现Function Calling的关键框架。本文从RAG原理出发,结合真实体验横向评测五款主流AI搜索工具,并给出基于LangChain和Spring AI的联网搜索实操示例,覆盖API接入、重排序、超

weixin_34056162的博客 461

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

C语言分布式系统中的进程标识

本文来自:智趣网-C/C++语言编程技术交流论坛http://www.bczh.net 本文假定一台机器 (host) 只有一个 IP,不考虑 multihome 的情况。同时假定分布式系统中的每一台机器都正确运行了 NTP,各台机器的时间大体同步。  “进程 process”是操作系统的两大基本概念之一,指的是在内存中运行的程序。在日常交流中,“进程”这个词通常不止这一个意思。有时候我们会

bys689的专栏 453

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

分布式系统 c语言,C语言分布式系统中的进程标识!

该楼层疑似违规已被系统折叠隐藏此楼查看此楼如果进程本身是无状态的,或者重启了也没有关系,那么用 ip:port 来标识一个“服务”是没问题的,比如常见的 httpd 和 memcached 都可以用它们的惯用 port (80 和 11211)来标识。我们可以在其他程序里安全地引用(refer to)“运行在 10.0.0.5:80 的那个 http 服务器”,或者“10.0.0.6:11211...

weixin_39715997的博客 152

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

构建一个分布式操作系统的简单方案—答陈硕的“分布式系统中的进程标识”一文

本文提出了构建一个分布式操作系统的简单方案。核心是使用ssh的强大能力,构建一个简单、安全、灵活、高效的分布式操作系统!并且没有单点失效的问题。注意,是通用的分布式操作系统,而不是专用的分布式系统。

【良少课堂】 9556

c语言获取进程标识符,C语言分布式系统中的进程标识!

该楼层疑似违规已被系统折叠隐藏此楼查看此楼如果进程本身是无状态的,或者重启了也没有关系,那么用 ip:port 来标识一个“服务”是没问题的,比如常见的 httpd 和 memcached 都可以用它们的惯用 port (80 和 11211)来标识。我们可以在其他程序里安全地引用(refer to)“运行在 10.0.0.5:80 的那个 http 服务器”,或者“10.0.0.6:11211...

weixin_39518678的博客 197

构建一个分布式操作系统的简单方案—答陈硕的“分布式系统中的进程标识”一文...

对分布式系统中的进程标识”一文的疑问 刚才看到陈硕先生的一篇blog:“分布式系统中的进程标识”,地址:http://www.cnblogs.com/Solstice/archive/2011/03/29/1998412.html 我不同意该文的观点,因此在这里抛砖引玉,提出一个构建一个分布式系统的简单方案。 ...

weixin_30699955的博客 85

c语言分布式系统有哪些,C语言分布式系统中的进程标识!

该楼层疑似违规已被系统折叠隐藏此楼查看此楼如果进程本身是无状态的,或者重启了也没有关系,那么用 ip:port 来标识一个“服务”是没问题的,比如常见的 httpd 和 memcached 都可以用它们的惯用 port (80 和 11211)来标识。我们可以在其他程序里安全地引用(refer to)“运行在 10.0.0.5:80 的那个 http 服务器”,或者“10.0.0.6:11211...

weixin_42282482的博客 257

[zz]构建一个分布式操作系统的简单方案—答陈硕的“分布式系统中的进程标识”一文...

对分布式系统中的进程标识”一文的疑问 刚才看到陈硕先生的一篇blog:“分布式系统中的进程标识”,地址:http://www.cnblogs.com/Solstice/archive/2011/03/29/1998412.html 我不同意该文的观点,因此在这里抛砖引玉,提出一个构建一个分布式系统的简单方案。 文中说:“正确做法:以四元组ip:po...

weixin_30608131的博客 74

muduo网络库—分布式系统知识精要

每个数据块都分割到分布式许多服务器上,因此每个服务器都存储了一个较小的数据块。首先,由于高带宽和低时延,在需要数据的客户端向存储数据的服务器发送数据请求后,这些服务器几乎同时向客户端发送数据,导致大量数据流同时涌向网络。又由于交换机缓冲区空间有限,这种流量很容易就会将其溢出,接着发生丢包,TCP 通过超时重传进行恢复。超时的时间通常至少要几百毫秒。需要超时重传的服务器会进入超时等待。由于同步的传输模式,多个服务器可能会同时进入这种等待。

baidu_41553551的博客 1529

MongoDB的ObjectId生成原理

在分布式系统中,分布式 ID 有很多特殊的要求,其中两个要求 各个 ID 必须全局唯一,且 ID 能够趋势递增。 mongo插入一条记录 db.xttblog.insert({"name":"张三","age":88,"url":"www.xttblog.com"}) 插入成功: Inserted 1 record(s) in 64ms 查询 db.getCollection('xttblog').find({}) 查询结果多出了一个_id,它是 ObjectId 类型。它是一个 24.

我的博客 1181
上一篇: C++ 工程实践(5):避免使用虚函数作为库的接口
下一篇: 构建易于维护的分布式程序
陈硕
博客等级 码龄26年 1万+粉丝 144原创
评论 47
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值