淺談原子操作

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"作者:阿里雲操作系統:子札","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"前言","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/3f/3f2377d5e16099046179156338a82495.png","alt":null,"title":"","style":[{"key":"width","value":"25%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所謂原子操作,就是要麼不做,要麼全做。在很多場景中,都有對原子操作的需求。在翻aep的spec文檔時,也發現了一個巧妙的方法。所以順便發散性地總結一下各種實現原子操作的方法,歡迎大家交流探討。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"小粒度——指令","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/3f/3f2377d5e16099046179156338a82495.png","alt":null,"title":"","style":[{"key":"width","value":"25%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"根據intel手冊卷三第八章的描述,x86使用三種機制來實現原子操作:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1. Guaranteed atomic operations。Guaranteed atomic operations是指一些基本的讀寫內存操作,這些操作都是保證原子性的。一般來說,讀寫位於一個cache line中的數據是原子性的。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2. bus lock,使用LOCK#信號和指令的lock前綴。鎖總線的方式很簡單,進行原子操作的cpu會在bus上assert一個LOCK#信號,此時其他cpu的操作都會被block住。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3. cache lock,利用cache一致性協議(MESI協議)來實現。如果要訪問的內存區域已經在當前cpu的cache中了,就會利用cache一致性協議來實現原子操作,否則會鎖總線。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"intel早期cpu(如Intel386,Intel486,奔騰處理器)實現原子操作,是通過bus lock來實現的。這種實現的問題,是完全不相關的兩個cpu之間,也會相互競爭總線鎖,從而導致整體性能下降。在後來的cpu中,intel對這一問題進行了優化。當要進行原子操作的內存已經被拉入cache中時,cpu會使用cache一致性協議來保證原子性,這被稱爲cache lock。相比於bus lock,cache lock粒度更細,能獲得更好的性能。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"x86中,有些指令是自帶lock語義的,比如XCHG,更新段描述符等等;另外一些指令可以手動加上lock前綴來實現lock語義,比如BTS, BTR,CMPXCHG指令。在這些指令中,最核心的當屬CAS(Compare And Swap)指令了,它是實現各種鎖語義的核心指令。不同於自帶原子語義的XCHG,CAS操作要通過\"lock CMPXCHG\"這樣的形式來實現。一般而言,原子操作的數據長度不會超過8個字節,也不允許同時對兩個內存地址進行CAS操作(如果可以的話,免鎖雙向鏈表不是夢)。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原子操作中另一個繞不開的話題是ABA問題,水平有限,就不展開講了。簡單提一個例子,在linux內核的slub實現中,用上了一個宏cmpxchg_double,這並不是同時對兩個內存地址進行CAS的黑魔法,而正是利用CMPXCHG16B指令解決ABA問題的宏函數,有興趣的可以深究一把。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"大粒度","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/3f/3f2377d5e16099046179156338a82495.png","alt":null,"title":"","style":[{"key":"width","value":"25%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當原子操作的對象大小在16字節或者8字節以內時,一兩條指令就能實現原子操作。但是,當對象的大小較大時,實現原子操作的就需要其他方法了,比如加鎖和COW。深究這兩種方法,可以發現在本質上,它們還是將問題轉換成了16字節的原子操作。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"加鎖","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"加鎖這個方式很好理解,只要一加鎖,整個臨界區的操作就可以被看作一個原子操作。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"內核中提供了各種各樣的鎖,自旋鎖,讀寫鎖,seq鎖,mutex,semaphore等等,這些鎖對讀寫者的傾向各有不同,在是否允許睡眠上也有所不同。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"簡單來說,自旋鎖和讀寫鎖的核心都是利用原子指令來CAS操縱一個32位/64位的值,它們都不允許睡眠,但是讀寫鎖對於讀者做了優化,允許多個讀者同時讀取數據,而自旋鎖則對於讀寫操作沒有什麼偏向性。seq基於自旋鎖實現,不允許睡眠,但是對寫者更爲友好。mutex和semaphore也是基於自旋鎖實現的,但是它們允許互斥區的操作陷入睡眠。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以看到,加鎖這種方式,最核心的還是利用指令實現原子操作。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"COW","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"針對大對象原子操作的另一種方式是COW(copy on write)。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"cow的思想其實非常簡單,首先我們有一個指向這個大對象的指針,在需要原子性修改這個大對象的數據時,因爲沒辦法做到inplace修改,所以就把這個對象的數據拷貝一份,在對象副本上修改,最後再原子性地修改指向這個對象的指針。可以看到,這裏最核心的地方是利用指令來實現指針的替換。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"關於COW,這裏舉一個AEP的例子。AEP是一種存儲介質,這裏只需要知道它可以按字節尋址和數據在掉電後不消失即可。普通的磁盤,一般有扇區原子性的保證,也就是在將新數據寫入某個扇區的途中突然掉電的話,這個扇區上要麼完全沒有新數據,要麼新數據完全被寫下去了,不會出現一半新一半舊的狀態。扇區原子性的保證很重要,許多數據庫都依賴它,然而,AEP這種存儲介質沒有這種保證,所以需要用軟件的方式來做這種保證,稱爲BTT。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"BTT的思路也很簡單,爲了方便理解,後文我不引入AEP的術語來進行描述。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先把整個存儲空間劃分成若干個block,每個block有自己的物理塊號,然後再維護一個表來做邏輯塊號到物理塊號的轉換。給上層邏輯塊的數量略小於物理塊數量,這樣就會有一部分的物理塊沒有被映射,姑且稱爲free block。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"比如下圖,4個邏輯塊,5個物理塊,其中1號塊是free block。","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/f2/f238436aef4e3d3c7f26cf36e99de5c8.png","alt":null,"title":"","style":[{"key":"width","value":"50%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下來,在往一個邏輯塊上寫數據時,先找一個free block,把數據寫上去,接下來去映射表中,將邏輯塊的映射修改該free block。整個流程中,最關鍵的一步——修改映射關係——是原子性的。只要有這個保證,那麼就能夠提供block數據原子性更新的能力。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"COW的思想在很多地方都有,比如qemu的qcow鏡像快照,ext4和btrfs在寫入數據時的cow,linux內核的rcu機制等等。此外,cow最有名的使用場景莫過於fork的實現了,但是它只是單純的爲了減少拷貝開銷,與原子性沒有太大關係","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"COW優化","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"cow的方式,有個很麻煩的事情,就是每次都得原子性的去更新指針。那麼有沒有辦法去掉這個指針呢?有的。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這個是在intel關於AEP的文檔上學到的另一種取巧的方式(注意,下面描述的例子和上文中的BTT沒有任何關係)。起因是這樣的:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"AEP的驅動使用一個稱爲index block的結構來管理元數據,這個index block處於整個介質的起始位置,大小至少爲256字節。有些操作會去更改它的多個字段的值,所以可能出現更改字段到一半的過程中掉電的情況,因此需要一種機制來保證更改過程是原子性的。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"正常的COW方式,需要在起始位置處保留兩個index block大小的空間以及一個指針,其中一個index block作爲備用。在修改index block的數據時,以cow的方式將全部的數據存儲在備用index block中,然後以COW的方式更改指針指向該備用index block中。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Intel使用下面的機制來優化掉指針:","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/cc/cc3bc29e9c74e8398aeaf85737ef0f56.png","alt":null,"title":"","style":[{"key":"width","value":"50%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了方便敘述,兩個index block分別命名爲blockA和blockB。","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第一次寫入數據,寫入到blockA中,其上的seq爲01;","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第二次寫入數據,寫入到blockB中,其上的seq爲10;","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第三次寫入數據,寫入到blockA中,其上的seq爲11;","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第四次寫入數據,寫入到blockB中,其上的seq爲01;","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"...","attrs":{}}]}],"attrs":{}}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如此往復,在恢復時,只要讀取並比較兩個index block上的seq中哪個處於循環的前方,就能找到最新的那個index block。這樣的優勢是顯而易見的,一是避免了額外的指針,或者說把指針固化到兩個index block中,避免了一個8字節指針對兩個index block對齊帶來的麻煩;二是少一次寫操作,提升了效率。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"多對象","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/3f/3f2377d5e16099046179156338a82495.png","alt":null,"title":"","style":[{"key":"width","value":"25%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前面針對的都是一個個單個的對象,如果涉及到多個對象,要保證原子性就比較複雜了。比如,如果使用加解鎖的方式,就需要注意鎖的順序,防止死鎖的問題;如果是cow的方式,就需要注意中途失敗以後的把已替換的指針回滾回去的問題。從更大的格局來看,針對多個對象的原子操作,本質上就是進行一次事務操作。所以,這個問題的解法,參考事務的實現就好了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"寫日誌","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/3f/3f2377d5e16099046179156338a82495.png","alt":null,"title":"","style":[{"key":"width","value":"25%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"事務的四大特徵ACID,即原子性,一致性,隔離性和持久性,基本上是一個常識了,而原子性只是事務的一個特性。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"寫日誌算是實現事務最通用的方式了,日誌一般分爲redo和undo兩種日誌,爲了加快恢復速度,一般還會引入檢查點(checkpoint)的概念。在文件系統和數據庫的實現中,基本上都能看到事務的身影。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"寫日誌除了能保證原子性和一致性以外,還對磁盤這種外存設備很友好,因爲寫日誌基本上都是順序的。在這一方面的典型案例,當屬日誌結構文件系統和leveldb的LSM-tree了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"leveldb的原理想必不用再提了,它把對於K-V對的增刪改操作都變成一條條的日誌,然後持久化爲磁盤上的一個個SST,之後再觸發合併整理。這樣一來,基本上對於磁盤的所有操作都是順序的了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"日誌結構文件系統也是類似的思想,它將文件數據的增刪改操作直接變成日誌寫到磁盤裏面,文件的實際數據不需要單獨再存到某個地方,而是靠日誌恢復出來。這種做法對寫操作是非常友好的,但是讀方面的性能就有點差強人意了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"事務內存","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/3f/3f2377d5e16099046179156338a82495.png","alt":null,"title":"","style":[{"key":"width","value":"25%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"事務通常是用於保證持久性數據一致性的。去掉持久性的要求,將事務的概念引入到對於內存對象的操控中,就有了事務內存的概念。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"正如上文所說,對於多個對象的操作,加鎖和cow的方式,在使用時都比較麻煩。加鎖的方式要考慮加解鎖順序防止死鎖,中途失敗了還要按照特定的順序解鎖回滾;cow也是一樣,雖然沒有死鎖的問題,但是在回滾上也是很麻煩的。另一個問題就是,針對不同的場景,加解鎖的順序要重新考慮,cow的回滾也要重新考慮,不具有通用性。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"事務內存機制則是爲了解決這些問題而提出的,它把針對多個對象的原子操作抽象爲一個事務,只要按照它提供的api,以串行化的思路去編程就行了。不用考慮加解鎖的順序,也不必考慮回滾的問題,在遇到了某些fatal error時只要abort掉事務即可。這是一種通用的併發編程方式,簡化編碼的同時,還能保證併發的性能。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"事實上,事務內存機制的內部實現,也是依賴於cow機制和加解鎖來實現的,更深一步,其實也是依賴於原子操作指令的。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"總結","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/3f/3f2377d5e16099046179156338a82495.png","alt":null,"title":"","style":[{"key":"width","value":"25%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"總結一下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"16字節或8字節以內的內存數據,使用cpu的原子操作指令;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"16字節以上的數據,使用加鎖、COW的方式,或者優化過的使用seq的COW方式,本質上還是依賴於原子指令;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"針對多個對象的原子操作,引入事務或者事務內存的概念,實際上的實現要麼是寫日誌,要麼是依賴於cow或加鎖的方式,最終依賴於原子指令。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以,萬變不離其宗,原子操作指令很關鍵。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"參考鏈接","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://pmem.io/documents/NVDIMM_Namespace_Spec.pdf","title":null},"content":[{"type":"text","text":"https://pmem.io/documents/NVDIMM_Namespace_Spec.pdf","attrs":{}}]}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://software.intel.com/content/dam/develop/public/us/en/documents/325462-sdm-vol-1-2abcd-3abcd.pdf","title":null},"content":[{"type":"text","text":"https://software.intel.com/content/dam/develop/public/us/en/documents/325462-sdm-vol-1-2abcd-3abcd.pdf","attrs":{}}]}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://zhuanlan.zhihu.com/p/151425608","title":null},"content":[{"type":"text","text":"https://zhuanlan.zhihu.com/p/151425608","attrs":{}}]}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://zh.wikipedia.org/wiki/%E8%BD%AF%E4%BB%B6%E4%BA%8B%E5%8A%A1%E5%86%85%E5%AD%98","title":null},"content":[{"type":"text","text":"https://zh.wikipedia.org/wiki/%E8%BD%AF%E4%BB%B6%E4%BA%8B%E5%8A%A1%E5%86%85%E5%AD%98","attrs":{}}]}]}],"attrs":{}}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"更多信息,歡迎釘釘掃描二維碼進羣交流。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/17/17655dec580e3d3fcf07ab58310102e2.png","alt":null,"title":"","style":[{"key":"width","value":"50%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"往期精彩回顧:","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"http://mp.weixin.qq.com/s?__biz=MzUxNjE3MTcwMg==&mid=2247484798&idx=1&sn=2f91a6983cf714d938a05493d9b53c3e&chksm=f9aa37a7ceddbeb1fc1ff2e30640ccf05c43314719e8148f142aad44572ba8545b4698b27c56&scene=21#wechat_redirect","title":null},"content":[{"type":"text","text":"阿里馬濤:重新定義雲時代的開源操作系統 | 人物誌","attrs":{}}]}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"http://mp.weixin.qq.com/s?__biz=MzUxNjE3MTcwMg==&mid=2247484788&idx=1&sn=3603207b75136ab43bbd4f983edfa52d&chksm=f9aa37adceddbebbc426c803805f11238ffc176b50257a0d4bb90e455e2691fd47a35d968a37&scene=21#wechat_redirect","title":null},"content":[{"type":"text","text":"阿里雲官方推出操作系統“等保合規”鏡像 -- Alibaba Cloud Linux 等保2.0三級版","attrs":{}}]}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"http://mp.weixin.qq.com/s?__biz=MzUxNjE3MTcwMg==&mid=2247484689&idx=1&sn=c9590700df6bb981528f4b1a9eaf81b3&chksm=f9aa37c8ceddbedebf4fcb5e139ef0b00da5c54db00e0f14ebec9009387e8afda761d6cfe5ee&scene=21#wechat_redirect","title":null},"content":[{"type":"text","text":"面對疾風吧!io_uring 優化 nginx 實戰演練","attrs":{}}]}]}],"attrs":{}}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/b8/b892c228205f030b8f36c7bb15107a3f.png","alt":null,"title":"","style":[{"key":"width","value":"50%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章