【分布式】Zookeeper在大型分布式系统中的应用

一、前言

  上一篇博文讲解了Zookeeper的典型应用场景,在大数据时代,各种分布式系统层出不穷,其中,有很多系统都直接或间接使用了Zookeeper,用来解决诸如配置管理、分布式通知/协调、集群管理和Master选举等一系列分布式问题。

二、 Hadoop

  Hadoop的核心是HDFS(Hadoop Distributed File System)和MapReduce,分别提供了对海量数据的存储和计算能力,后来,Hadoop又引入了全新MapReduce框架YARN(Yet Another Resource Negotiator)。在Hadoop中Zookeeper主要用于实现HA(High Availability),这部分逻辑主要集中在Hadoop Common的HA模块中,HDFS的NameNode与YARN的ResourceManager都是基于此HA模块来实现自己的HA功能,YARN又使用了Zookeeper来存储应用的运行状态。

  YARN

  YARN是一种新的 Hadoop 资源管理器,它是一个通用资源管理系统,可为上层应用提供统一的资源管理和调度,它的引入为集群在利用率、资源统一管理和数据共享等方面带来了巨大好处。其可以支持MapReduce模型,同时也支持Tez、Spark、Storm、Impala、Open MPI等。

  YARN主要由ResourceManager(RM)、NodeManager(NM)、ApplicationManager(AM)、Container四部分构成。其中,ResourceManager为全局资源管理器,负责整个系统的资源管理和分配。由YARN体系架构可以看到ResourceManager的单点问题,ResourceManager的工作状况直接决定了整个YARN架构是否可以正常运转。

  ResourceManager HA

  为了解决ResourceManager的单点问题,YARN设计了一套Active/Standby模式的ResourceManager HA架构。

  由上图可知,在运行期间,会有多个ResourceManager并存,并且其中只有一个ResourceManager处于Active状态,另外一些(允许一个或者多个)则处于Standby状态,当Active节点无法正常工作时,其余处于Standby状态的节点则会通过竞争选举产生新的Active节点。

  主备切换

  ResourceManager使用基于Zookeeper实现的ActiveStandbyElector组件来确定ResourceManager的状态。具体步骤如下

  1. 创建锁节点。在Zookeeper上会有一个类似于/yarn-leader-election/pseudo-yarn-rm-cluster的锁节点,所有的ResourceManager在启动时,都会去竞争写一个Lock子节点(/yarn-leader-election/pseudo-yarn-rm-cluster/ActiveStandbyElectorLock),子节点类型为临时节点,利用Zookeeper的特性,创建成功的那个ResourceManager切换为Active状态,其余的为Standby状态。

  2. 注册Watcher监听。所有Standby状态的ResourceManager都会向/yarn-leader-election/pseudo-yarn-rm-cluster/ActiveStandbyElectorLock节点注册一个节点变更监听,利用临时节点的特性,能够快速感知到Active状态的ResourceManager的运行情况。

  3. 主备切换。当Active的ResourceManager无法正常工作时,其创建的Lock节点也会被删除,此时,其余各个Standby的ResourceManager都会收到通知,然后重复步骤1。

  隔离(Fencing)

  在分布式环境中,经常会出现诸如单机假死(机器由于网络闪断或是其自身由于负载过高,常见的有GC占用时间过长或CPU负载过高,而无法正常地对外进行及时响应)情况。假设RM集群由RM1和RM2两台机器构成,某一时刻,RM1发生了假死,此时,Zookeeper认为RM1挂了,然后进行主备切换,RM2会成为Active状态,但是在随后,RM1恢复了正常,其依然认为自己还处于Active状态,这就是分布式脑裂现象,即存在多个处于Active状态的RM工作,可以使用隔离来解决此类问题。

  YARN引入了Fencing机制,借助Zookeeper的数据节点的ACL权限控制机制来实现不同RM之间的隔离。在上述主备切换时,多个RM之间通过竞争创建锁节点来实现主备状态的确定,此时,只需要在创建节点时携带Zookeeper的ACL信息,目的是为了独占该节点,以防止其他RM对该节点进行更新。

  还是上述案例,若RM1出现假死,Zookeeper会移除其创建的节点,此时RM2会创建相应的锁节点并切换至Active状态,RM1恢复之后,会试图去更新Zookeeper相关数据,但是此时其没有权限更新Zookeeper的相关节点数据,因为节点不是由其创建的,于是就自动切换至Standby状态,这样就避免了脑裂现象的出现。

  ResourceManager状态存储

  在ResourceManager中,RMStateStore可以存储一些RM的内部状态信息,包括Application以及Attempts信息、Delegation Token及Version Information等,值得注意的是,RMStateStore的绝大多数状态信息都是不需要持久化存储的(如资源使用情况),因为其很容易从上下文信息中重构,,在存储方案设计中,提供了三种可能的实现。

  1. 基于内存实现,一般用于日常开发测试。

  2. 基于文件系统实现,如HDFS。

  3. 基于Zookeeper实现。

  由于存储的信息不是特别大,Hadoop官方建议基于Zookeeper来实现状态信息的存储,在Zookeeper中,ResourceManager的状态信息都被存储在/rmstore这个根节点下,其数据结构如下。

  在RMAppRoot节点下存储的是与各个Application相关的信息,RMDTSecretManagerRoot存储的是与安全相关的Token信息。每个Active状态的ResourceManager在初始化节点都会从Zookeeper上读取到这些信息,并根据这些状态信息继续后续的处理。

三、HBase

  HBase(Hadoop Database)是一个基于Hadoop的文件系统设计的面向海量数据的高可靠、高性能、面向列、可伸缩的分布式存储系统,其针对数据写入具有强一致性,索引列也实现了强一致性,其采用了Zookeeper服务来完成对整个系统的分布式协调工作,其架构如下

  HBase架构中,Zookeeper是串联起HBase集群与Client的关键所在,Zookeeper在HBase中的系统容错、RootRegion管理、Region状态管理、分布式SplitLog任务管理、Replication管理都扮演重要角色

  系统容错

  在HBase启动时,每个RegionServer服务器都会到Zookeeper的/hbase/rs节点下创建一个信息节点,例如/hbase/rs/[Hostname],同时,HMaster会对这个节点进行监听,当某个RegionServer挂掉时,Zookeeper会因为在一段时间内无法接收其心跳信息(Session失效),而删除掉该RegionServer服务器对应的节点,与此同时,HMaster则会接收到Zookeeper的NodeDelete通知,从而感知到某个节点断开,并立即开始容错工作,HMaster会将该RegionServer所处理的数据分片(Region)重新路由到其他节点上,并记录到Meta信息中供客户端查询。

  RootRegion管理

  数据存储的位置信息是记录在元数据分片上的,即在RootRegion上,每次客户端发起新的请求,就会查询RootRegion来确定数据的位置,而RootRegion自身的位置则记录在Zookeeper上(默认情况下在/hbase/root-region-server节点中)。当RootRegion发生变化时,如Region手工移动、Balance或者是RootRegion所在服务器发生了故障,就能通过Zookeeper来感知到这一变化并做出一系列相应的容灾措施,从而保障客户端总能够拿到正确的RootRegion信息。

  Region状态管理

  Region是HBase中数据的物理切片,每个Region记录了全局数据的一小部分,并且不同的Region之间的数据是相互不重复的。但对于一个分布式系统来说,Region是会发生变更的,原因可能是系统故障、负载均衡、配置修改、Region分裂合并等,一旦Region发生变动,它必然经历离线和重新在线的过程。在离线期间,数据是不能被访问的,并且Region的状态变化必须让全局知晓,否则可能会出现某些事务性的异常,而对于HBase集群而言,Region的数量可能会多达10万级别,因此这样规模的Region状态管理只有依靠Zookeeper才能做到。

  分布式SplitLog任务管理

  当某台RegionServer服务器挂掉后,由于总有一部分新写入的数据还没有持久化到HFile中(在内存中),因此在迁移该RegionServer的服务时,应该从HLog中恢复这部分还在内存中的数据,此时HMaster需要遍历该RegionServer服务器的HLog(SplitLog),并按照Region切分成小块移动到新的地址,并进行数据的Replay。由于单个RegionServer的日志量相对庞大(可能存在上千个Region,上GB的日志),而用户往往希望系统能够快速完成日志的恢复工作,因此,需要将处理HLog的任务分配给多台RegionServer服务器共同处理,而这又需要一个持久化组件来辅助HMaster完成任务的分配,当前做法如下,HMaster会在Zookeeper上创建一个splitlog节点(默认为/hbase/splitlog节点),将"哪个RegionServer处理哪个Region"的信息以列表的形式存放在该节点上,然后由各个RegionServer服务器自行到该节点上去领取任务并在任务执行成功或失败后再更新该节点的信息以通知HMaster继续后续步骤,Zookeeper起到了相互通知和信息持久化的角色。

  Replication管理

  Replication是实现HBase中主备集群间的实时同步的重要模块,与传统关系型数据库不同的是,HBase的Replication是多对多的,且每个节点随时都有可能挂掉,因此其会复杂得多。HBase也借助了Zookeeper来完成Replication功能,做法是在Zookeeper上记录一个replication节点(默认是/hbase/replication节点),然后把不同的RegionServer服务器对应的HLog文件名称记录到相应的节点上,HMaster集群会将新增的数据推送给Slave集群,并同时将推送信息记录到Zookeeper上(称为断点记录),然后重复上述步骤,当服务器挂掉时,由于Zookeeper上已经保存了断点信息,因此只要有HMaster能够根据这些信息来协同用来推送HLog数据的主节点服务器就可以进行继续复制操作。

四、Kafka

  kafka是一个吞吐量极高的分布式消息系统,其整体设计是典型的发布与订阅系统模式,在Kafka集群中,没有中心主节点概念,所有服务器都是对等的,因此,可以在不做任何配置更改的情况下实现服务器的添加与删除,同样,消息的生产者和消费者也能够随意重启和机器的上下线。

  生产者(Producer):消息产生的源头,负责生成消息并发送到Kafka服务器。

  消费者(Consumer):消息的使用方,负责消费Kafka服务器上的消息。

  主题(Topic):由用户定义并配置在Kafka服务端,用于建立生产者和消费者之间的订阅关系,生产者发送消息到指定Topic下,消费者从这个Topic中消费消息。

  消息分区(Partition):一个Topic下会分为多个分区,如"kafka-test"这个Topic可以分为10个分区,分别由两台服务器提供,那么通常可以配置让每台服务器提供5个分区,假设服务器ID为0和1,那么分区为0-0、0-1、0-2、0-3、0-4和1-0、 1-1、1-2、1-3、1-4。消息分区机制和分区的数量与消费者的负载均衡机制有很大的关系。

  服务器(Broker):用于存储信息,在消息中间件中通常被称为Broker。

  消费者分组(Group):归组同类消费者,多个消费者可以共同消费一个Topic下的消息,每个消费者消费其中的部分消息,这些消费者组成了消费者分组,拥有同一个分组名称,通常也被称为消费者集群。

  偏移量(Offset):消息存储在Kafka的Broker上,消费者拉取消息数据的过程中需要知道消息在文件中的偏移量。

  Broker注册

  Broker是分布式部署并且相互之间相互独立,但是需要有一个注册系统能够将整个集群中的Broker管理起来,此时就使用到了Zookeeper。在Zookeeper上会有一个专门用来进行Broker服务器列表记录的节点/brokers/ids。每个Broker在启动时,都会到Zookeeper上进行注册,即到/brokers/ids下创建属于自己的节点,如/brokers/ids/[0...N]。Kafka使用了全局唯一的数字来指代每个Broker服务器,不同的Broker必须使用不同的Broker ID进行注册,创建完节点后,每个Broker就会将自己的IP地址和端口信息记录到该节点中去。其中,Broker创建的节点类型是临时节点,一旦Broker宕机,则对应的临时节点也会被自动删除。

  Topic注册

  在Kafka中,同一个Topic的消息会被分成多个分区并将其分布在多个Broker上,这些分区信息及与Broker的对应关系也都是由Zookeeper在维护,由专门的节点来记录,如/borkers/topics。Kafka中每个Topic都会以/brokers/topics/[topic]的形式被记录,如/brokers/topics/login和/brokers/topics/search等。Broker服务器启动后,会到对应Topic节点(/brokers/topics)上注册自己的Broker ID并写入针对该Topic的分区总数,如/brokers/topics/login/3->2,这个节点表示Broker ID为3的一个Broker服务器,对于"login"这个Topic的消息,提供了2个分区进行消息存储,同样,这个分区节点也是临时节点。

  生产者负载均衡

  由于同一个Topic消息会被分区并将其分布在多个Broker上,因此,生产者需要将消息合理地发送到这些分布式的Broker上,那么如何实现生产者的负载均衡,Kafka支持传统的四层负载均衡,也支持Zookeeper方式实现负载均衡。

  ① 四层负载均衡,根据生产者的IP地址和端口来为其确定一个相关联的Broker。通常,一个生产者只会对应单个Broker,然后该生产者产生的消息都发往该Broker。这种方式逻辑简单,每个生产者不需要同其他系统建立额外的TCP连接,只需要和Broker维护单个TCP连接即可。但是,其无法做到真正的负载均衡,因为实际系统中的每个生产者产生的消息量及每个Broker的消息存储量都是不一样的,如果有些生产者产生的消息远多于其他生产者的话,那么会导致不同的Broker接收到的消息总数差异巨大,同时,生产者也无法实时感知到Broker的新增和删除。

  ② 使用Zookeeper进行负载均衡,由于每个Broker启动时,都会完成Broker注册过程,生产者会通过该节点的变化来动态地感知到Broker服务器列表的变更,这样就可以实现动态的负载均衡机制。

  消费者负载均衡

  与生产者类似,Kafka中的消费者同样需要进行负载均衡来实现多个消费者合理地从对应的Broker服务器上接收消息,每个消费者分组包含若干消费者,每条消息都只会发送给分组中的一个消费者,不同的消费者分组消费自己特定的Topic下面的消息,互不干扰。

  消费分区与消费者的关系

  对于每个消费者分组,Kafka都会为其分配一个全局唯一的Group ID,同一个消费者分组内部的所有消费者共享该ID。同时,Kafka为每个消费者分配一个Consumer ID,通常采用"Hostname:UUID"形式表示。在Kafka中,规定了每个消息分区有且只能同时有一个消费者进行消费,因此,需要在Zookeeper上记录消息分区与消费者之间的关系,每个消费者一旦确定了对一个消息分区的消费权力,需要将其Consumer ID 写入到对应消息分区的临时节点上,例如/consumers/[group_id]/owners/[topic]/[broker_id-partition_id],其中,[broker_id-partition_id]就是一个消息分区的标识,节点内容就是该消费分区上消息消费者的Consumer ID。

  消息消费进度Offset记录

  在消费者对指定消息分区进行消息消费的过程中,需要定时地将分区消息的消费进度Offset记录到Zookeeper上,以便在该消费者进行重启或者其他消费者重新接管该消息分区的消息消费后,能够从之前的进度开始继续进行消息消费。Offset在Zookeeper中由一个专门节点进行记录,其节点路径为/consumers/[group_id]/offsets/[topic]/[broker_id-partition_id],节点内容就是Offset的值。

  消费者注册

  消费者服务器在初始化启动时加入消费者分组的步骤如下

  ① 注册到消费者分组。每个消费者服务器启动时,都会到Zookeeper的指定节点下创建一个属于自己的消费者节点,例如/consumers/[group_id]/ids/[consumer_id],完成节点创建后,消费者就会将自己订阅的Topic信息写入该临时节点。

  ② 对消费者分组中的消费者的变化注册监听。每个消费者都需要关注所属消费者分组中其他消费者服务器的变化情况,即对/consumers/[group_id]/ids节点注册子节点变化的Watcher监听,一旦发现消费者新增或减少,就触发消费者的负载均衡。

  ③ 对Broker服务器变化注册监听。消费者需要对/broker/ids/[0-N]中的节点进行监听,如果发现Broker服务器列表发生变化,那么就根据具体情况来决定是否需要进行消费者负载均衡。

  ④ 进行消费者负载均衡。为了让同一个Topic下不同分区的消息尽量均衡地被多个消费者消费而进行消费者与消息分区分配的过程,通常,对于一个消费者分组,如果组内的消费者服务器发生变更或Broker服务器发生变更,会发出消费者负载均衡。

  负载均衡

  Kafka借助Zookeeper上记录的Broker和消费者信息,采用消费者均衡算法进行负载均衡,其具体步骤如下。假设一个消息分组的每个消费者记为C1,C2,Ci,...,Cn。那么对于消费者Ci,其对应的消息分区分配策略如下:

  1. 设置Pr为指定Topic所有的消息分区。

  2. 设置Cg为统一消费者分组中的所有消费者。

  3. 对Pr进行排序,使分布在同一个Broker服务器上的分区尽量靠在一起。

  4. 对Cg进行排序。

  5. 设置i为Ci在Cg中的位置索引,同时设置N = size (Pr) / size (Cg)。

  6. 将编号为i * N ~ (i + 1) * N - 1的消息分区分配给Ci。

  7. 重新更新Zookeeper上消息分区与消费者Ci的关系。

五、总结

  本篇博客讲解了Zookeeper在大型分布式系统中的应用,也体现了Zookeeper作为一款分布式协调器的优秀特点,至于Zookeeper在各个系统的详细应用,读者可以自行查阅资料,也谢谢各位园友的观看~ 

转载于:https://www.cnblogs.com/leesf456/p/6063694.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/572996.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Egret资源管理解决方案

关于egret开发H5页游,资源管理和加载的一点看法。 一 多json文件管理 二 资源归类和命名 三 exml文件编写规范 四 资源预加载、分步加载、偷载 五 资源文件group分组 六 ResUtils,多json文件管理类 七 ResUtils,资源组加载管理类 八 开发中遇…

java 等待唤醒机制,Java线程等待唤醒机制

记录面试过程中被问到的几个需要手写代码的小案例1.请手写出线程的等待唤醒机制案例中两个线程:SyncSetThread设置学生信息,SyncGetThread用来获取学生信息,在Student实体中提供一个标记属性flag,记录当前是否有数据。等待唤醒机制…

Xshell实现Windows上传文件到Linux主机

经常有这样的需求,我们在Windows下载的软件包,如何上传到远程Linux主机上?还有如何从Linux主机下载软件包到Windows下;之前我的做法现在看来好笨好繁琐,不过也达到了目的,笨人有本方法嘛; 我是怎…

织梦自适应php源码,DEDE织梦PHP源码响应式建筑设计类网站织梦模板(自适应手机端)...

模板名称:响应式建筑设计类网站织梦模板(自适应移动端) 利于SEO优化模板详情:织梦最新内核开发的模板,该模板属于企业通用、HTML5响应式、建筑设计类企业使用,一款适用性很强的模板,基本可以适合各行业的企业网站&…

mac本用WTG(Windows To Go)安装Win10到移动硬盘

准备工作: 一个空的 USB 3.0 移动硬盘(在安装 WTG 时候会将这个硬盘清空重新并分区,注意备份好数据。USB 3.0 的优盘是不行的,即使安装成功,系统的运行速度会奇慢) 原版Windows 10 安装镜像(建议…

js初步简单的编程代码

简单图片切换编码demo图片地址自行替换 简单图片切换编码<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns"http://www.w3.org/1999/xhtml" …

安卓文本编辑器php cpp,开源的Android富文本编辑器

RichEditor基于原生EditTextspan实现的Android富文本编辑器github地址&#xff1a;https://github.com/yuruiyin/RichEditor组件描述该组件是基于原生EditTextspan的方式实现的&#xff0c;旨在提供一个功能齐全且使用方便的Android富文本编辑器。主要支持了加粗斜体等行内样式…

python gif 透明,Python3+试点批量处理简单的GIF到PNG并透明地去除背景色,python3Pillow,gif,转成,png,透明化,去掉...

1. 安装Pillow, 只用这个应该也可以&#xff0c;2. 安装 cImage下载后解压&#xff0c;拷贝image.py到你python安装目录的 Lib\site-packages 中。from PIL import Imageimport osimport imagedef get_imlist(path):"""返回目录中所有gif图像的文件名列表图像的…

matlab求半衰期,如何使用GLD和GDX价差来估计均值回归的半衰期

计算均值回归时间序列的半衰期我们可以通过例中GLD和GDX的均值回归差价来计算均值回归半衰期。MATLAB代码可以从epchan. com/book/example? _ 5. m获得。(这个程序的第一部分与example7 2. m.相同。)%在此播入example7_2. m%Insert example7 2. m in the beginning hereprevzb…

框架错误汇总

1.struts标签&#xff0c;在body中输入代码发现值栈不存在&#xff0c; 即<s:debug></s:debug>没有起作用 1 <body>2 3 4 测试url标签<br>5 <s:url value"index.jsp" var"surl"></s:url><br>6 <s:url value&…

初次进入oracle数据库,Oracle数据库的初次使用

oracle数据库的初次使用&#xff1a;oracle自带了用户 system /system管理员用户 scott/tiger用户初次使用&#xff1a;创建表空间(此处为使用默认的用户scott/tiger)在控制台&#xff1a;1.使用system/system用户登录语句&#xff1a;sqlplus system/system2.赋予用户权限&…

oracle+循环插入sql,SQL server,Oracle循环插入百万数据

SQL server&#xff0c;Oracle循环插入百万数据SQL server&#xff0c;Oracle循环插入百万数据压测时常需要往数据库插入大量数据&#xff0c;下面是我往两个数据库插入数据时用的脚本declare maxSum int,lid nvarchar(64), -- lid为表idcid int,userid nvarchar(64),oper_time…

jquery 通过submit()方法 提交表单示例

jquery 通过submit()方法 提交表单示例&#xff1a; 本示例&#xff1a;以用户注册作为例子。使用jquery中的submit()方法实现表单提交。 注&#xff1a;本示例仅提供了对表单的验证&#xff0c;本例只用选用了三个字段作为测试。 用户点击提交按钮时&#xff0c;触发点击事件&…

php background-image,css background-image属性怎么用

css background-image属性为元素设置背景图像&#xff0c;语法为&#xff1a;background-image:url(图片路径)。设置的背景图像会占据元素的全部尺寸&#xff0c;包括内边距和边框&#xff0c;但不包括外边距。css background-image属性怎么用&#xff1f;作用&#xff1a;为元…

webstorm

问题描述&#xff1a;webstorm打开文件夹&#xff0c;文件夹内的文件不能全部显示&#xff0c;如图 原因&#xff1a;配置文件xml出错 解决方法&#xff1a;删除文件夹内的idea文件&#xff0c;再用webstrom重新打开就行╮(╯▽╰)╭转载于:https://www.cnblogs.com/chenluomen…

linux文件句柄数满,linux文件句柄数超出系统限制怎么办?

1、问题阐述&#xff1a;too many open files&#xff1a;顾名思义即打开过多文件数。不过这里的files不单是文件的意思&#xff0c;也包括打开的通讯链接(比如socket)&#xff0c;正在监听的端口等等&#xff0c;所以有时候也可以叫做句柄(handle)&#xff0c;这个错误通常也可…

linux 内核编译不能打字,linux系统升级后,手动编译的kernel无法启动问题

linux系统升级后&#xff0c;手动编译的kernel无法启动问题linux系统升级后&#xff0c;手动编译的kernel无法启动问题做开发相关&#xff0c;需要编译3.18的kernel&#xff0c;x86_64的&#xff0c;但是我的deepin升级v20之后&#xff0c;编译的kernel就无法启动了&#xff0c…

arcgis api 3.x for js 入门开发系列六地图分屏对比(附源码下载)

前言 关于本篇功能实现用到的 api 涉及类看不懂的&#xff0c;请参照 esri 官网的 arcgis api 3.x for js&#xff1a;esri 官网 api&#xff0c;里面详细的介绍 arcgis api 3.x 各个类的介绍&#xff0c;还有就是在线例子&#xff1a;esri 官网在线例子&#xff0c;这个也是学…

SVN版本管理trunk及branch相关merge操作

先说说什么是branch。按照Subversion的说法&#xff0c;一个branch是某个development line&#xff08;通常是主线也即trunk&#xff09;的一个拷贝&#xff0c;见下图&#xff1a; branch存在的意义在于&#xff0c;在不干扰trunk的情况下&#xff0c;和trunk并行开发&#xf…

线程之间通信 等待(wait)和通知(notify)

线程通信概念&#xff1a; 线程是操作系统中独立的个体&#xff0c;但这些个体如果不经过特殊的处理就不能成为一个整体&#xff0c;线程之间的通信就成为整体的必用方式之一。当线程存在通信指挥&#xff0c;系统间的交互性会更强大&#xff0c;在提高CPU利用率的同时还会对线…