专栏名称: 刘超的通俗云计算
刘超,网易云解决方案首席架构师,代码级略懂OpenStack、Hadoop、Docker、Lucene、Mesos等开源软件,曾出版《Lucene应用开发揭秘》,个人博客可搜索popsuper1982。
目录
相关文章推荐
51好读  ›  专栏  ›  刘超的通俗云计算

只有程序员才能读懂的三国演义(二)

刘超的通俗云计算  · 公众号  · 架构  · 2019-10-03 14:17

正文

这是通过三国演义串起操作系统的原理,之前写过五篇小马创业篇,这次改编为三国演义篇。


用一个创业故事串起操作系统原理(一)

用一个创业故事串起操作系统原理(二)

用一个创业故事串起操作系统原理(三)

用一个创业故事串起操作系统原理(四)

用一个创业故事串起操作系统原理(五)


上一篇,我们讲到,刘备三顾茅庐请来诸葛亮,从而战略,战术,政务全方位体系都建立了。


第八回: 诸葛阵法复合多变,进程同步方法多样


自从诸葛亮当军师以来,排兵布阵便开始使用复合式战法,往往是多个将军带着多只部队配合作战。


诸葛亮排兵布阵风格一,可见于赤壁大战后对于华容道的安排。


孔明便与玄德、刘琦升帐坐定,谓赵云曰:“子龙可带三千军马,渡江径取乌林小路,拣树木芦苇密处埋伏。今夜四更已后,曹操必然从那条路奔走。等他军马过,就半中间放起火来。虽然不杀他尽绝,也杀一半。”云曰:“乌林有两条路:一条通南郡,一条取荆州。不知向那条路来?”孔明曰:“南郡势迫,曹操不敢往;必来荆州,然后大军投许昌而去。”云领计去了。又唤张飞曰:“翼德可领三千兵渡江,截断彝陵这条路,去葫芦谷口埋伏。曹操不敢走南彝陵,必望北彝陵去。来日雨过,必然来埋锅造饭。只看烟起,便就山边放起火来。虽然不捉得曹操,翼德这场功料也不小。”飞领计去了。


对于关羽,孔明曰:“昔日曹操待足下甚厚,足下当有以报之。今日操兵败,必走华容道;若令足下去时,必然放他过去。因此不敢教去。”云长曰:“愿依军法!”云长曰:“若曹操不从那条路上来,如何?”孔明曰:“我亦与你军令状。云长大喜。孔明曰:“云长可于华容小路高山之处,堆积柴草,放起一把火烟,引曹操来。”云长曰:“曹操望见烟,知有埋伏,如何肯来?”孔明笑曰:“岂不闻兵法虚虚实实之论?操虽能用兵,只此可以瞒过他也。他见烟起,将谓虚张声势,必然投这条路来。将军休得容情。”云长领了将令,引关平、周仓并五百校刀手,投华容道埋伏去了。




对于这次的排兵布阵,诸葛亮采用的是串联式,也即在敌人的必经之路上,依次埋伏将领,每个将领处理一批敌人,剩下的交给下一个环节。


在Linux里面,有一种类似的进程间通信机制,就是管道。


所谓的管道,就是在两个进程之间建立一条单向的通道,其实是一段缓存,它会将前一个命令的输出,作为后一个命令的输入。




管道的方式比较简单,缺点是必须事先全部安排好,如果有变动比较难灵活处理,需要依赖神机妙算,比如曹操如果没有按计划走华容道的话,也来不及通知关羽了。


军队之间通信的第二种方式就是靠人,也即靠信使。就是我们常听到的,报!!!大事不好!!!再探!!!



例如在夷陵之战的时候,信使将刘备联营七百里的图本传给诸葛亮看,可是已经晚了。所以这种方式的实时性也不好。


在Linux里面,和管道将信息一股脑儿地从一个进程,倒给另一个进程不同,消息队列有点儿像邮件,发送数据时,会分成一个一个独立的数据单元,也就是消息体,每个消息体都是固定大小的存储块,在字节流上不连续。


在Linux里面还有非常实时的一种模式,就是共享内存+信号量。


进程间通信的共享内存模型的原理是这样的。前面咱们讲内存管理的时候,知道每个进程都有自己独立的虚拟内存空间,不同的进程的虚拟内存空间映射到不同的物理内存中去。这个进程访问A地址和另一个进程访问A地址,其实访问的是不同的物理内存地址,对于数据的增删查改互不影响。

但是,咱们是不是可以变通一下,拿出一块虚拟地址空间来,映射到相同的物理内存中。这样这个进程写入的东西,另外一个进程马上就能看到了,都不需要拷贝来拷贝去,传来传去。

共享内存也有问题呀。如果两个进程使用同一个共享内存,大家都往里面写东西,很有可能就冲突了。例如两个进程都同时写一个地址,那先写的那个进程会发现内容被别人覆盖了。

当然,和共享内存配合的,有另一种保护机制,使得同一个共享的资源,同时只能被一个进程访问叫信号量。

信号量其实是一个计数器,主要用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。

我们可以将信号量初始化为一个数值,来代表某种资源的总体数量。对于信号量来讲,会定义两种原子操作,一个是P操作,我们称为申请资源操作。这个操作会申请将信号量的数值减去N,表示这些数量被他申请使用了,其他人不能用了。另一个是V操作,我们称为归还资源操作,这个操作会申请将信号量加上M,表示这些数量已经还给信号量了,其他人可以使用了。

例如,你有100元钱,就可以将信号量设置为100。其中A向你借80元,就会调用P操作,申请减去80。如果同时B向你借50元,但是B的P操作比A晚,那就没有办法,只好等待A归还钱的时候,B的P操作才能成功。之后,A调用V操作,申请加上30元,也就是还给你30元,这个时候信号量有50元了,这时候B的P操作才能成功,才能借走这50元。

所谓原子操作(Atomic Operation),就是任何一块钱,都只能通过P操作借给一个人,不能同时借给两个人。也就是说,当A的P操作(借80)和B的P操作(借50),几乎同时到达的时候,不能因为大家都看到账户里有100就都成功,必须分个先来后到。



共享内存+信号量这种模式类似八门金锁阵,好处是配合紧密,不是和一个人战斗,而是和所有人。但是信号量的控制非常重要,要有个人站在最高处控制,在极端场景下,信号量设计不好容易死锁。比如赵云破阵, 如从东南角上生门击人,往正西景门而出,其阵必乱。


上面的这些机制,基本常规状态下的工作模式,如果发生了异常怎么办?例如出现线上系统故障,这个时候,什么流程都来不及了,不可能发邮件,也来不及开会,所有的架构师、开发、运维都要被通知紧急出动。所以,7乘24小时不间断执行的系统都需要有告警系统,一旦出事情,就要通知到人,哪怕是半夜,也要电话叫起来,处理故障。是不是应该还有一种异常情况下的工作模式。


当然应该有,我们可以建立像操作系统里面的信号机制。信号没有特别复杂的数据结构,就是用一个代号一样的数字。Linux提供了几十种信号,分别代表不同的意义。信号之间依靠它们的值来区分。这就像咱们看警匪片,对于紧急的行动,都是说,‘1号作战任务’开始执行,警察就开始行动了。情况紧急,不能啰里啰嗦了。

信号可以在任何时候发送给某一进程,进程需要为这个信号配置信号处理函数。当某个信号发生的时候,就默认执行这个函数就可以了。这就相当于咱们运维一个系统应急手册,当遇到什么情况,做什么事情,都事先准备好,出了事情照着做就可以了。



这种信号模式,诸葛亮经常使用,例如火烧博望坡的时候,诸葛亮是这样布置的。 孔明令曰:“博望之左有山,名曰豫山;右有林,名曰安林:可以埋伏军马。云长可引一千军往豫山埋伏,等彼军至,放过休敌;其辎重粮草,必在后面,但看南面火起,可纵兵出击,就焚其粮草。翼德可引一千军去安林背后山谷中埋伏,只看南面火起,便可出,向博望城旧屯粮草处纵火烧之。关平、刘封可引五百军,预备引火之物,于博望坡后两边等候,至初更兵到,便可放火矣。”又命:“于樊城取回赵云,令为前部,不要赢,只要输,主公自引一军为后援。各须依计而行,勿使有失。”



第九回: 孙刘联盟赤壁破曹,网络通信多机合作


诸葛亮辅佐刘备打了几个胜仗,但是曹操实力太强,还是敌不过,最终要按照隆中对中计划的一样,和孙权联合攻抗曹操。


但是两个集团的合作能否成功呢?这依赖于双方的合作协议是如何谈的。


在Linux里面,服务器之间的协作要靠网络协议。


这其实就像机器与机器之间合作,一台机器将自己想要表达的内容,按照某种约定好的格式发送出去。当另外一台机器收到这些信息后,也能够按照约定好的格式解析出来,从而准确、可靠地获得发送方想要表达的内容。这种约定好的格式就是网络协议。

现在业内知名的有两种网络协议模型,一种是OSI的标准七层模型,一种是业界标准的TCP/IP模型。它们的对应关系如下图所示:



下面我们来解析一下网络协议。


我们先从第三层网络层开始,因为这一层有我们熟悉的IP地址,所以这一层我们也叫IP层。

连接到网络上的每一个设备都至少有一个IP地址,用于定位这个设备。无论是近在咫尺的、你旁边同学的电脑,还是远在天边的电商网站,都可以通过IP地址进行定位。因此,IP地址类似互联网上的邮寄地址,是有全局定位功能的。

就算你要访问美国的一个地址,也可以从你身边的网络出发,通过不断地打听道儿,经过多个网络,最终到达目的地址,和快递员送包裹的过程差不多。打听道儿的协议也在第三层,我们称为路由协议。将网络包从一个网络转发给另一个网络的设备,我们称为路由器。

总而言之,第三层干的事情,就是网络包从一个起始的IP地址,沿着路由协议指的道儿,经过多个网络,通过多次路由器转发,到达目标IP地址。


IP层是网络协议里面的核心层,承上启下。


对于刘备集团和孙权集团来讲,首先双方建立联系的,就是诸葛亮和鲁肃。这两个人都是双方中流砥柱的人才,也是制定战略的人才。就像两台机器要通信事先双方知道对方的IP地址一样,诸葛亮和鲁肃互相闻名已久。


鲁子敬愿亲到江夏,搬请诸葛亮共议破曹大计。孙权因刘备两次打败曹操,急于摸清曹军兵力,同意鲁肃去江夏探听虚实。诸葛亮于是决定只身入吴,要凭三寸不烂之舌,去说孙、曹两家互相吞并。



从第三层,我们往下看。第二层是数据链路层。有时候我们简称为二层或者MAC层。所谓MAC,就是每个网卡都有的唯一的硬件地址(不绝对唯一,相对大概率唯一即可,类比UUID)。这虽然也是一个地址,但是这个地址是没有全局定位功能的。

就像给你送外卖的小哥,不可能根据手机尾号找到你家,但是手机尾号有本地定位功能的,只不过这个定位主要靠“吼“。外卖小哥到了你的楼层就开始大喊:“尾号xxxx的,你外卖到了!“

MAC地址的定位功能局限在一个网络里面,也即同一个网络号下的IP地址之间,可以通过MAC进行定位和通信。从IP地址获取MAC地址要通过ARP协议,是通过在本地发送广播包,也就是“吼“,获得的MAC地址。

由于同一个网络内的机器数量有限,通过MAC地址的好处就是简单。匹配上MAC地址就接收,匹配不上就不接收,没有什么所谓路由协议这样复杂的协议。当然坏处就是,MAC地址的作用范围不能出本地网络,所以一旦跨网络通信,虽然IP地址保持不变,但是MAC地址每经过一个路由器就要换一次。

所以第二层干的事情,就是网络包在本地网络中的服务器之间定位及通信的机制。


我们再往下看第一层,物理层。这一层就是物理设备。例如,连着电脑的网线,我们能连上的WiFi。


鲁肃和诸葛亮各管各的属下,这不消说。到了东吴的地盘,诸葛亮也是一切听鲁肃安排,因为江东的地理,人物,政治,权力格局,也是只有鲁肃最清楚的。



到了东吴,诸葛亮也是遍访东吴人物,摸清各自主战主和,最终敲定关键要劝说的人物——周瑜。这就相当于ARP通过广播获取目标MAC了。


从第三层往上看,第四层是传输层,这里面有两个著名的协议,TCP和UDP。尤其是TCP,更是广泛使用,在IP层的代码逻辑中,仅仅负责数据从一个IP地址发送给另一个IP地址,丢包、乱序、重传、拥塞,这些IP层都不管。处理这些问题的代码逻辑写在了传输层的TCP协议里面。

我们常说,TCP是可靠传输协议,也是难为它了。因为从第一层到第三层都不可靠,网络包说丢就丢,是TCP这一层通过各种编号、重传等机制,让本来不可靠的网络对于更上层来讲,变得“看起来”可靠。哪有什么应用层的岁月静好,只不过是TCP层在负重前行。


对于东吴来讲,两个比鲁肃更加重要的两个人物,就是张昭和周瑜,这两个一个主战,主张和刘备达成协作,是周瑜,是TCP,也即定向建立连接,一个主和,主张投降曹操,是张昭,是UDP,也即和谁通信都行。



接下来,诸葛亮要和周瑜建立TCP连接了,也即三次握手,智激周瑜。



传输层再往上就是应用层,例如,咱们在浏览器里面输入的HTTP,Java服务端写的Servlet,都是这一层的。


孙权就是应用层了。



二层到四层都是在Linux内核里面处理的,应用层例如浏览器、Nginx、Tomcat都是用户态的。内核里面对于网络包的处理是不区分应用的。

从四层再往上,就需要区分网络包发给哪个应用。在传输层的TCP和UDP协议里面,都有端口的概念,不同的应用监听不同的端口。例如,服务端Nginx监听80、Tomcat监听8080;再如客户端浏览器监听一个随机端口,FTP客户端监听另外一个随机端口。

应用层和内核互通的机制,就是通过Socket系统调用。所以经常有人会问,Socket属于哪一层,其实它哪一层都不属于,它属于操作系统的概念,而非网络协议分层的概念。

操作系统对于网络协议的实现模式是这样的:二到四层的处理代码在内核里面,七层的处理代码让应用自己去做。两者需要跨内核态和用户态通信,就需要一个系统调用完成这个衔接,这就是Socket。

如果公司想要和其他公司沟通,我们将请求封装为HTTP协议,通过Socket发送到内核。内核的网络协议栈里面,在TCP层创建用于维护连接、序列号、重传、拥塞控制的数据结构,将HTTP包加上TCP头,发送给IP层,IP层加上IP头,发送给MAC层,MAC层加上MAC头,从硬件网卡发出去。

最终网络包会被转发到目标服务器,它发现MAC地址匹配,就将MAC头取下来,交给上一层。IP层发现IP地址匹配,将IP头取下来,交给上一层。TCP层会根据TCP头中的序列号等信息,发现它是一个正确的网络包,就会将网络包缓存起来,等待应用层的读取。

应用层通过Socket监听某个端口,因而读取的时候,内核会根据TCP头中的端口号,将网络包发给相应的应用。



第十回: 赤壁大胜又得荆益,设备众多统一管理


联合了孙权之后,果真赤壁大胜曹操,诸葛亮趁机占领了荆州,并以荆州为根基,进一步占领了益州,隆中对中的计划算是完成了一半。


还记得隆中对怎么说的嘛?


若跨有荆、益,保其岩阻,西和诸戎,南抚夷越,外结好孙权,内修政理;天下有变,则命一上将将荆州之军以向宛、洛,将军身率益州之众出于秦川,百姓孰敢不箪食壶浆,以迎将军者乎?诚如是,则霸业可成,汉室可兴矣。


现在“跨有荆、益,保其岩阻”问题解决了,接下来就是“西和诸戎,南抚夷越,外结好孙权,内修政理”,由于刘备算是从夹缝里面打出一片自己的天下,所以导致面临的环境比较复杂,周围各个方面的关系都要照顾好。


这有点像一家公司要做To B的生意,发现客户多种多样,众口难调,不同的地域不一样,不同的行业不一样。如果你不懂某个地方的规矩,根本卖不出去东西;如果你不懂某个具体行业的使用场景,也无法满足客户的需求。怎么办呢?一般公司采取的策略就是建立生态,设置很多代理商,让各个地区和各个行业的代理商帮你屏蔽这些差异化。你和代理商之间只要进行简单的标准产品交付就可以了。


诸葛亮自有一套自己的办法,从他七擒孟获就可以看出来。



作为Linux操作系统,需要管理的设备也是复杂多样的。我们能举出来的,例如键盘、鼠标、显示器、网卡、硬盘、打印机、CD/DVD等等,多种多样。这样,当然方便用户使用了,但是对于操作系统来讲,却是一件复杂的事情,因为这么多设备,形状、用法、功能都不一样,怎么才能统一管理起来呢?我们一层一层来看。







请到「今天看啥」查看全文