緩衝管理的基本問題

來源:互聯網
上載者:User

     所謂緩衝,本質上是同一塊資料在不同空間的儲存。這樣的例子很多:

※ CPU和記憶體之間的快取;

※ 同時映射到兩個進程地址空間的資料,典型的是共用記憶體;

※ 同時位於資料庫和記憶體中的同一個業務資料,如O-R映射;

※ 位於兩台伺服器的資料,典型的例子是叢集全域配置資訊。

一、訪問緩衝可能發生的簡單問題:

    1、在同一個儲存空間中,不同進程/線程間的共用資料一致性問題。

例如,假設有一個表示姓名的資料結構被兩個線程A、B共用:

struct name {

  char* first;

  char* last;

}  

假設線程A要修改姓名,步驟如下:

第一步,修改name.first

第二步,修改name.last

    如果線程B在第一步和第二步之間讀取name,那麼它將獲得的是不匹配的“姓”和“名”。

   2、在不同儲存空間中,資料的一致性問題。

仍然以上面的資料為例,這次假設同樣的資料在記憶體和資料庫中各有一份。如果線程A要修改姓名,步驟如下:

第一步:修改記憶體中的name資料;

第二步:將資料儲存在資料庫中(修改資料庫中的name資料)。

    同樣,如果在第一步和第二步之間,B先從資料庫中讀取了name,再與記憶體中的name比較,就會探索資料不一致問題。

     雖然上述兩個問題看起來都是由於不同儲存空間(記憶體的不同地區、記憶體和資料庫)造成的資料一致性。其實,這兩個問題本質是不同的,問題1是兩份有關聯的資料間的一致性問題;問題2是同一份資料在不同儲存空間中的一致性問題。

 

二、解決思路

    1、Copy-on-Write方法

         對於被多個線程共用的資料來說,如果一個線程要修改資料,步驟如下:

         第一步:將要求改的資料D複製一份,作為線程私人資料D’;

         第二步:對D’進行所需的修改;

         第三步:查看D從第一步到現在是否未被被其他線程修改過。如果是,則用D’替換D;否則重新從第一步開始。

         第三步其實是一個CAS過程(Compare and Set),要求是一個原子操作。上述過程常用迴圈來類比:

         while (true) {

             D’ = copy(D);

             modify(D’);

             if CAS( !modified(D) , D’)

                break;

         }

    2、加鎖方法

         對於被多個線程共用的資料來說,如果一個線程要修改資料,步驟如下:

         第一步:對要修改的資料D加獨佔鎖定(X鎖),阻止其他線程訪問;

         第二步:修改資料D;

         第三步:解除資料D上的鎖。       

     方法1正是所謂無鎖結構(lock-free),相比方法2並發要效能高一些,但是複雜性也相對高一些。而且,方法1通常也可用鎖機制來類比,只是加鎖時間短暫一些,通常被稱為spin-lock(旋轉鎖)。

     上述兩個方法的根本,有其共同之處,就是要保證:在共用資料被修改完成以前,不能被其他線程訪問。

 

三、稍微複雜一些的緩衝管理問題

    1、階層的資料一致性問題。

        例如下面的資料結構中,結構name是結構person的成員:

struct name {

  char* first;

  char* last;

}  

        stuct person {

            int id;

            struct name full_name;

        }

        如果我們要通過加鎖的方式更新person的資料,就要考慮是否對person.full_name也加鎖。

    2、寫緩衝的時機

        對於需要在兩種儲存介質中儲存的某種資訊,必須考慮何時同步這兩種儲存中的資料。例如,記憶體和資料庫中的資料同步;記憶體和磁碟之間的資料同步;CPU和記憶體之間的資料同步。

    3、緩衝的透明性

這就首先要考慮下面兩個問題。

        1)沖機制的引入,與沒有緩衝相比,是否需要對外暴露更多的介面。

     考慮為保證一致性而引入鎖機制,對編程介面的影響。最直觀的方案,就是要求程式員必須顯式的進行“加鎖/解鎖”操作:

     lock(d);

     *d = new_value;

     unlock(d);

     另一種方案,就是對外不暴露鎖機制,由架構內部完成:

     change(data* d, data new_value) {

         lock(d);

         *d = new_value;

         unlock(d);

     }

     雖然後一種方案看起來先進一些,但其實對於比較複雜的資料結構來說,要求實現被修改資料實現深拷貝(deep copy)介面。

        2)是不是每次修改資料,都要同步資料。

           對於一個較複雜的資料結構來說,我們可能常常一次只修改其中的一部分資料。例如:

           name.first = “Tom”;

           /* 進行其他動作 */

           /* … */

           name.last = “Smith”;

     有時,如果修改每一部分資料都進行同步操作,分散寫入資料,不但步驟比較繁瑣,而且效率不如集中寫入高。如果讓緩衝管理機制來決定何時寫入資料,可能即方便又高效。但是,這樣做也有新的問題,一方面實現起來比較複雜,另一方面,如果系統崩潰,可能造成緩衝中為寫入的資料丟失。

     這就引出了其他機制,回寫、直寫、先寫日誌和檢查點等各種新的概念和技術。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.