分佈式開發+Linux集羣

  • 簡單說,分佈式是以縮短單個任務的執行時間來提升效率的,而集羣則是通過提高單位時間內執行的任務數來提升效率。

    例如:

    如果一個任務由10個子任務組成,每個子任務單獨執行需1小時,則在一臺服務器上執行改任務需10小時。

    採用分佈式方案,提供10臺服務器,每臺服務器只負責處理一個子任務,不考慮子任務間的依賴關係,執行完這個任務只需一個小時。(這種工作模式的一個典型代表就是Hadoop的Map/Reduce分佈式計算模型)

    而採用集羣方案,同樣提供10臺服務器,每臺服務器都能獨立處理這個任務。假設有10個任務同時到達,10個服務器將同時工作,10小後,10個任務同時完成,這樣,整身來看,還是1小時內完成一個任務!

     

    以下是摘抄自網絡文章:

    集羣概念

    1. 兩大關鍵特性 
    集羣是一組協同工作的服務實體,用以提供比單一服務實體更具擴展性與可用性的服務平臺。在客戶端看來,一個集羣就象是一個服務實體,但事實上集羣由一組服務實體組成。與單一服務實體相比較,集羣提供了以下兩個關鍵特性:

    ·  可擴展性--集羣的性能不限於單一的服務實體,新的服務實體可以動態地加入到集羣,從而增強集羣的性能。

    ·  高可用性--集羣通過服務實體冗餘使客戶端免於輕易遇到out of service的警告。在集羣中,同樣的服務可以由多個服務實體提供。如果一個服務實體失敗了,另一個服務實體會接管失敗的服務實體。集羣提供的從一個出 錯的服務實體恢復到另一個服務實體的功能增強了應用的可用性。

    2. 兩大能力 
    爲了具有可擴展性和高可用性特點,集羣的必須具備以下兩大能力:

    ·  負載均衡--負載均衡能把任務比較均衡地分佈到集羣環境下的計算和網絡資源。

    ·  錯誤恢復--由於某種原因,執行某個任務的資源出現故障,另一服務實體中執行同一任務的資源接着完成任務。這種由於一個實體中的資源不能工作,另一個實體中的資源透明的繼續完成任務的過程叫錯誤恢復。

    負載均衡和錯誤恢復都要求各服務實體中有執行同一任務的資源存在,而且對於同一任務的各個資源來說,執行任務所需的信息視圖(信息上下文)必須是一樣的。

    3. 兩大技術 
    實現集羣務必要有以下兩大技術:

    ·  集羣地址--集羣由多個服務實體組成,集羣客戶端通過訪問集羣的集羣地址獲取集羣內部各服務實體的功能。具有單一集羣地址(也叫單一影像)是集羣的一個基 本特徵。維護集羣地址的設置被稱爲負載均衡器。負載均衡器內部負責管理各個服務實體的加入和退出,外部負責集羣地址向內部服務實體地址的轉換。有的負載均 衡器實現真正的負載均衡算法,有的只支持任務的轉換。只實現任務轉換的負載均衡器適用於支持ACTIVE-STANDBY的集羣環境,在那裏,集羣中只有 一個服務實體工作,當正在工作的服務實體發生故障時,負載均衡器把後來的任務轉向另外一個服務實體。

    ·  內部通信--爲了能協同工作、實現負載均衡和錯誤恢復,集羣各實體間必須時常通信,比如負載均衡器對服務實體心跳測試信息、服務實體間任務執行上下文信息的通信。

    具有同一個集羣地址使得客戶端能訪問集羣提供的計算服務,一個集羣地址下隱藏了各個服務實體的內部地址,使得客戶要求的計算服務能在各個服務實體之間分佈。內部通信是集羣能正常運轉的基礎,它使得集羣具有均衡負載和錯誤恢復的能力。

    集羣分類

    Linux集羣主要分成三大類( 高可用集羣, 負載均衡集羣,科學計算集羣)

    高可用集羣( High Availability Cluster)
    負載均衡集羣(Load Balance Cluster)
    科學計算集羣(High Performance Computing Cluster)
    ================================================

    具體包括:

    Linux High Availability 高可用集羣                                       
    (普通兩節點雙機熱備,多節點HA集羣,RAC, shared, share-nothing集羣等)

    Linux Load Balance 負載均衡集羣                                      
     (LVS等....)

    Linux High Performance Computing 高性能科學計算集羣     
     (Beowulf 類集羣....)

    分佈式存儲                                                                         
    其他類linux集羣              
    (如Openmosix, rendering farm 等..)

    詳細介紹

    1. 高可用集羣(High Availability Cluster)
    常見的就是2個節點做成的HA集羣,有很多通俗的不科學的名稱,比如"雙機熱備", "雙機互備", "雙機".
    高可用集羣解決的是保障用戶的應用程序持續對外提供服務的能力。 (請注意高可用集羣既不是用來保護業務數據的,保護的是用戶的業務程序對外不間斷提供服務,把因軟件/硬件/人爲造成的故障對業務的影響降低到最小程度)。

    2. 負載均衡集羣(Load Balance Cluster)

    負載均衡系統:集羣中所有的節點都處於活動狀態,它們分攤系統的工作負載。一般Web服務器集羣、數據庫集羣和應用服務器集羣都屬於這種類型。

    負載均衡集羣一般用於相應網絡請求的網頁服務器,數據庫服務器。這種集羣可以在接到請求時,檢查接受請求較少,不繁忙的服務器,並把請求轉到這些服務器上。從檢查其他服務器狀態這一點上看,負載均衡和容錯集羣很接近,不同之處是數量上更多。

    3. 科學計算集羣(High Performance Computing Cluster)

    高性能計算(High Perfermance Computing)集羣,簡稱HPC集羣。這類集羣致力於提供單個計算機所不能提供的強大的計算能力。

    高性能計算分類  
     高吞吐計算(High-throughput Computing)
      有一類高性能計算,可以把它分成若干可以並行的子任務,而且各個子任務彼此間沒有什麼關聯。象在家搜尋外星人( SETI@HOME  -- Search for Extraterrestrial Intelligence at Home )就是這一類型應用。這一項目是利用Internet上的閒置的計算資源來搜尋外星人。SETI項目的服務器將一組數據和數據模式發給Internet上 參加SETI的計算節點,計算節點在給定的數據上用給定的模式進行搜索,然後將搜索的結果發給服務器。服務器負責將從各個計算節點返回的數據彙集成完整的 數據。因爲這種類型應用的一個共同特徵是在海量數據上搜索某些模式,所以把這類計算稱爲高吞吐計算。所謂的Internet計算都屬於這一類。按照 Flynn的分類,高吞吐計算屬於SIMD(Single Instruction/Multiple Data)的範疇。

     分佈計算(Distributed Computing)
      另一類計算剛好和高吞吐計算相反,它們雖然可以給分成若干並行的子任務,但是子任務間聯繫很緊密,需要大量的數據交換。按照Flynn的分類,分佈式的高性能計算屬於MIMD(Multiple Instruction/Multiple Data)的範疇。

    4. 分佈式(集羣)與集羣的聯繫與區別 
    分佈式是指將不同的業務分佈在不同的地方。 
    而集羣指的是將幾臺服務器集中在一起,實現同一業務。 
    分佈式中的每一個節點,都可以做集羣。 
    而集羣並不一定就是分佈式的。 
    舉例:就比如新浪網,訪問的人多了,他可以做一個羣集,前面放一個響應服務器,後面幾臺服務器完成同一業務,如果有業務訪問的時候,響應服務器看哪臺服務器的負載不是很重,就將給哪一臺去完成。 
    而分佈式,從窄意上理解,也跟集羣差不多, 但是它的組織比較鬆散,不像集羣,有一個組織性,一臺服務器垮了,其它的服務器可以頂上來。 
    分佈式的每一個節點,都完成不同的業務,一個節點垮了,哪這個業務就不可訪問了。

    發佈於 2個月前, 閱讀(16) | 評論(0) | 投票(0) | 收藏(0) 閱讀全文...
  • 162013-10

    一致性hash和solr千萬級數據分佈式搜索引擎中的應用

    互聯網創業中大部分人都是草根創業,這個時候沒有強勁的服務器,也沒有錢去買很昂貴的海量數據庫。在這樣嚴峻的條件下,一批又一批的創業者從創業中獲得成功,這個和當前的開源技術、海量數據架構有着必不可分的關係。比如我們使用mysql、nginx等開源軟件,通過架構和低成本服務器也可以搭建千萬級用戶訪問量的系統。新浪微博、淘寶網、騰訊等大型互聯網公司都使用了很多開源免費系統搭建了他們的平臺。所以,用什麼沒關係,只要能夠在合理的情況下采用合理的解決方案。

    那怎麼搭建一個好的系統架構呢?這個話題太大,這裏主要說一下數據分流的方式。比如我們的數據庫服務器只能存儲200個數據,突然要搞一個活動預估達到600個數據。
    可以採用兩種方式:橫向擴展或者縱向擴展。
    縱向擴展是升級服務器的硬件資源。但是隨着機器的性能配置越高,價格越高,這個代價對於一般的小公司是承擔不起的。
    橫向擴展是採用多個廉價的機器提供服務。這樣一個機器只能處理200個數據、3個機器就可以處理600個數據了,如果以後業務量增加還可以快速配置增加。在大多數情況都選擇橫向擴展的方式。如下圖:
    圖1

    圖2

    現在有個問題了,這600個數據如何路由到對應的機器。需要考慮如果均衡分配,假設我們600個數據都是統一的自增id數據,從1~600,分成3堆可以採用 id mod 3的方式。其實在真實環境可能不是這種id是字符串。需要把字符串轉變爲hashcode再進行取模。

    目前看起來是不是解決我們的問題了,所有數據都很好的分發並且沒有達到系統的負載。但如果我們的數據需要存儲、需要讀取就沒有這麼容易了。業務增多怎麼辦,大家按照上面的橫向擴展知道需要增加一臺服務器。但是就是因爲增加這一臺服務器帶來了一些問題。看下面這個例子,一共9個數,需要放到2臺機器(1、2)上。各個機器存放爲:1號機器存放1、3、5、7、9 ,2號機器存放 2、4、6、8。如果擴展一臺機器3如何,數據就要發生大遷移,1號機器存放1、4、7, 2號機器存放2、5、8, 3號機器存放3、6、9。如圖:

    圖3
    從圖中可以看出 1號機器的3、5、9遷移出去了、2好機器的4、6遷移出去了,按照新的秩序再重新分配了一遍。數據量小的話重新分配一遍代價並不大,但如果我們擁有上億、上T級的數據這個操作成本是相當的高,少則幾個小時多則數天。並且遷移的時候原數據庫機器負載比較高,那大家就有疑問了,是不是這種水平擴展的架構方式不太合理?

    —————————–華麗分割線—————————————

    一致性hash就是在這種應用背景提出來的,現在被廣泛應用於分佈式緩存,比如memcached。下面簡單介紹下一致性hash的基本原理。最早的版本 http://dl.acm.org/citation.cfm?id=258660。國內網上有很多文章都寫的比較好。如: http://blog.csdn.net/x15594/article/details/6270242

    下面簡單舉個例子來說明一致性hash。

    準備:1、2、3 三臺機器
    還有待分配的9個數 1、2、3、4、5、6、7、8、9
    一致性hash算法架構

    步驟
    一、構造出來 2的32次方 個虛擬節點出來,因爲計算機裏面是01的世界,進行劃分時採用2的次方數據容易分配均衡。另 2的32次方是42億,我們就算有超大量的服務器也不可能超過42億臺吧,擴展和均衡性都保證了。
    一致性hash
    二、將三臺機器分別取IP進行hashcode計算(這裏也可以取hostname,只要能夠唯一區別各個機器就可以了),然後映射到2的32次方上去。比如1號機器算出來的hashcode並且mod (2^32)爲 123(這個是虛構的),2號機器算出來的值爲 2300420,3號機器算出來爲 90203920。這樣三臺機器就映射到了這個虛擬的42億環形結構的節點上了。
    圖5
    三、將數據(1-9)也用同樣的方法算出hashcode並對42億取模將其配置到環形節點上。假設這幾個節點算出來的值爲 1:10,2:23564,3:57,4:6984,5:5689632,6:86546845,7:122,8:3300689,9:135468。可以看出 1、3、7小於123, 2、4、9 小於 2300420 大於 123, 5、6、8 大於 2300420 小於90203920。從數據映射到的位置開始順時針查找,將數據保存到找到的第一個Cache節點上。如果超過2^32仍然找不到Cache節點,就會保存到第一個Cache節點上。也就是1、3、7將分配到1號機器,2、4、9將分配到2號機器,5、6、8將分配到3號機器。
    圖6
    這個時候大家可能會問,我到現在沒有看見一致性hash帶來任何好處,比傳統的取模還增加了複雜度。現在馬上來做一些關鍵性的處理,比如我們增加一臺機器。按照原來我們需要把所有的數據重新分配到四臺機器。一致性hash怎麼做呢?現在4號機器加進來,他的hash值算出來取模後是12302012。 5、8 大於2300420 小於12302012 ,6 大於 12302012 小於90203920 。這樣調整的只是把5、8從3號機器刪除,4號機器中加入 5、6。
    圖7
    同理,刪除機器怎麼做呢,假設2號機器掛掉,受影響的也只是2號機器上的數據被遷移到離它節點,上圖爲4號機器。
    圖8
    大家應該明白一致性hash的基本原理了吧。不過這種算法還是有缺陷,比如在機器節點比較少、數據量大的時候,數據的分佈可能不是很均衡,就會導致其中一臺服務器的數據比其他機器多很多。爲了解決這個問題,需要引入虛擬服務器節點的機制。如我們一共有隻有三臺機器,1、2、3。但是實際又不可能有這麼多機器怎麼解決呢?把 這些機器各自虛擬化出來3臺機器,也就是 1a 1b 1c 2a 2b 2c 3a 3b 3c,這樣就變成了9臺機器。實際 1a 1b 1c 還是對應1。但是實際分佈到環形節點就變成了9臺機器。數據分佈也就能夠更分散一點。如圖:
    圖91

    寫了這麼多一致性hash,這個和分佈式搜索有什麼半點關係?我們現在使用solr4搭建了分佈式搜索,測試了基於solrcloud的分佈式平臺提交20條數據居然需要幾十秒,所以就廢棄了solrcloud。採用自己hack solr平臺,不用zookeeper做分佈式一致性管理平臺,自己管理數據的分發機制。既然需要自己管理數據的分發,就需要考慮到索引的創建,索引的更新。這樣我們的一致性hash也就用上了。整體架構如下圖:

    圖10
    建立和更新需要維持機器的位置,能夠根據數據的key找到對應的數據分發並更新。這裏需要考慮的是如何高效、可靠的把數據建立、更新到索引裏。
    備份服務器防止建立服務器掛掉,可以根據備份服務器快速恢復。
    讀服務器主要做讀寫分離使用,防止寫索引影響查詢數據。
    集羣管理服務器管理整個集羣內的服務器狀態、告警。

    整個集羣隨着業務增多還可以按照數據的類型劃分,比如用戶、微博等。每個類型按照上圖架構搭建,就可以滿足一般性能的分佈式搜索。對於solr和分佈式搜索的話題後續再聊。

    擴展閱讀:
    java的hashmap隨着數據量的增加也會出現map調整的問題,必要的時候就初始化足夠大的size以防止容量不足對已有數據進行重新hash計算。

    疫苗:Java HashMap的死循環 http://coolshell.cn/articles/9606.html
    一致性哈希算法的優化—-關於如何保正在環中增加新節點時,命中率不受影響 (原拍拍同事scott)http://scottina.iteye.com/blog/650380

    語言實現:
    http://weblogs.java.net/blog/2007/11/27/consistent-hashing java 版本的例子
    http://blog.csdn.net/mayongzhan/archive/2009/06/25/4298834.aspx PHP 版的例子
    http://www.codeproject.com/KB/recipes/lib-conhash.aspx C語言版本例子

    發佈於 3個月前, 閱讀(150) | 評論(1) | 投票(0) | 收藏(21) 閱讀全文...
  • 162013-10

    1)首先在${tomcat目錄}/conf/Catalina/localhost 創建兩個solr的配置文件。

       可以命名爲solr.xml(主服務器配置)內容爲:

     <Context docBase="F:/apache-solr-1.4.0/dist/apache-solr-1.4.0.war" reloadable="true" >  
         <Environment name="solr/home" type="java.lang.String" value="F:/apache-solr-1.4.0/example/solr" override="true" />  
     </Context> 

    slaver_solr.xml (從服務器配置)內容爲:

     <Context docBase="F:/apache-solr-1.4.0/dist/apache-solr-1.4.0.war" reloadable="true" >  
         <Environment name="solr/home" type="java.lang.String" value="F:/solr分佈式/solr" override="true" />  
     </Context> 

     

    可以看到兩個配置所引用的後臺管理是同一個目錄的,但這個沒關係,只要solr/home的不一樣就行了,接着看主從服務器上solr/home的配置有什麼不一樣。主要是在solr/home/conf/solrconfig.xml上配置不一樣的,其它配置可以互相拷貝。

     

    主要不同的地方爲如下:

     

    從服務器的配置

     

    <requestHandler name="/replication" class="solr.ReplicationHandler" >
        <lst name="slave">

    <!--主服務器的url-->


          <str name="masterUrl">http://localhost:8080/solr/replication</str>

    <!--定時去請求主服務器,查看索引是否有改變-->
          <str name="pollInterval">00:00:60</str>
        </lst>
    </requestHandler>

     

    主服務器的配置

     


    <requestHandler name="/replication" class="solr.ReplicationHandler" >
        <lst name="master">
          <str name="replicateAfter">commit</str>
          <str name="replicateAfter">startup</str>
          <str name="confFiles">schema.xml,stopwords.txt</str>
        </lst>

    </requestHandler>

     

    大概這樣的。啓動 tomcat看看吧。。主服務器建立索引後,從服務器會請求將索引拷貝到從服務器中。

    發佈於 3個月前, 閱讀(54) | 評論(0) | 投票(0) | 收藏(0) 閱讀全文...
  • 162013-04
    時間過得很快,來淘寶已經兩個月了,在這兩個月的時間裏,自己也感受頗深。下面就結合淘寶目前的一些底層技術框架以及自己的一些感觸來說說如何構建一個可伸縮,高性能,高可用性的分佈式互聯網應用。

      一應用無狀態淘寶session框架

      俗話說,一個系統的伸縮性的好壞取決於應用的狀態如何管理。爲什麼這麼說呢?咱們試想一下,假如我們在session中保存了大量與客戶端的狀態信息的話,那麼當保存狀態信息的server宕機的時候,我們怎麼辦?通常來說,我們都是通過集羣來解決這個問題,而通常所說的集羣,不僅有負載均衡,更重要的是要有失效恢復failover,比如tomcat採用的集羣節點廣播複製,jboss採用的配對複製等session狀態複製策略,但是集羣中的狀態恢復也有其缺點,那就是嚴重影響了系統的伸縮性,系統不能通過增加更多的機器來達到良好的水平伸縮,因爲集羣節點間session的通信會隨着節點的增多而開銷增大,因此要想做到應用本身的伸縮性,我們需要保證應用的無狀態性,這樣集羣中的各個節點來說都是相同的,從而是的系統更好的水平伸縮。

      OK,上面說了無狀態的重要性,那麼具體如何實現無狀態呢?此時一個session框架就會發揮作用了。幸運的是淘寶已經具有了此類框架。淘寶的session框架採用的是client cookie實現,主要將狀態保存到了cookie裏面,這樣就使得應用節點本身不需要保存任何狀態信息,這樣在系統用戶變多的時候,就可以通過增加更多的應用節點來達到水平擴展的目的.但是採用客戶端cookie的方式來保存狀態也會遇到限制,比如每個cookie一般不能超過4K的大小,同時很多瀏覽器都限制一個站點最多保存20個cookie.淘寶cookie框架採用的是“多值cookie”,就是一個組合鍵對應多個cookie的值,這樣不僅可以防止cookie數量超過20,同時還節省了cookie存儲有效信息的空間,因爲默認每個cookie都會有大約50個字節的元信息來描述cookie。

      除了淘寶目前的session框架的實現方式以外,其實集中式session管理來完成,說具體點就是多個無狀態的應用節點連接一個session服務器,session服務器將session保存到緩存中,session服務器後端再配有底層持久性數據源,比如數據庫,文件系統等等。

      二有效使用緩存Tair

      做互聯網應用的兄弟應該都清楚,緩存對於一個互聯網應用是多麼的重要,從瀏覽器緩存,反向代理緩存,頁面緩存,局部頁面緩存,對象緩存等等都是緩存應用的場景。

      一般來說緩存根據與應用程序的遠近程度不同可以分爲:local cache和remote cache。一般系統中要麼採用local cache,要麼採用remote cache,兩者混合使用的話對於local cache和remote cache的數據一致性處理會變大比較麻煩.

      在大部分情況下,我們所說到的緩存都是讀緩存,緩存還有另外一個類型:寫緩存.對於一些讀寫比不高,同時對數據安全性需求不高的數據,我們可以將其緩存起來從而減少對底層數據庫的訪問,比如統計商品的訪問次數,統計API的調用量等等,可以採用先寫內存緩存然後延遲持久化到數據庫,這樣可以大大減少對數據庫的寫壓力。

      OK,我以店鋪線的系統爲例,在用戶瀏覽店鋪的時候,比如店鋪介紹,店鋪交流區頁,店鋪服務條款頁面,店鋪試衣間頁面,以及店鋪內搜索界面這些界面更新不是非常頻繁,因此適合放到緩存中,這樣可以大大減低DB的負載。另外寶貝詳情頁面相對也更新比較少,因此也適合放到緩存中來減低DB負載。

      三應用拆分HSF

      首先,在說明應用拆分之前,我們先來回顧一下一個系統從小變大的過程中遇到的一些問題,通過這些問題我們會發現拆分對於構建一個大型系統是如何的重要。

      系統剛上線初期,用戶數並不多,所有的邏輯也許都是放在一個系統中的,所有邏輯跑到一個進程或者一個應用當中,這個時候因爲比較用戶少,系統訪問量低,因此將全部的邏輯都放在一個應用未嘗不可。但是,兄弟們都清楚,好景不長,隨着系統用戶的不斷增加,系統的訪問壓力越來越多,同時隨着系統發展,爲了滿足用戶的需求,原有的系統需要增加新的功能進來,系統變得越來越複雜的時候,我們會發現系統變得越來越難維護,難擴展,同時系統伸縮性和可用性也會受到影響。那麼這個時候我們如何解決這些問題呢?明智的辦法就是拆分這也算是一種解耦,我們需要將原來的系統根據一定的標準,比如業務相關性等分爲不同的子系統,不同的系統負責不同的功能,這樣切分以後,我們可以對單獨的子系統進行擴展和維護,從而提高系統的擴展性和可維護性,同時我們系統的水平伸縮性scale out大大的提升了,因爲我們可以有針對性的對壓力大的子系統進行水平擴展而不會影響到其它的子系統,而不會像拆分以前,每次系統壓力變大的時候,我們都需要對整個大系統進行伸縮,而這樣的成本是比較大的,另外經過切分,子系統與子系統之間的耦合減低了,當某個子系統暫時不可用的時候,整體系統還是可用的,從而整體系統的可用性也大大增強了。

      因此一個大型的互聯網應用,肯定是要經過拆分,因爲只有拆分了,系統的擴展性,維護性,伸縮性,可用性纔會變的更好。但是拆分也給系統帶來了問題,就是子系統之間如何通信的問題,而具體的通信方式有哪些呢?一般有同步通信和異步通信,這裏我們首先來說下同步通信,下面的主題“消息系統”會說到異步通信。既然需要通信,這個時候一個高性能的遠程調用框架就顯得非常總要啦,因此咱們淘寶也有了自己的HSF框架。

      上面所說的都是拆分的好處,但是拆分以後必然的也會帶來新的問題,除了剛纔說的子系統通信問題外,最值得關注的問題就是系統之間的依賴關係,因爲系統多了,系統的依賴關係就會變得複雜,此時就需要更好的去關注拆分標準,比如能否將一些有依賴的系統進行垂直化,使得這些系統的功能儘量的垂直,這也是目前淘寶正在做的系統垂直化,同時一定要注意系統之間的循環依賴,如果出現循環依賴一定要小心,因爲這可能導致系統連鎖啓動失敗。

      OK,既然明白了拆分的重要性,我們看看隨着淘寶的發展,淘寶本身是如何拆分系統的。

      首先我們來看以下這個圖:作者圖片已無法打開,請見諒

      從上面的圖可以看出淘寶系統的一個演變過程,在這個演變的過程中,我們所說的拆分就出現V2.2和V3.0之間。在V2.2版本中,淘寶幾乎所有的邏輯都放在Denali系統中,這樣導致的問題就是系統擴展和修改非常麻煩,並且更加致命的是隨着淘寶業務量的增加,如果按照V2.2的架構已經沒有辦法支撐以後淘寶的快速發展,因此大家決定對整個系統進行拆分,最終V3.0版本的淘寶系統架構圖如下:作者圖片已無法打開,請見諒

      從上圖可以看出V3.0版本的系統對整個系統進行了水平和垂直兩個方向的拆分,水平方向上,按照功能分爲交易,評價,用戶,商品等系統,同樣垂直方向上,劃分爲業務系統,核心業務系統以及以及基礎服務,這樣以來,各個系統都可以獨立維護和獨立的進行水平伸縮,比如交易系統可以在不影響其它系統的情況下獨立的進行水平伸縮以及功能擴展。

      從上面可以看出,一個大型系統要想變得可維護,可擴展,可伸縮,我們必須的對它進行拆分,拆分必然也帶來系統之間如何通信以及系統之間依賴管理等問題,關於通信方面,淘寶目前獨立開發了自己的高性能服務框架HSF,此框架主要解決了淘寶目前所有子系統之間的同步和異步通信目前HSF主要用於同步場合,FutureTask方式的調用場景還比較少。至於系統間的依賴管理,目前淘寶還做的不夠好,這應該也是我們以後努力解決的問題。

      四數據庫拆分TDDL

      在前面“應用拆分”主題中,我們提到了一個大型互聯網應用需要進行良好的拆分,而那裏我們僅僅說了”應用級別”的拆分,其實我們的互聯網應用除了應用級別的拆分以外,還有另外一個很重要的層面就是存儲如何拆分的。因此這個主題主要涉及到如何對存儲系統,通常就是所說的RDBMS進行拆分。

      好了,確定了這個小節的主題之後,我們回顧一下,一個互聯網應用從小變大的過程中遇到的一些問題,通過遇到的問題來引出我們拆分RDBMS的重要性。

      系統剛開始的時候,因系統剛上線,用戶不多,那個時候,所有的數據都放在了同一個數據庫中,這個時候因爲用戶少壓力小,一個數據庫完全可以應付的了,但是隨着運營那些哥們辛苦的吶喊和拼命的推廣以後,突然有一天發現,oh,god,用戶數量突然變多了起來,隨之而來的就是數據庫這哥們受不了,它終於在某一天大家都和愜意的時候掛掉啦。此時,咱們搞技術的哥們,就去看看究竟是啥原因,我們查了查以後,發現原來是數據庫讀取壓力太大了,此時咱們都清楚是到了讀寫分離的時候,這個時候我們會配置一個server爲master節點,然後配幾個salve節點,這樣以來通過讀寫分離,使得讀取數據的壓力分攤到了不同的salve節點上面,系統終於又恢復了正常,開始正常運行了。但是好景還是不長,有一天我們發現master這哥們撐不住了,它負載老高了,汗流浹背,隨時都有翹掉的風險,這個時候就需要咱們垂直分區啦也就是所謂的分庫,比如將商品信息,用戶信息,交易信息分別存儲到不同的數據庫中,同時還可以針對商品信息的庫採用master,salve模式,OK,通過分庫以後,各個按照功能拆分的數據庫寫壓力被分擔到了不同的server上面,這樣數據庫的壓力終於有恢復到正常狀態。但是是不是這樣,我們就可以高枕無憂了呢?NO,這個NO,不是我說的,是前輩們通過經驗總結出來的,隨着用戶量的不斷增加,你會發現系統中的某些表會變的異常龐大,比如好友關係表,店鋪的參數配置表等,這個時候無論是寫入還是讀取這些表的數據,對數據庫來說都是一個很耗費精力的事情,因此此時就需要我們進行“水平分區”了這就是俗話說的分表,或者說sharding.

      OK,上面說了一大堆,無非就是告訴大家一個事實“數據庫是系統中最不容易scale out的一層”,一個大型的互聯網應用必然會經過一個從單一DB server,到Master/salve,再到垂直分區分庫,然後再到水平分區分表,sharding的過程,而在這個過程中,Master/salve以及垂直分區相對比較容易,應用的影響也不是很大,但是分表會引起一些棘手的問題,比如不能跨越多個分區join查詢數據,如何平衡各個shards的負載等等,這個時候就需要一個通用的DAL框架來屏蔽底層數據存儲對應用邏輯的影響,使得底層數據的訪問對應用透明化。

      拿淘寶目前的情況來說,淘寶目前也正在從昂貴的高端存儲小型機+ORACLE切換到MYSQL,切換到MYSQL以後,勢必會遇到垂直分區分庫以及水平分區Sharding的問題,因此目前淘寶根據自己的業務特點也開發了自己的TDDL框架,此框架主要解決了分庫分表對應用的透明化以及異構數據庫之間的數據複製

      五異步通信Notify

      在”遠程調用框架”的介紹中,我們說了一個大型的系統爲了擴展性和伸縮性方面的需求,肯定是要進行拆分,但是拆分了以後,子系統之間如何通信就成了我們首要的問題,在”遠程調用框架”小節中,我們說了同步通信在一個大型分佈式系統中的應用,那麼這一小節我們就來說說異步通信.好了,既然說到了異步通信,那麼”消息中間件”就要登場了,採用異步通信這其實也是關係到系統的伸縮性,以及最大化的對各個子系統進行解耦.

      說到異步通信,我們需要關注的一點是這裏的異步一定是根據業務特點來的,一定是針對業務的異步,通常適合異步的場合是一些鬆耦合的通信場合,而對於本身業務上關聯度比較大的業務系統之間,我們還是要採用同步通信比較靠譜。

      OK,那麼下一步我們說說異步能給系統帶來什麼樣子的好處。首先我們想想,假如系統有A和B兩個子系統構成,假如A和B是同步通信的話,那麼要想使得系統整體伸縮性提高必須同時對A和B進行伸縮,這就影響了對整個系統進行scale out.其次,同步調用還會影響到可用性,從數學推理的角度來說,A同步調用B,如果A可用,那麼B可用,逆否命題就是如果B不可用,那麼A也不可用,這將大大影響到系統可用性,再次,系統之間異步通信以後可以大大提高系統的響應時間,使得每個請求的響應時間變短,從而提高用戶體驗,因此異步在提高了系統的伸縮性以及可用性的同時,也大大的增強了請求的響應時間當然了,請求的總體處理時間也許不會變少。

      下面我們就以淘寶的業務來看看異步在淘寶的具體應用。交易系統會與很多其它的業務系統交互,如果在一次交易過程中採用同步調用的話,這就要求要向交易成功,必須依賴的所有系統都可用,而如果採用異步通信以後,交易系統藉助於消息中間件Notify和其它的系統進行了解耦,這樣以來當其它的系統不可用的時候,也不會影響到某此交易,從而提高了系統的可用性。

      最後,關於異步方面的討論,我可以推薦大家一些資源:

      1 . J2EE meets web2.0

      2. Ebay架構特點HPTS 2009

      六非結構化數據存儲 TFS,NOSQL

      在一個大型的互聯網應用當中,我們會發現並不是所有的數據都是結構化的,比如一些配置文件,一個用戶對應的動態,以及一次交易的快照等信息,這些信息一般不適合保存到RDBMS中,它們更符合一種Key-value的結構,另外還有一類數據,數據量非常的大,但是實時性要求不高,此時這些數據也需要通過另外的一種存儲方式進行存儲,另外一些靜態文件,比如各個商品的圖片,商品描述等信息,這些信息因爲比較大,放入RDBMS會引起讀取性能問題,從而影響到其它的數據讀取性能,因此這些信息也需要和其它信息分開存儲,而一般的互聯網應用系統都會選擇把這些信息保存到分佈式文件系統中,因此淘寶目前也開發了自己的分佈式文件系統TFS,TFS目前限制了文件大小爲2M,適合於一些小於2M數據的存放。

      隨着互聯網發展,業界從08年下半年開始逐漸流行了一個概念就是NOSQL。我們都知道根據CAP理論,一致性,可用性和分區容錯性3者不能同時滿足,最多隻能同時滿足兩個,我們傳統的關係數據採用了ACID的事務策略,而ACID的事務策略更加講究的是一種高一致性而降低了可用性的需求,但是互聯網應用往往對可用性的要求要略高於一致性的需求,這個時候我們就需要避免採用數據的ACID事務策略,轉而採用BASE事務策略,BASE事務策略是基本可用性,事務軟狀態以及最終一致性的縮寫,通過BASE事務策略,我們可以通過最終一致性來提升系統的可用性,這也是目前很多NOSQL產品所採用的策略,包括facebook的cassandra,apache hbase,google bigtable等,這些產品非常適合一些非結構化的數據,比如key-value形式的數據存儲,並且這些產品有個很好的優點就是水平伸縮性。目前淘寶也在研究和使用一些成熟的NOSQL產品。

      七監控、預警系統

      對於大型的系統來說,唯一可靠的就是系統的各個部分是不可靠。

      因爲一個大型的分佈式系統中勢必會涉及到各種各樣的設備,比如網絡交換機,普通PC機,各種型號的網卡,硬盤,內存等等,而這些東東都在數量非常多的時候,出現錯誤的概率也會變大,因此我們需要時時刻刻監控系統的狀態,而監控也有粒度的粗細之分,粒度粗一點的話,我們需要對整個應用系統進行監控,比如目前的系統網絡流量是多少,內存利用率是多少,IO,CPU的負載是多少,服務的訪問壓力是多少,服務的響應時間是多少等這一系列的監控,而細粒度一點的話,我們就需對比如應用中的某個功能,某個URL的訪問量是多,每個頁面的PV是多少,頁面每天佔用的帶寬是多少,頁面渲染時間是多少,靜態資源比如圖片每天佔用的帶寬是多少等等進行進一步細粒度的監控。因此一個監控系統就變得必不可少了。

      前面說了一個監控系統的重要性,有了監控系統以後,更重要的是要和預警系統結合起來,比如當某個頁面訪問量增多的時候,系統能自動預警,某臺Server的CPU和內存佔用率突然變大的時候,系統也能自動預警,當併發請求丟失嚴重的時候,系統也能自動預警等等,這樣以來通過監控系統和預警系統的結合可以使得我們能快速響應系統出現的問題,提高系統的穩定性和可用性。

      八配置統一管理

      一個大型的分佈式應用,一般都是有很多節點構成的,如果每次一個新的節點加入都要更改其它節點的配置,或者每次刪除一個節點也要更改配置的話,這樣不僅不利於系統的維護和管理,同時也更加容易引入錯誤。另外很多時候集羣中的很多系統的配置都是一樣的,如果不進行統一的配置管理,就需要再所有的系統上維護一份配置,這樣會造成配置的管理維護很麻煩,而通過一個統一的配置管理可以使得這些問題得到很好的解決,當有新的節點加入或者刪除的時候,配置管理系統可以通知各個節點更新配置,從而達到所有節點的配置一致性,這樣既方便也不會出錯。(編選:中國電子商務研究中心 勇全)

    發佈於 9個月前, 閱讀(89) | 評論(1) | 投票(0) | 收藏(1) 閱讀全文...
  • 262013-03

    基於HTTP協議的Web API是時下最爲流行的一種分佈式服務提供方式。無論是在大型互聯網應用還是企業級架構中,我們都見到了越來越多SOA或RESTful的Web API。爲什麼Web API如此流行呢?我認爲很大程度上應歸功於簡單有效的HTTP協議。HTTP協議是一種分佈式的面向資源的網絡應用層協議無論是服務器端提供Web服務,還是客戶端消費Web服務都非常簡單。再加上瀏覽器、Javascript、AJAX、JSON以及HTML5等技術和工具的發展,互聯網應用架構設計表現出了從傳統的PHP、JSP、ASP.NET等服務器端動態網頁向Web API + RIA(富互聯網應用)過渡的趨勢。Web API專注於提供業務服務,RIA專注於用戶界面和交互設計,從此兩個領域的分工更加明晰。在這種趨勢下,Web API設計將成爲服務器端程序員的必修課。然而,正如簡單的Java語言並不意味着高質量的Java程序,簡單的HTTP協議也不意味着高質量的Web API要想設計出高質量的Web API,還需要深入理解分佈式系統及HTTP協議的特性。

     

    冪等性定義

    本文所要探討的正是HTTP協議涉及到的一種重要性質:冪等性(Idempotence)。在HTTP/1.1規範中冪等性的定義是:

    Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request.

    從定義上看,HTTP方法的冪等性是指一次和多次請求某一個資源應該具有同樣的副作用。冪等性屬於語義範疇,正如編譯器只能幫助檢查語法錯誤一樣,HTTP規範也沒有辦法通過消息格式等語法手段來定義它,這可能是它不太受到重視的原因之一。但實際上,冪等性是分佈式系統設計中十分重要概念,而HTTP的分佈式本質也決定了它在HTTP中具有重要地位。

     

    分佈式事務 vs 冪等設計

    爲什麼需要冪等性呢?我們先從一個例子說起,假設有一個從賬戶取錢的遠程API(可以是HTTP的,也可以不是),我們暫時用類函數的方式記爲: 

    bool withdraw(account_id, amount)

    withdraw的語義是從account_id對應的賬戶中扣除amount數額的錢;如果扣除成功則返回true,賬戶餘額減少amount;如果扣除失敗則返回false,賬戶餘額不變。值得注意的是:和本地環境相比,我們不能輕易假設分佈式環境的可靠性。一種典型的情況是withdraw請求已經被服務器端正確處理,但服務器端的返回結果由於網絡等原因被掉丟了,導致客戶端無法得知處理結果。如果是在網頁上,一些不恰當的設計可能會使用戶認爲上一次操作失敗了,然後刷新頁面,這就導致了withdraw被調用兩次,賬戶也被多扣了一次錢。如圖1所示:

    non-idemponent

    圖1

    這個問題的解決方案一是採用分佈式事務,通過引入支持分佈式事務的中間件來保證withdraw功能的事務性。分佈式事務的優點是對於調用者很簡單,複雜性都交給了中間件來管理。缺點則是一方面架構太重量級,容易被綁在特定的中間件上,不利於異構系統的集成;另一方面分佈式事務雖然能保證事務的ACID性質,而但卻無法提供性能和可用性的保證。

    另一種更輕量級的解決方案是冪等設計。我們可以通過一些技巧把withdraw變成冪等的,比如:

    int create_ticket() 

    bool idempotent_withdraw(ticket_id, account_id, amount)

    create_ticket的語義是獲取一個服務器端生成的唯一的處理號ticket_id,它將用於標識後續的操作。idempotent_withdraw和withdraw的區別在於關聯了一個ticket_id,一個ticket_id表示的操作至多隻會被處理一次,每次調用都將返回第一次調用時的處理結果。這樣,idempotent_withdraw就符合冪等性了,客戶端就可以放心地多次調用。

    基於冪等性的解決方案中一個完整的取錢流程被分解成了兩個步驟:1.調用create_ticket()獲取ticket_id;2.調用idempotent_withdraw(ticket_id, account_id, amount)。雖然create_ticket不是冪等的,但在這種設計下,它對系統狀態的影響可以忽略,加上idempotent_withdraw是冪等的,所以任何一步由於網絡等原因失敗或超時,客戶端都可以重試,直到獲得結果。如圖2所示:

    image

    圖2

    和分佈式事務相比,冪等設計的優勢在於它的輕量級,容易適應異構環境,以及性能和可用性方面。在某些性能要求比較高的應用,冪等設計往往是唯一的選擇。

     

    HTTP的冪等性

    HTTP協議本身是一種面向資源的應用層協議,但對HTTP協議的使用實際上存在着兩種不同的方式:一種是RESTful的,它把HTTP當成應用層協議,比較忠實地遵守了HTTP協議的各種規定;另一種是SOA的,它並沒有完全把HTTP當成應用層協議,而是把HTTP協議作爲了傳輸層協議,然後在HTTP之上建立了自己的應用層協議。本文所討論的HTTP冪等性主要針對RESTful風格的,不過正如上一節所看到的那樣,冪等性並不屬於特定的協議,它是分佈式系統的一種特性;所以,不論是SOA還是RESTful的Web API設計都應該考慮冪等性。下面將介紹HTTP GET、DELETE、PUT、POST四種主要方法的語義和冪等性。

    HTTP GET方法用於獲取資源,不應有副作用,所以是冪等的。比如:GET http://www.bank.com/account/123456,不會改變資源的狀態,不論調用一次還是N次都沒有副作用。請注意,這裏強調的是一次和N次具有相同的副作用,而不是每次GET的結果相同。GET http://www.news.com/latest-news這個HTTP請求可能會每次得到不同的結果,但它本身並沒有產生任何副作用,因而是滿足冪等性的。

    HTTP DELETE方法用於刪除資源,有副作用,但它應該滿足冪等性。比如:DELETE http://www.forum.com/article/4231,調用一次和N次對系統產生的副作用是相同的,即刪掉id爲4231的帖子;因此,調用者可以多次調用或刷新頁面而不必擔心引起錯誤。

    比較容易混淆的是HTTP POST和PUT。POST和PUT的區別容易被簡單地誤認爲“POST表示創建資源,PUT表示更新資源”;而實際上,二者均可用於創建資源,更爲本質的差別是在冪等性方面。在HTTP規範中對POST和PUT是這樣定義的:

    The POST method is used to request that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line. ...... If a resource has been created on the origin server, the response SHOULD be 201 (Created) and contain an entity which describes the status of the request and refers to the new resource, and a Location header.

    The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server. If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI.

    POST所對應的URI並非創建的資源本身,而是資源的接收者。比如:POST http://www.forum.com/articles的語義是在http://www.forum.com/articles下創建一篇帖子,HTTP響應中應包含帖子的創建狀態以及帖子的URI。兩次相同的POST請求會在服務器端創建兩份資源,它們具有不同的URI;所以,POST方法不具備冪等性。而PUT所對應的URI是要創建或更新的資源本身。比如:PUT http://www.forum/articles/4231的語義是創建或更新ID爲4231的帖子。對同一URI進行多次PUT的副作用和一次PUT是相同的;因此,PUT方法具有冪等性。

    在介紹了幾種操作的語義和冪等性之後,我們來看看如何通過Web API的形式實現前面所提到的取款功能。很簡單,用POST /tickets來實現create_ticket;用PUT /accounts/account_id/ticket_id&amount=xxx來實現idempotent_withdraw。值得注意的是嚴格來講amount參數不應該作爲URI的一部分,真正的URI應該是/accounts/account_id/ticket_id,而amount應該放在請求的body中。這種模式可以應用於很多場合,比如:論壇網站中防止意外的重複發帖。

     

    總結

    上面簡單介紹了冪等性的概念,用冪等設計取代分佈式事務的方法,以及HTTP主要方法的語義和冪等性特徵。其實,如果要追根溯源,冪等性是數學中的一個概念,表達的是N次變換與1次變換的結果相同,有興趣的讀者可以從Wikipedia上進一步瞭解。

     

    參考

    RFC 2616, Hypertext Transfer Protocol -- HTTP/1.1, Method Definitions

    The Importance of Idempotence

    stackoverflow -  PUT vs POST in REST

    發佈於 9個月前, 閱讀(9) | 評論(0) | 投票(0) | 收藏(0) 閱讀全文...
  • 292012-11
    摘要:HBTC 2012(Hadoop&BigData Technology Conference 2012)即將召開,爲了讓讀者可以提前瞭解一下目前國內各個公司在Hadoop和大數據方面的運用,CSDN於會前對演講嘉賓進行了採訪。本期採訪了阿里巴巴的代志遠,他給我們提前分享了一下HBase在阿里巴巴海量數據部門的實踐。

    【CSDN報道】代志遠早年就職網易研究院從事MapReduce與DFS系統的自主研發,後加入支付寶數據平臺負責Hadoop與HBase體系的架構設計與二次研發,支付寶流計算與分佈式搜索系統的設計和研發,後成爲支付寶海量計算體系架構師兼支付寶三代架構成員。現就轉戰於阿里巴巴集團-CDO-海量數據部門,負責創新性項目的研究和跟進,目前專注於Google第二代數據庫產品MegaStore的研究和在阿里的落地。

    在即將召開的HBTC大會中,我們有幸邀請到代志遠作爲我們的演講嘉賓,請他分享下阿里巴巴在海量數據分佈式數據庫領域的探索。我們也對他提前做了郵件採訪,讓用戶可以更快地瞭解阿里巴巴海量數據分佈式數據庫以及在Hadoop應用領域的實踐。

    阿里巴巴海量數據部門: 代志遠

    CSDN: Hadoop目前是大數據處理領域的王者,你認爲中小企業應用Hadoop的瓶頸在哪裏?

    代志遠:首先因爲Hadoop本身機制複雜,所依賴的參數配置頗多,並且Hadoop需要像數據庫一樣穩定,滿足性能的運行,就需要運維人員如同DBA一樣要懂網絡、磁盤、內核以及其他一些硬件知識,這對於運維人員的要求是比較高的。其次Hadoop社區蓬勃發展,生態圈不斷擴大,用戶不斷增多,規模極限也不斷突破,這就促使了Hadoop的架構和代碼發展非常快而且變更也比較快,正因爲如此,系統在快速發展的時候容易引入很多的Bug和一些缺陷(可能因爲稍稍的使用不當或比較小的問題就引起整體性能和穩定性的波動)。更重要的是,Hadoop代碼複雜,而且需要與社區接軌,能夠找到對Hadoop源碼熟悉並能優化升級和bugfix的人才是很難的,這對於一個公司的研發來說是個很大的挑戰。最後一點是公司的認知,除了類似Cloudera、MapR之類的軟件公司需要對軟件技術負責,其他多數公司無論大中小都依賴於公司業務,尤其中小公司業務壓力大、人員緊張,能夠從業務研發人員中抽調或通過其他方式組建專有的Hadoop運維團隊甚至是研發團隊,從公司規劃與發展上來說是比較困難的事情。

    CSDN: Hadoop的本質是爲全量而生,就是說它重吞吐量,響應時間完全沒有保障,那麼對於像淘寶、天貓在“雙11”活動搶購的時候,需要實時處理數據(可能是毫秒級,秒級的響應),是如何進行實現的?

    代志遠:Hadoop是離線計算平臺,其中包括分佈式文件系統(HDFS)和分佈式計算(MapReduce),這本身是無法對響應時間做保證的。但是目前在Hadoop之上的生態系統越來越完善,其中HBase就是支持海量數據、高併發的在線數據庫,應對這種場景就非常適合。HBase在這次雙十一中與MySQL等在線數據庫共同作爲線上庫使用,承擔了重要的責任,並創下了並在全天高壓力之下無故障的佳績。另外非Hadoop生態圈的流式計算框架Storm、S4也同樣可以爲實時計算分擔一定的壓力。

    CSDN: 你在雲計算大會時做的一場有關HBase的報告,主要講如何用HBase替代MySQL,HBase對比MySQL的優勢在哪裏?

    代志遠:準確來說是HBase替換MySQL的一部分應用,這些應用自然是要符合HBase的應用場景(與MySQL對比),比如數據量大、對線性拓展有需求、對自動化運維(負載均衡)有要求而且應用模式簡單。在支付寶中因其增長速度快,業務量大,造成了很多應用都是數據量龐大而且速度增長快,因此有一些應用迫切需要一個數據庫能夠支撐現在的業務而降低對關係型的需求,所以嘗試了HBase的解決方案。

    CSDN: 阿里巴巴在部署Hadoop的過程中有哪些比較好的經驗可以跟技術人員分享?

    代志遠:最重要的是要有一個完善團隊,健全的流程。

    • 集羣越來越大,要樹立以集羣穩定性和性能爲要領的工作思路。
    • 現在進入Hadoop應用開發領域的人變多,但本身知識因其入行早晚而積累不同,無法對集羣的穩定性負責,常常會寫出跑死集羣的任務(數據庫中SQL使用不善也常會如此)。因此要有一個較好的管理流程約束開發人員做到責任分明,以便促使應用開發不僅要對自己的任務負責還要對集羣負責,不斷學習和檢查減少故障的產生。
    • 要有一個好的運維團隊,懂硬件、重流程、負責任。
    • 公司在資源和戰略上應有所傾斜,重視研發人員加強在研發的投入,畢竟分佈式系統的入行門檻相比應用開發的技術門檻要高,當然有好的應用架構師能夠取長補短規避大多數問題也是可行的,但單一系統的穩定性還是需要靠人來保證。

    CSDN: 請您簡要介紹一下本次HBTC2012大會上的議題的內容。

    代志遠:06年Google發表論文Bigtable,社區隨之出現HBase,後Google 08年發表第二代數據庫產品MegaStore至今未有社區同類產品出現,現今Google又出現新一代數據庫理論Spanner和F1。 而最近幾年隨之Bigtable和NoSQL的興起,社區產品HBase逐步走向NoSQL系統的主流產品,優勢明顯然而缺點也明顯,大數據平臺下的業務由SQL向NoSQL的遷移比較複雜而應用人員學習成本頗高,並且無法支持事務和多維索引,使得許多業務無法享用來自NoSQL系統中線性拓展能力。

    Google內部MegaStore就作爲Bigtable的一個補充而出現,在Bigtable的上層支持了SQL,事務、索引、跨機房災備,併成爲大名鼎鼎的Gmail、Google App Engine、Android Market的底層存儲。因此我們決定以MegaStore爲理論模型進行探索如何在HBase系統上不犧牲線性拓展能力,同時又能提供跨行事務、索引、SQL的功能。

    HBase系統故障恢復的優化實踐

    其實在第四屆中國雲計算大會上,當時還在支付寶數據平臺的架構師代志遠就爲大家帶來了題爲“HBase系統故障恢復的優化實踐分享”的精彩演講,他分析了支付寶海量數據在線處理的現狀,以HBase解決方案取代傳統MySQL解決方案的技術歷程,並詳盡分享了Region Server的宕機恢復流程(閱讀全文)。

    在Hadoop的體系當中,支持實時的一條線,HBase,支持海量數據庫初衷的時候,設計爲了設計萬一級實時數據庫,HBase這個東西經過這幾年的發展,已經逐漸成爲目前業界當中主要的實時數據庫,分佈式數據庫,像支付寶直接上HBase系統,就是考慮到HBase的先進架構,能夠幫助支付寶完成現在很多的海量數據的存儲以及在線隨機讀寫高性能的訪問和存儲。

    不過在HBase的系統當中,體現它的可用性有幾個風險。第一個是HBase本身在底層依賴的HDFS,加載了唯一一塊數據,單臺機器保證一致性,HDFS保持了冗餘。第二點,恢復過程當中,Failover過程非常複雜,這個時間消耗越長,作爲在線系統,這種時間越長可能會影響到在線訪問用戶體驗。第三點它依賴的HDFS,HBase作爲在線數據庫依賴HDFS有故障的,經過幾小時恢復提供生產業務,對業務方沒有直接感受,作爲在線系統如果掛掉,如果需要經過近小時恢復時間,恐怕就會直接收到自於支付寶外部的用戶投訴了。HBase目前它自己的監控體系尚不完善,目前的監控力度非常得粗,只能監控到單臺的Region Server的情況,看不到當前用戶表有多少讀寫比例,看不到當前服務結點寫作量多少,讀出量多少。

    Region Server在恢復過程當中有幾個流程這個流程很複雜,流程非常非常多,以當前的系統規模,它凸顯出來的問題,這幾個流程是影響到它的恢復速度的關鍵流程。等待時間週期非常長,週期之所以比較長,是因爲現在的機器發展速度非常得快,每臺機器從兩個G到8個G,96G,140G的大層次的機器,Java語言實現了系統當中大內存管理本身存在問題,除非革新這門語言,否則別無他法。如果說在設計的參數不合理,就可能會導致一個問題,有可能這臺服務器就會停止運行,發生這麼一次情況就非常可怕,幾十G的內存這個過程需要幾十秒甚至上分鐘,通常情況下,我們會設置到3分鐘,這就意味着,爲了避免出現這種問題,就會同時引入新的問題,宕機之後恢復等待時間需要三分鐘。第二個關鍵流程當中,當它感知到已經掛掉了,在線數據庫協助WL數據重新做到存儲當中去,以保證實時更新是同步,否則這個數據庫肯定要丟出去,重做數據過程當中,會有一個過程,Split Hlog,跟當前數據量有關係,Edit Log數據又比較多,大家在業餘時間可以進行測試,數據不以支付寶的爲準,以當前數據系統大小爲準。

    第三個關鍵流程,重做完數據之後,這部分重新上線,上線之前進行數據進行二次掃描,告訴系統,Region怎麼加入到Region Server當中去,掃描也存在問題,問題可能引發到兩分鐘到6分鐘,這也跟當前系統數據有關。第四部分,這個過程稱之爲再次上線的過程,這個再次上線,上線時間跟當前這臺機器的Region上線有關係。支付寶面對消費記錄查詢,用戶查不出來數據,15分鐘之後才能查到,在面臨在線問題上這是非常可怕的事情。

    針對Region Server這一關鍵流程,做了一些優化。這個優化正是提到關鍵流程第一點,在判斷宕機超市的情況下,不強依賴於Zookeeper,支付寶又啓動了監控進程Mirror Process,每一臺,Region Server當中都會起到PID存不存在,這種檢查並非完全可靠,當檢查PID不存在,就有理由認爲已經掛掉了,要進行可靠檢查,通常DBA在線判斷數據庫是否可用,通常會用PIng連續服務端口,這就彌補了系動中的調用命令不可靠的事情。最後當發現服務端口不可用時,有理由認爲當前進程已經死掉了,死掉了之後,那麼就按照現有邏輯刪除結點,這三分鐘的時間就完全省略掉了。(整理/@CSDN王鵬,審校/包研)

    11月30日-12月1日,北京新雲南皇冠假日酒店,業內將迎來國內大數據領域最純粹的技術盛會——HBTC 2012(Hadoop&BigData Technology Conference 2012)。Hadoop及雲計算生態系統的力量齊聚北京,歡迎熱愛開源的朋友們加入!報名網址參見HBTC 2012

    發佈於 1年前, 閱讀(112) | 評論(0) | 投票(0) | 收藏(2) 閱讀全文...
  • 292012-11

    在前面三篇文章中,介紹了關於分佈式系統中數據一致性的問題,這一篇主要介紹CAP定理以及自己對CAP定理的瞭解。

    CAP定理是2000年,由 Eric Brewer 提出來的

    Brewer認爲在分佈式的環境下設計和部署系統時,有3個核心的需求,以一種特殊的關係存在。這裏的分佈式系統說的是在物理上分佈的系統,比如我們常見的web系統。

    這3個核心的需求是:ConsistencyAvailabilityPartition Tolerance,賦予了該理論另外一個名字 - CAP

    Consistency:一致性,這個和數據庫ACID的一致性類似,但這裏關注的所有數據節點上的數據一致性和正確性,而數據庫的ACID關注的是在在一個事務內,對數據的一些約束。

    Availability:可用性,關注的在某個結點的數據是否可用,可以認爲某一個節點的系統是否可用,通信故障除外。

    Partition Tolerance:分區容忍性,是否可以對數據進行分區。這是考慮到性能和可伸縮性。

    爲什麼不能完全保證這個三點了,個人覺得主要是因爲一旦進行分區了,就說明了必須節點之間必須進行通信,涉及到通信,就無法確保在有限的時間內完成指定的行文,如果要求兩個操作之間要完整的進行,因爲涉及到通信,肯定存在某一個時刻只完成一部分的業務操作,在通信完成的這一段時間內,數據就是不一致性的。如果要求保證一致性,那麼就必須在通信完成這一段時間內保護數據,使得任何訪問這些數據的操作不可用。

    如果想保證一致性和可用性,那麼數據就不能夠分區。一個簡單的理解就是所有的數據就必須存放在一個數據庫裏面,不能進行數據庫拆分。這個對於大數據量,高併發的互聯網應用來說,是不可接受的。

     

    我們可以拿一個簡單的例子來說明:假設一個購物系統,賣家A和賣家B做了一筆交易100元,交易成功了,買家把錢給賣家。

    這裏面存在兩張表的數據:Trade表Account表 ,涉及到三條數據Trade(100),Account A ,Account B

    假設 trade表和account表在一個數據庫,那麼只需要使用數據庫的事務,就可以保證一致性,同時不會影響可用性。但是隨着交易量越來越大,我們可以考慮按照業務分庫,把交易庫和account庫單獨分開,這樣就涉及到trade庫和account庫進行通信,也就是存在了分區,那麼我們就不可能同時保證可用性和一致性。

    我們假設初始狀態

    trade(buyer,seller,tradeNo,status) = trade(A,B,20121001,I)

    account(accountNo,balance) = account(A,300)

    account(accountNo,balance) = account(B,10)

    在理想情況下,我們期望的狀態是

    trade(buyer,seller,tradeNo,status) = trade(A,B,20121001,S)

    account(accountNo,balance) = account(A,200)

    account(accountNo,balance) = account(B,110)

     

    但是考慮到一些異常情況

    假設在trade(20121001,S)更新完成之前,帳戶A進行扣款之後,帳戶A進行了另外一筆300款錢的交易,把錢消費了,那麼就存在一個狀態

    trade(buyer,seller,tradeNo,status) = trade(A,B,20121001,S)

    account(accountNo,balance) = account(A,0)

    account(accountNo,balance) = account(B,10)

    產生了數據不一致的狀態

     

    由於這個涉及到資金上的問題,對資金要求比較高,我們必須保證一致性,那麼怎麼辦,只能在進行trade(A,B,20121001)交易的時候,對於任何A的後續交易請求trade(A,X,X),必須等到A完成之後,才能夠進行處理,也就是說在進行trade(A,B,20121001)的時候,Account(A)的數據是不可用的。

     

    任何架構師在設計分佈式的系統的時候,都必須在這三者之間進行取捨。首先就是是否選擇分區,由於在一個數據分區內,根據數據庫的ACID特性,是可以保證一致性的,不會存在可用性和一致性的問題,唯一需要考慮的就是性能問題。對於可用性和一致性,大多數應用就必須保證可用性,畢竟是互聯網應用,犧牲了可用性,相當於間接的影響了用戶體驗,而唯一可以考慮就是一致性了。

     

    犧牲一致性

    對於犧牲一致性的情況最多的就是緩存和數據庫的數據同步問題,我們把緩存看做一個數據分區節點,數據庫看作另外一個節點,這兩個節點之間的數據在任何時刻都無法保證一致性的。在web2.0這樣的業務,開心網來舉例子,訪問一個用戶的信息的時候,可以先訪問緩存的數據,但是如果用戶修改了自己的一些信息,首先修改的是數據庫,然後在通知緩存進行更新,這段期間內就會導致的數據不一致,用戶可能訪問的是一個過期的緩存,而不是最新的數據。但是由於這些業務對一致性的要求比較高,不會帶來太大的影響。

     

    異常錯誤檢測和補償

    還有一種犧牲一致性的方法就是通過一種錯誤補償機制來進行,可以拿上面購物的例子來說,假設我們把業務邏輯順序調整一下,先扣買家錢,然後更新交易狀態,在把錢打給賣家

    我們假設初始狀態

    account(accountNo,balance) = account(A,300)

    account(accountNo,balance) = account(B,10)

    trade(buyer,seller,tradeNo,status) = trade(A,B,20121001,I)

     

    那麼有可能出現

    account(accountNo,balance) = account(A,200)

    trade(buyer,seller,tradeNo,status) = trade(A,B,20121001,S)

    account(accountNo,balance) = account(B,10)

     

    那麼就出現了A扣款成功,交易狀態也成功了,但是錢沒有打給B,這個時候可以通過一個時候的異常恢復機制,把錢打給B,最終的情況保證了一致性,在一定時間內數據可能是不一致的,但是不會影響太大。

     

    兩階段提交協議

    當然,還有一種方式就是我另外一篇文章裏面《X/Open DTP-分佈式事務模型》裏面說的,但是再第一階段和第二階段之間,數據也可不能是一致性的,也可能出現同樣的情況導致異常。而且DTP的分佈式事務模型 限制太多,例如必須有實現其功能的相關的容器支持,並且資源管理器也必須實現了XA規範。限制比較多。

     

    國外有的架構師有兩種方案去解決CAP的限制,但是也是比較適合特定的業務,而沒有通用的解決方案,

    探知分區->分區內操作->事後補償

    就是上面介紹的異常檢測恢復機制,這種機制其實還是有限制,

    首先對於分區檢測操作,不同的業務涉及到的分區操作可能不一樣

    分區內操作限制:不同的業務對應的約束不一致

    事後補償:由於業務約束不一樣,補償方式也不一樣。

    所以這隻能作爲一種思想,不能做一個通用的解決方案

     

     

    轉載自:http://www.cnblogs.com/aigongsi/archive/2012/10/15/2721366.html

    發佈於 1年前, 閱讀(69) | 評論(0) | 投票(0) | 收藏(0) 閱讀全文...
  • 292012-11
    關於分佈式系統的數據一致性問題(三)

    在我的博文裏面 關於分佈式系統的數據一致性問題(二) 裏面主要介紹了數據分佈的情況下保證一致性的情況,在第二篇文章裏面,我這裏提出了三個問題

    1. 訂單系統調用支付系統支付訂單,支付成功,但是返回給訂單系統數據超時,訂單還是I(初始狀態),但是此時會員帳戶餘額100,會員肯定會馬上找京東罵京東,爲啥不給老子發貨,我都付錢了
    2. 訂單系統調用支付系統成功,狀態也已經更新成功,但是通知倉庫發貨失敗,這個時候訂單是P(已支付)狀態,此時會員帳戶餘額是100,但是倉庫不會發貨。會員也要罵京東。
    3. 訂單系統調用支付系統成功,狀態也已經更新成功,然後通知倉庫發貨,倉庫告訴訂單系統,沒有貨了。這個時候數據狀態和第二種情況一樣。

     

    重點分析解決了第一個的問題以及相應的方案,發現在數據分佈的環境下,很難絕對的保證數據一致性(任何一段區間),但是有辦法通過一種補償機制,最終保證數據的一致性。

     

    在下面在分析一下第二個問題

    • 訂單系統調用支付系統成功,狀態也已經更新成功,但是通知倉庫發貨失敗,這個時候訂單是P(已支付)狀態,此時會員帳戶餘額是100,但是倉庫不會發貨。會員也要罵京東。

    通過在上一篇文章裏面分析過,這個相對來說是比較簡單的,我可以採取重試機制,如果發現通知倉庫發貨失敗,就一致重試,

    這裏面有兩種方式:

    1 異步方式:通過類似MQ(消息通知)的機制,這個是異步的通知

    2 同步調用:類似於遠程過程調用

    對於同步的調用的方式,比較簡單,我們能夠及時獲取結果,對於異步的通知,就必須採用請求,應答的方式進行,這一點在(關於分佈式系統的數據一致性問題(一))裏面有介紹。這裏面就不再闡述。

     

    來看看第三個問題

    • 訂單系統調用支付系統成功,狀態也已經更新成功,然後通知倉庫發貨,倉庫告訴訂單系統,沒有貨了。這個時候數據狀態和第二種情況一樣。

    我覺得這是一個很有意思的問題,我們還是考慮幾種解決的方案

    1 在會員下單的時刻,就告訴倉庫,我要你把貨物留下來,

    2 在會員支付訂單時候,在支付之前檢查倉庫有沒有貨,如果沒有貨,就告知會員木有貨物了

    3 如果會員支付成功,這個時候沒有貨了,就會退款給用戶或者等待有貨的時候在發貨

     

    正常情況,京東的倉庫一般都是有貨的,所以影響到的會員很少,但是在秒殺和營銷的時候,這個時候就不一定了,我們考慮假設倉庫有10臺iphone

    如果採用第一種方案,

    1 在會員下單的時候,相當於庫存就-1,那麼用戶惡意拍下來,沒有去支付,就影響到了其他用戶的購買。京東可以設置一個訂單超時時間,如果這段時間內沒有支付,就自動取消訂單

    2 在會員支付之前,檢查倉庫有貨,這種方案了,對於用戶體驗不好,但是對於京東比較好,至少我東西都賣出去了。那些沒有及時付款的用戶,只能投訴了京東無故取消訂單

    3 第三種方案,這個方案體驗更不好,而且用戶感覺受到京東欺詐,但是對於京東來說,比第二種方案更有益,畢竟我還可以多賣出一點東西。

     

    個人覺得,京東應該會採用第二種或者第三種方式來處理這類情況,我在微博上搜索了 “京東 無故取消訂單”,發現果真和我預料的處理方式。不過至於這裏的無故取消是不是技術上的原因我不知道,如果真的是技術上的原因,我覺得京東可以採用不同的處理方案。對於秒殺和促銷商品,可以考慮第一種方案,大多數人都會直接付款,畢竟便宜啊,如果用戶搶不到便宜的東西,抱怨當然很大了。這樣可以照顧大多數用戶的體驗。對於一般的訂單,可以採用第二種或者第三種方式,這種情況下,發生付款之後倉庫沒有貨的情況會比較少,並且就算髮生了,用戶也會覺得無所謂,大不了退錢嗎,這樣就可以實現自己的利益最大化而最低程度的減少用戶體驗。

     

    而鐵道部在這個問題上,採用的是第一種方案,爲什麼和京東不一樣,就是因爲用戶體驗,如果用戶把票都買了,你告訴我木有票了,旅客會殺人的。哈哈,不過鐵道部不擔心票賣不出去,第一種方案對他影響沒有什麼。

     

    說了這麼多,就是說 分佈式環境下(數據分佈)要任何時刻保證數據一致性是不可能的,只能採取妥協的方案來保證數據最終一致性。這個也就是著名的CAP定理。

     

    轉載自:http://www.cnblogs.com/aigongsi/archive/2012/09/25/2701396.html


    發佈於 1年前, 閱讀(36) | 評論(0) | 投票(0) | 收藏(0) 閱讀全文...
  • 292012-11

    分佈式系統的數據一致性問題(一)裏面,簡單的介紹了分佈式數據的同步問題,上面的問題比較抽象,在目前的互聯網應用中還很少見,這次在通過一個比較常見的例子,讓大家更深入的瞭解一下分佈式系統設計中關於數據一致性的問題

     

    這次我們拿我們經常使用的功能來考慮吧,最近網購比較熱門,就以京東爲例的,我們來看看京東的一個簡單的購物流程

     

    用戶在京東上下了一個訂單,發現自己在京東的賬戶裏面有餘額,然後使用餘額支付,支付成功之後,訂單狀態修改爲支付成功,然後通知倉庫發貨。假設訂單系統,支付系統,倉庫系統是三個獨立的應用,是獨立部署的,系統之間通過遠程服務調用。

    訂單的有三個狀態:I:初始 P:已支付 W:已出庫,訂單金額100, 會員帳戶餘額200

    如果整個流程比較順利,正常情況下,訂單的狀態會變爲I->P->W,會員帳戶餘額100,訂單出庫。

     

    但是如果流程不順利了?考慮以下幾種情況

    1:訂單系統調用支付系統支付訂單,支付成功,但是返回給訂單系統數據超時,訂單還是I(初始狀態),但是此時會員帳戶餘額100,會員肯定會馬上找京東罵京東,爲啥不給老子發貨,我都付錢了

    2:訂單系統調用支付系統成功,狀態也已經更新成功,但是通知倉庫發貨失敗,這個時候訂單是P(已支付)狀態,此時會員帳戶餘額是100,但是倉庫不會發貨。會員也要罵京東。

    3:訂單系統調用支付系統成功,狀態也已經更新成功,然後通知倉庫發貨,倉庫告訴訂單系統,沒有貨了。這個時候數據狀態和第二種情況一樣。

     

    對於問題一,我們來分析一下解決方案,能想到的解決方案如下

    1 假設調用支付系統支付訂單的時候先不扣錢,訂單狀態更新完成之後,在通知支付系統你扣錢

    如果採用這種設計方案,那麼在同一時刻,這個用戶,又支付了另外一筆訂單,訂單價格200,順利完成了整個訂單支付流程,由於當前訂單的狀態已經變成了支付成功,但是實際用戶已經沒有錢支付了,這筆訂單的狀態就不一致了。即使用戶在同一個時刻沒有進行另外的訂單支付行爲,通知支付系統扣錢這個動作也有可能完不成,因爲也有可能失敗,反而增加了系統的複雜性。

     

    2 訂單系統自動發起重試,多重試幾次,例如三次,直到扣款成功爲止。

    這個看起來也是不錯的考慮,但是和解決方案一樣,解決不了問題,還會帶來新的問題,假設訂單系統第一次調用支付系統成功,但是沒有辦法收到應答,訂單系統又發起調用,完了,重複支付,一次訂單支付了200。

    假設支付系統正在發佈,你重試多少次都一樣,都會失敗。這個時候用戶在等待,你怎麼處理?

     

    3 在第二種方案的基礎上,我們先解決訂單的重複支付行爲,我們需要在支付系統上對訂單號進行控制,一筆訂單如果已經支付成功,不能在進行支付。返回重複支付標識。那麼訂單系統根據返回的標識,更新訂單狀態。

    接下來解決重試問題,我們假設應用上重試三次,如果三次都失敗,先返回給用戶提示支付結果未知。假設這個時候用戶重新發起支付,訂單系統調用支付系統,發現訂單已經支付,那麼繼續下面的流程。如果會員沒有發起支付,系統定時(一分鐘一次)去核對訂單狀態,如果發現已經被支付,則繼續後續的流程。

     

    這種方案,用戶體驗非常差,告訴用戶支付結果未知,用戶一定會罵你,你丫咋回事情,我明明支付了,你告訴我未知。假設告訴用戶支付失敗,萬一實際是成功的咋辦。你告訴用戶支付成功,萬一支付失敗咋辦。

     

    4 第三種方案能夠解決訂單和支付數據的一致性問題,但是用戶體驗非常差。當然這種情況比較可能是少數,可以犧牲這一部分的用戶體驗,我們還有沒有更好的解決方案,既能照顧用戶體驗,又能夠保證資金的安全性。

    我們再回來看看第一種方案,我們先不扣錢,但是有木有辦法讓這一部分錢不讓用戶使用,對了,我們先把這一部分錢凍結起來,訂單系統先調用支付系統成功的時候,支付系統先不扣錢,而是先把錢凍結起來,不讓用戶給其他訂單支付,然後等訂單系統把訂單狀態更新爲支付成功的時候,再通知支付系統,你扣錢吧,這個時候支付系統扣錢,完成後續的操作。

     

    看起來這個方案不錯,我們仔細在分析一下流程,這個方案還存在什麼問題,假設訂單系統在調用支付系統凍結的時候,支付系統凍結成功,但是訂單系統超時,這個時候返回給用戶,告知用戶支付失敗,如果用戶再次支付這筆訂單,那麼由於支付系統進行控制,告訴訂單系統凍結成功,訂單系統更新狀態,然後通知支付系統,扣錢吧。如果這個時候通知失敗,木有問題,反正錢都已經是凍結的了,用戶不能用,我只要定時掃描訂單和支付狀態,進行扣錢而已。

     

    那麼如果變態的用戶重新拍下來一筆訂單,100塊錢,對新的訂單進行支付,這個時候由於先前那一筆訂單的錢被凍結了,這個時候用戶餘額剩餘100,凍結100,發現可用的餘額足夠,那就直接在對用戶扣錢。這個時候餘額剩餘0,凍結100。先前那一筆怎麼辦,一個辦法就是定時掃描,發現訂單狀態是初始的話,就對用戶的支付餘額進行解凍處理。這個時候用戶的餘額變成100,訂單數據和支付數據又一致了。假設原先用戶餘額只有100,被凍結了,用戶重新下單,支付的時候就失敗了啊,的確會發生這一種情況,所以要儘可能的保證在第一次訂單結果不明確的情況,儘早解凍用戶餘額,比如10秒之內。但是不管如何快速,總有數據不一致的時刻,這個是沒有辦法避免的。

     

    第二種情況和第三種情況如何處理,下次在分析吧。

    由於互聯網目前越來越強調分佈式架構,如果是交易類系統,面臨的將會是分佈式事務上的挑戰。當然目前有很多開源的分佈式事務產品,例如java JPA,但是這種解決方案的成本是非常高的,而且實現起來非常複雜,效率也比較低下。對於極端的情況:例如發佈,故障的時候都是沒有辦法保證強一致性的。

     

    轉載自:http://www.cnblogs.com/aigongsi/archive/2012/09/22/2698055.html

    發佈於 1年前, 閱讀(41) | 評論(0) | 投票(0) | 收藏(1) 閱讀全文...
  • 292012-11
    關於分佈式系統的數據一致性問題(一)

     

    先把問題簡單化處理,假設A增加一條記錄Message_A,發送到M,B增加一條記錄 MESSAGE_B發送到M,都是通過MQ服務器進行轉發,那麼M系統接收到條消息,增加兩條數據,那麼M在把增加的消息羣發給A,B,A和B找到自己缺失的數據,更新數據庫。這樣就完成了一個數據的同步。

     

    從正常情況下來看,都沒有問題,邏輯完全合理,但是請考慮以下三個問題

    1 如何保證A->M的消息,M一定接收到了,同樣,如何保證M->A的消息,M一定接收到了

    2 如果數據需要一致性更新,比如A發送了三條消息給M,M要麼全部保存,要麼全部不保存,不能夠只保存其中的幾條記錄。我們假設更新的數據是一條條發送的。

    3 假設同時A發送了多條更新請求,如何保證順序性要求?

     

    這兩個問題就是分佈式環境下數據一致性的問題

    對於第一個問題,比較好解決,我們先看看一個tcp/ip協議鏈接建立的過程

    我們的思路可以從這個上面出發,在簡化一下,就一個請求,一個應答。

    簡單的通信模型是這樣的

    A->M : 你收到我的一條消息沒有,消息的ID是12345

    M->A:  我收到了你的一條消息數據,消息數據是ID;12345

    這樣就一個請求,一個應答,就完成了一次可靠性的傳輸。如果A一致沒有收到M的應答,就不斷的重試。這個時候M就必須保證冪等性。不能重複的處理消息。那麼最極端的情況是,怎麼也收不到M的應答,這個時候是系統故障。自己檢查一下吧。

    這麼設計就要求,A在發送消息的時候持久化這個消息的數據內容,然後不斷的重試,一旦接收到M的應答,就刪除這條消息。同樣,M端也是一樣的。不要相信MQ的持久化機制,不是很靠譜的。

    那麼M給A發送消息也採取類似的原理就可以了。

     

    下面在看看第二個問題,如何保持數據的一致性更新,這個還是可以參考TCP/IP的協議。

    首先A發送一條消息給M:我要發送一批消息數據給你,批次號是10000,數據是5條。

    M發送一條消息給A:ok,我準備好了,批次號是10000,發送方你A

    接着A發送5條消息給M,消息ID分別爲1,2,3,4,5 ,批次號是10000,

    緊接着,A發送一個信息給M:我已經完成5小消息的發送,你要提交數據更新了

     

    接下來可能發送兩種情況

    1 那麼M發送消息給A:ok,我收到了5條消息,開始提交數據

    2 那麼M也可以發送給A:我收到了5條消息,但是還缺少,請你重新發送,那麼A就繼續發送,直到A收到M成功的應答。

    整個過程相當複雜。這個也就是數據一旦分佈了,帶來最大的問題就是數據一致性的問題。這個成本非常高。

     

    對於第三個問題,這個就比較複雜了

    這個最核心的問題就是消息的順序性,我們只能在每個消息發一個消息的序列號,但是還是沒有最好解決這個問題的辦法。因爲消息接收方不知道順序。因爲即使給他了序列號,也沒有辦法告訴他,這個應該何時處理。最好的辦法是在第二種方式的基礎作爲一個批次來更新。

     

    這個只是以最簡單的例子來說明一下分佈式系統的要保證數據一致性是一件代價很大的事情。當然有的博主會說,這個何必這麼複雜,直接數據庫同步不就可以了。這個例子當然是沒有問題的,萬一這個幾個庫的模型都不一樣,我發送消息要處理的事情不一樣的。怎麼辦?

    發表評論
    所有評論
    還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
    相關文章