九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
超越POSIX:一個時代的終結(jié)?

Source: Pekka Enberg, Ashwin Rao, Jon Crowcroft, Sasu Tarkoma, Transcending POSIX: The End of an Era? September 8, 2022

在本文中,我們通過對Portable Operating System Interface(POSIX)抽象的歷史演變進行系統(tǒng)性的回顧,提供了一個全面的視圖。我們討論了推動這些演變的一些關(guān)鍵因素,并確定了在構(gòu)建現(xiàn)代應(yīng)用程序時使它們不可行的缺陷。

POSIX標(biāo)準(zhǔn)[1]定義了類Unix操作系統(tǒng)的接口。Unix是由程序員編寫給程序員的第一個操作系統(tǒng),而POSIX使開發(fā)人員能夠編寫可在不同的Unix操作系統(tǒng)變體和指令集架構(gòu)上運行的可移植應(yīng)用程序。Unix的主要應(yīng)用場景是對存儲(文件系統(tǒng))進行多路復(fù)用,并為用戶提供交互式環(huán)境(shell)[2],[3]。相比之下,許多當(dāng)代基于POSIX的系統(tǒng)的主要應(yīng)用場景是在數(shù)據(jù)中心的計算機上運行的服務(wù),這些服務(wù)具有數(shù)量級較低的延遲要求。由于登納德縮放定律(Dennard Scaling)在2004年前后結(jié)束,這些服務(wù)不能指望隨著CPU時鐘頻率的增加而逐年運行得更快,因為CPU時鐘頻率不再以Unix普及時期普遍存在的速度增長。此外,許多人認(rèn)為摩爾定律(Moore’s Law)正在放緩,因此軟件不再能指望通過硬件優(yōu)化的增加來變得更快,這是由于晶體管密度的增加所驅(qū)動的。隨著我們邁向后摩爾定律時代的計算,系統(tǒng)設(shè)計師開始利用快速可編程網(wǎng)卡(NICs)、專用硬件加速器和非易失性主存等設(shè)備來應(yīng)對應(yīng)用程序的嚴(yán)格延遲限制。

年份抽象示例接口版本
’69Filesystemopen, read, writeV0
’69ProcessesforkV0
’71ProcessesexecV1
’71Virtual memorybreak1V1
’73PipespipeV3
’73SignalssignalV4
’79SignalskillV7
’79Virtual memoryvfork23BSD
’83Networkingsocket, recv, send4.2BSD
’83I/O multiplexingselect4.2BSD
’83Virtual memorymmap34.2BSD
’83IPCmsgget, semget, shmgetSRV1
’87I/O multiplexingpollSRV3
’88Virtual memorymmapSunOS 4.0
’93Async. I/Oaio_submitPOSIX.1b
’95Threadspthread_createPOSIX.1c

POSIX抽象和接口的時間線

這些抽象是在1970年代至1990年代的不同Unix變體中引入的。文件系統(tǒng)和進程是早期接口中的基本部分,已經(jīng)存在于V0中。虛擬內(nèi)存在1970年代的3BSD中引入,并在1980年代的4.2BSD和SunOS 4.0中完成。網(wǎng)絡(luò)支持是在1980年代的4.2BSD中添加的。異步I/O和線程是在1990年代的POSIX標(biāo)準(zhǔn)中引入的。
  1. break系統(tǒng)調(diào)用后來被重命名為brk,并添加了另一個變體sbrk?,F(xiàn)在這兩個都已被棄用。
  2. 3BSD添加了對基于頁面的虛擬內(nèi)存的支持。它們添加了vfork系統(tǒng)調(diào)用,以避免實現(xiàn)fork的寫時復(fù)制[4]。
  3. 盡管mmap是在1983年設(shè)計的,但提議的設(shè)計在1986年完全實現(xiàn)了[5]。



POSIX的演進

POSIX的抽象(進程、文件系統(tǒng)、虛擬內(nèi)存、套接字和線程)是基于不同Unix變體在1970年代和1980年代的開發(fā)中的操作系統(tǒng)抽象,例如Research Unix、System V、BSD、SunOS等。

它們各自時代的應(yīng)用場景和硬件能力影響了這些抽象。例如,早期的Unix運行在PDP-11/20上,這是一臺16位計算機,具有單個CPU和最多248KB的主存儲器[6]。由于PDP-11/20缺乏內(nèi)存保護,Unix不支持虛擬內(nèi)存,這與當(dāng)時的其它操作系統(tǒng)(如Multics)不同。雖然后來的PDP-11變體,如PDP-11/70,具有內(nèi)存映射單元(MMU)[7],但直到1970年代末VAX架構(gòu)的出現(xiàn),Unix才添加了虛擬內(nèi)存[4],這成為當(dāng)時Unix的主要架構(gòu)。同樣,Unix直到1980年代初互聯(lián)網(wǎng)出現(xiàn)后才有了網(wǎng)絡(luò)抽象,當(dāng)時的4.2BSD引入了套接字抽象,用于抽象TCP/IP網(wǎng)絡(luò)協(xié)議進行遠程進程通信。類似地,Unix直到1990年代初多處理器機器變得更加主流時才有了線程抽象[8]。

文件系統(tǒng)

文件系統(tǒng)是一種訪問和組織存儲設(shè)備上字節(jié)數(shù)據(jù)的抽象。這種抽象及其I/O接口在很大程度上起源于Multics[9],并且被認(rèn)為是Unix中最重要的抽象[2],[10]。然而,與Unix僅支持同步I/O不同,Multics還支持異步I/O[11],[12],這個特性最終成為了POSIX的一部分。

文件系統(tǒng)抽象還包括文件、目錄、特殊文件[2]以及硬鏈接和符號鏈接[13]。文件系統(tǒng)中的文件是一系列字節(jié),操作系統(tǒng)不以任何方式解釋這些字節(jié)[2]。這使得操作系統(tǒng)可以將硬件設(shè)備表示為特殊文件,并且操作文件的接口已經(jīng)成為I/O設(shè)備的事實標(biāo)準(zhǔn)接口。

文件系統(tǒng)抽象可以方便地集成I/O設(shè)備。然而,它可能成為快速I/O設(shè)備的瓶頸[14],[15],[16],[17]。

進程

進程是系統(tǒng)中執(zhí)行應(yīng)用程序的抽象。具體而言,應(yīng)用程序被表示為一個映像,抽象了其執(zhí)行環(huán)境,其中包括程序代碼(文本)、處理器寄存器值和打開的文件[2]。此映像存儲在文件系統(tǒng)中,操作系統(tǒng)確保進程映像的執(zhí)行部分駐留在內(nèi)存中。進程抽象自早期的Unix開始存在[2],并且對于共享計算和I/O資源的時間共享至關(guān)重要。

這種抽象根植于多道程序設(shè)計,這是一種在1950年代中期開發(fā)的技術(shù),用于提高硬件利用率同時進行I/O操作[18]。早期運行在PDP-7上的Unix僅支持兩個進程,一個用于連接到機器的每個終端[19];后來設(shè)計為在PDP-11上運行的Unix可以將多個進程保留在內(nèi)存中。

進程是一種以處理器為中心的抽象,對于假設(shè)進程映像的執(zhí)行僅在CPU上完成的應(yīng)用程序非常有用。然而,圖形處理單元(GPU)、張量處理單元(TPU)和各種其它用于卸載計算的專用加速器等硬件設(shè)備的普及正在挑戰(zhàn)這種假設(shè)。

虛擬內(nèi)存

虛擬內(nèi)存是一種抽象,可以創(chuàng)建一個看似與存儲空間一樣大的內(nèi)存空間[20]。它源于自動利用主內(nèi)存速度和廉價存儲容量的需要。虛擬內(nèi)存的概念可以追溯到1960年代初:基于頁面的虛擬內(nèi)存最早出現(xiàn)在Atlas Supervisor中(1962年),Multics也支持虛擬內(nèi)存[22]。

虛擬內(nèi)存是在Unix中添加的,大約在Unix誕生后的十年。在誕生時,Unix進程地址空間被劃分為三個段:一個程序文本(代碼)段,在所有進程之間共享但不可寫;一個進程數(shù)據(jù)段,可讀/寫但私有;以及一個棧段。sbrk系統(tǒng)調(diào)用可以擴展和收縮進程數(shù)據(jù)段。然而,由于需要運行需要比當(dāng)時主存儲器容量更多的存儲的程序(例如Lisp),VAX-11體系結(jié)構(gòu)中的MMU使基于頁面的虛擬內(nèi)存成為可能[4],[23]。

這種抽象解耦了兩個相關(guān)的概念:地址空間,即用于尋址內(nèi)存的標(biāo)識符,以及內(nèi)存空間,即用于存儲數(shù)據(jù)的物理位置。從歷史上看,這種解耦具有三個主要目標(biāo):(1)通過獨立于物理內(nèi)存空間的地址空間促進機器的獨立性,(2)通過允許程序員在執(zhí)行時將獨立的模塊組合成程序來促進模塊化,(3)實現(xiàn)運行大型程序的可能性,這些程序無法適應(yīng)物理內(nèi)存(例如Lisp程序)。虛擬內(nèi)存的其它好處包括運行任意大小的程序、運行部分加載的程序以及更改內(nèi)存配置而無需重新編譯程序。虛擬內(nèi)存被視為一種基本的操作系統(tǒng)抽象,但當(dāng)前的硬件和應(yīng)用趨勢正在挑戰(zhàn)其核心假設(shè)。

進程間通信(IPC)

進程間通信的抽象允許一個或多個進程相互交互。早期的Unix版本支持信號和管道[2]。信號使程序員能夠以編程方式處理硬件故障,并且該機制被泛化以允許一個進程通知其它進程。例如,shell進程可以使用信號來停止其它進程。管道是特殊的文件,允許進程彼此交換數(shù)據(jù)。管道不允許任意進程交換數(shù)據(jù),因為兩個進程之間的管道必須由它們共同的祖先進程建立。

由于管道和信號的限制,BSD添加了套接字以為本地和遠程進程提供統(tǒng)一的IPC機制,即在不同主機機器上運行的進程之間的通信。套接字已成為網(wǎng)絡(luò)的標(biāo)準(zhǔn)方式,但與平臺特定的本地IPC機制相比,它們并未被廣泛使用[24]。

共享內(nèi)存的mmap接口被設(shè)想為一種IPC機制[25],[26],但從未真正普及。附加的IPC機制(信號量、專用于共享內(nèi)存的IPC接口和消息隊列)在POSIX.1b中被添加,于1993年發(fā)布,但此后主要被供應(yīng)商特定的IPC機制所取代[24]。

線程和異步I/O

線程和異步I/O是POSIX中為滿足并行性和并發(fā)性需求的后來者抽象。

傳統(tǒng)的UNIX進程提供單個執(zhí)行線程。這種無法支持并發(fā)執(zhí)行線程的能力使得單個UNIX進程無法利用多個計算核心提供的并行性。利用并行性的一種方法是分叉多個進程,但這要求分叉的進程使用IPC機制進行通信,這反過來效率低下。

POSIX異步I/O(AIO)接口旨在滿足對非阻塞I/O接口的需求,從而改進并發(fā)性。該接口使進程能夠調(diào)用異步執(zhí)行的I/O操作。但在各種情況下它可能會阻塞,并且每個I/O操作需要至少兩個系統(tǒng)調(diào)用:一個用于提交請求,另一個用于等待其完成。

在POSIX中,線程于1990年代初開始出現(xiàn),是為了支持多核硬件的并行性并實現(xiàn)應(yīng)用級并發(fā)性[8],[27]。與進程不同,線程在相同的地址空間中運行。POSIX線程可以以不同的方式實現(xiàn):1對1:每個線程在自己的內(nèi)核線程中運行;N對1:所有線程在單個內(nèi)核線程中運行;N對M:N個線程在M個內(nèi)核線程中運行[27],[28],[29]。在用戶空間中管理并行性對于高性能至關(guān)重要[27]。然而,主流的POSIX操作系統(tǒng)采用了1對1的線程模型,理由是實現(xiàn)簡單[30],[31]。盡管如此,使用大量線程的應(yīng)用程序體系結(jié)構(gòu),如分階段事件驅(qū)動架構(gòu)(SEDA)[32],由于線程開銷的緣故效率低下[33]。因此,許多高性能應(yīng)用程序采用每個核心一個線程的模型,其中線程數(shù)量等于處理核心數(shù)量,并且提供自己的并發(fā)接口[34],[35]。

超越POSIX

計算卸載

POSIX進程是以CPU為中心的抽象,因為CPU在Unix發(fā)展的幾十年中一直是中心和主要的計算資源。然而,將計算從CPU卸載到特定領(lǐng)域的協(xié)處理器和加速器(例如用于圖形和并行計算的GPU,以及用于卸載數(shù)據(jù)包處理的NIC)已成為主流[36]。因此,CPU越來越成為協(xié)調(diào)計算資源的協(xié)調(diào)器,并且CPU的計算能力越來越多地被應(yīng)用程序用于僅在各種硬件資源上協(xié)調(diào)計算。

然而,POSIX沒有機制來處理協(xié)處理器或加速器。因此,所有不是CPU的計算元素都被視為I/O設(shè)備。因此,應(yīng)用程序需要使用用戶空間API將代碼和數(shù)據(jù)上傳到加速器,該API通過不透明的系統(tǒng)調(diào)用(例如fcntl())與操作系統(tǒng)內(nèi)核集成。例如,有用于GPGPU的OpenCL和CUDA,以及用于圖形編程的Vulkan等API[37]。這些API必須處理諸如內(nèi)存和資源管理等事物,因為POSIX本身不支持這種類型的硬件。


緩存同步拷貝復(fù)雜度
read/writekernelyesyeslow
mmapkernelyesnomedium
DIOuseryesnomedium
AIO/DIOusernonohigh
io_uringkernel/usernoyes/nohigh

Linux中的I/O訪問方法

異步I/O

異步I/O起源于Multics[11],[12]。然而,POSIX I/O調(diào)用起源于Unix,其I/O接口是同步的。因此,POSIX的read/write系統(tǒng)調(diào)用是同步的,并且它們會導(dǎo)致從內(nèi)核頁緩存中復(fù)制數(shù)據(jù)。同步接口對于快速I/O來說是一個瓶頸,并且需要應(yīng)用程序使用線程來實現(xiàn)應(yīng)用級并發(fā)和并行性。相比之下,mmap接口比傳統(tǒng)的read/write更快,因為它避免了系統(tǒng)調(diào)用開銷和內(nèi)核與用戶空間之間的數(shù)據(jù)復(fù)制。然而,使用mmap的I/O是同步的,具有更復(fù)雜的錯誤處理。例如,磁盤已滿時,寫入將返回錯誤代碼,而基于mmap的I/O則需要處理信號。相比之下,直接I/O(DIO)允許應(yīng)用程序使用相同的read和write系統(tǒng)調(diào)用,同時繞過頁緩存。但是,緩沖區(qū)管理和緩存是在用戶空間中執(zhí)行的。異步I/O(AIO)接口提供了一組新的系統(tǒng)調(diào)用,允許用戶空間應(yīng)用程序異步提交I/O請求,并使用io_submit系統(tǒng)調(diào)用輪詢I/O完成。然而,Linux的AIO實現(xiàn)存在一些問題:每次系統(tǒng)調(diào)用會復(fù)制高達104字節(jié)的描述符和完成元數(shù)據(jù),并且系統(tǒng)調(diào)用有時會發(fā)生阻塞[38]。

Linux的io_uring接口旨在解決這些缺陷,并提供真正的異步I/O接口[38]。它首次引入于Linux內(nèi)核5.1版本,使用兩個無鎖的單生產(chǎn)者單消費者(SPSC)隊列在內(nèi)核和用戶空間之間進行通信[38]。一個隊列用于I/O提交,應(yīng)用程序?qū)懭耄瑑?nèi)核讀取,而另一個隊列用于I/O完成,內(nèi)核寫入,應(yīng)用程序讀取。根據(jù)應(yīng)用場景,應(yīng)用程序可以配置io_uring實例以作為中斷驅(qū)動、輪詢或內(nèi)核輪詢來運行。io_uring接口允許線程提交I/O請求并在操作系統(tǒng)通知I/O操作完成前繼續(xù)執(zhí)行其它任務(wù)。

繞過POSIX I/O

POSIX I/O模型假設(shè)內(nèi)核執(zhí)行I/O,將數(shù)據(jù)傳輸?shù)接脩艨臻g進行進一步處理。然而,這個模型在高到達率下不是很好擴展,所以早期繞過POSIX I/O接口的一個例子是BSD數(shù)據(jù)包過濾器(BPF,BSD Packet filter)。BPF通過在運行于內(nèi)核中的偽機器內(nèi)部過濾數(shù)據(jù)包來促進用戶級別數(shù)據(jù)包捕獲[39]。數(shù)據(jù)包捕獲應(yīng)用程序首先命令內(nèi)核復(fù)制到達網(wǎng)絡(luò)接口卡(NIC)的數(shù)據(jù)包:其中一份復(fù)制遍歷網(wǎng)絡(luò)協(xié)議棧,而另一份遍歷偽機器。BPF偽機器在將經(jīng)過高級描述語言編譯的數(shù)據(jù)包過濾代碼發(fā)送到用戶空間之前執(zhí)行。擴展的伯克利數(shù)據(jù)包過濾器(eBPF,Extended Berkeley Packet Filter)在BPF的基礎(chǔ)上構(gòu)建,并允許應(yīng)用程序在內(nèi)核虛擬機中執(zhí)行沙箱程序,或在能夠運行這些程序的硬件上執(zhí)行[40]。這使得應(yīng)用程序可以將I/O活動(例如網(wǎng)絡(luò)協(xié)議處理和在用戶空間中實現(xiàn)文件系統(tǒng))卸載。具體而言,eBPF允許應(yīng)用程序完全繞過I/O的POSIX抽象,并在用戶空間中實現(xiàn)它們。eBPF補充了現(xiàn)有的內(nèi)核繞過方法,如DPDK和SPDK,它們使得應(yīng)用程序可以繞過內(nèi)核進行網(wǎng)絡(luò)和存儲I/O[41],[42]。

超越機器抽象

POSIX提供了一種可移植地編寫應(yīng)用程序的抽象方式,可在類Unix操作系統(tǒng)變體和機器架構(gòu)上運行。然而,當(dāng)代應(yīng)用程序很少在單個機器上運行。它們越來越多地使用遠程過程調(diào)用(RPC)、HTTP和REST API、分布式KV存儲和數(shù)據(jù)庫,所有這些都是使用高級語言(如JavaScript或Python)實現(xiàn)的,運行在托管的運行時上。這些托管的運行時和框架暴露了隱藏其底層POSIX抽象和接口的接口。此外,它們還允許應(yīng)用程序使用C之外的編程語言進行編寫,而C是Unix和POSIX的編程語言。因此,對于許多當(dāng)代系統(tǒng)和服務(wù)的開發(fā)者來說,POSIX在很大程度上已經(jīng)過時,因為它的抽象是低級的,并且與單個機器綁定在一起。

然而,云和無服務(wù)器平臺現(xiàn)在面臨的問題與之前的POSIX操作系統(tǒng)相似:它們的API是分散且特定于平臺的,這使得編寫可移植的應(yīng)用程序變得困難。此外,這些API仍然是以CPU為中心的,這使得在不使用定制解決方案的情況下,難以高效地利用特殊用途的加速器和非集成硬件。例如,可以認(rèn)為JavaScript今天與過去的POSIX處于類似的位置:它將應(yīng)用程序邏輯與底層操作系統(tǒng)和機器架構(gòu)解耦。然而,JavaScript運行時仍然是以CPU為中心的,這使得將JavaScript應(yīng)用程序的某些部分卸載到運行在NIC或存儲設(shè)備上的加速器變得困難。具體而言,我們需要一種能夠表達應(yīng)用程序邏輯的語言,使得編譯器和語言運行時能夠高效地利用不同硬件堆棧中新興的大量硬件資源的能力。與此同時,思考一下如果POSIX中沒有以CPU為中心的特點,這些設(shè)備的硬件設(shè)計會有多么不同,將是一個有趣的思想實驗。

結(jié)束語

多年來,POSIX已經(jīng)成為操作系統(tǒng)抽象和接口的標(biāo)準(zhǔn)。抽象設(shè)計的兩個驅(qū)動因素是硬件約束和當(dāng)時的應(yīng)用場景。今天,I/O和計算之間的速度平衡正在向I/O傾斜,這在一定程度上解釋了為什么協(xié)處理器和特殊用途的加速器越來越受歡迎。因此,我們認(rèn)為POSIX時代已經(jīng)結(jié)束,未來的設(shè)計需要超越POSIX,并在更高的級別上重新思考抽象和接口。我們還認(rèn)為操作系統(tǒng)接口必須改變以支持這些更高級別的抽象。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
深刻理解Linux進程間通信(IPC)
經(jīng)典Linux/UNIX必讀書單推薦給你
Linux 線程模型的比較:LinuxThreads 和 NPTL --貌似老舊晦澀
IT工程師必須了解的10個操作系統(tǒng)基本概念
QNX簡介
.NET軟件開發(fā), 你應(yīng)該知道 (整)
更多類似文章 >>
生活服務(wù)
熱點新聞
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服