淘寶Diamond架構分析


轉載:http://blog.csdn.net/szwandcj/article/details/51165954

早期的應用都是單體的,配置修改后,只要通過預留的管理界面刷新reload即可。后來,應用開始拆分,從單一系統拆分成多個子系統,每個子系統還會對應多個運行實例,就開始面臨一些問題: 
1. 配置分散在多個業務子系統里,對同一配置的翻譯在多個子系統里經常不一致。比如訂單和購物車都有貨幣類型的配置,如果購物車上了一種新的貨幣類型而訂單卻沒有相應同步增加配置項就會造成程序錯誤。 
2. 將配置收斂成一個公有服務,可以有效改善,但是又會帶來其他問題。在復雜應用里,修改一個配置項,無法確切的知道需要刷新哪些相關子系統。最終只能做全量刷新,甚至是停機發布。這對於一些停機敏感的應用例如電商幾乎是無法接受的。 
3. 配置收斂后,配置中心成了應用中的單點,配置如果掛了,應用也會跟着產生異常甚至掛掉。

Diamond就是為了解決這些問題,它是個高可用的配置中心。

Diamond的配置類型

配置是Diamond的核心域,也是Diamond致力於去解決的問題。Diamond有兩個主要配置類型– single和aggr。二者結構如下: 
配置結構 
Aggr和single相比,少md5多datumId。DatumId是aggr的邏輯主鍵,aggr下dataId和datumId是1對多的關系,也就是說多條aggr會聚合成一條single,diamond通過merge任務對aggr合並最終生成一條single。

Md5是對content md5編碼生成的字符串,用於判斷緩存數據相比數據庫數據是否不同,緩存數據必須嚴格與數據庫數據一致,diamond並沒有數據版本,默認數據庫數據是最新的,也就是說如果數據庫數據發生回退,即使緩存數據更新也會跟着回退。

Single才有md5,aggr其實並不算是完整的配置(多條aggr一起才是一個完整的配置),所以不需要校驗數據是否改變。

整體架構設計

下圖是Diamond的組件視圖。Diamond主要有ops, sdk, client和server 4個組件。Ops是運維用的配置工具,主要用於下發以及查詢配置等;server則是Diamond的后台,處理配置的一些邏輯;sdk則是提供給ops或者其他第三方應用的開發工具包;client則是編程api,它和sdk乍看有點像,其實差別很大,sdk是用於構建前台運維配置程序的,本質是對數據的維護,所有的訪問和操作都是直接面向數據庫的;而client則是這些數據的消費者,事實上准確的說是diamond的消費者們(各子系統)都是通過client組件對server訪問。 
進程視圖

Diamond server是無中心節點的邏輯集群,讀請求都是訪問local file,而寫請求則會先進入數據庫,接着再更新各節點緩存。注意:ops或者其他第三方運維系統(其實就是sdk模塊)讀取和寫入的都是數據庫,這很容易理解,緩存會有lag,配置系統必須面向的是實時數據。

Diamond的數據庫是單點的,這就可以利用數據庫特性保證數據的原子性,一致性和持久性,也就不需要實現類似zk的集群協議,也就不存在leader/follower以及observer等節點角色,它是去中心化的,所有節點都可以接受任意請求。Diamond是典型的讀多寫少,寫一般都來自運維系統例如ops,這種請求量會很小,即使峰值期對數據庫的沖擊也不會太大。實際上它就是數據庫之上的一個保護殼,數據庫的數據通過它透出來,也通過它滲進去。

Diamond的同質節點之間會相互通信以保證數據的一致性,每個節點都有其它節點的地址信息,其中一個節點收到變更請求后,首先寫入數據庫,再通知所有同質節點更新緩存,保證數據的一致性。

為了保證高可用,client會在app端以本地文件形式緩存數據的snapshot,保證即使server不可用時app也可用,這一點和dubbo很相似,所以也完全可以使用diamond搭建dubbo注冊中心。

內存緩存

  • Client端使用的內存cache是一個AtomicReference

    1. 它並不是通常理解的內存緩存,而只是一個事件源,只有被監聽的配置才會有cache。Cache內聚了group,dataId,md5,content和listener等。
    2. 客戶端的長輪詢任務(下一節將會重點介紹)只輪詢被監聽的配置,也就是cache的數據。客戶端在pull到新數據后首先會更新snapshot,再更新cache,接着全量對比所有cache和它關聯的listener的md5信息從而知道配置更新有沒有被通知,沒有則以cache中的內容作為消息載體通知,通知完成后更新listener的md5。
    3. 沒被監聽的數據不需要輪詢,因為diamond提供的讀數據api默認會先從服務節點獲取實時數據。
  • 在客戶端發起長輪詢或者服務節點做dump時,都需要對比md5信息以確定是否要推送或者dump。Server端緩存全量緩存了所有配置的md5信息,並會第一時間得到更新,得到更新同時還會推送LocalDataChangeEvent。

  • 無論客戶端還是服務端,內存緩存僅僅是為了滿足某種功能需求,並不作為讀的數據源(客戶端只緩存部分數據,服務端不緩存配置內容)。這是基於產品本身定位而來的,產品定位本身就是犧牲一部分速度以降低成本,並且同時提供長輪詢機制為時效性要求高的配置做到准實時的變更推送。但在客戶端,每個應用的興趣點都是分散的,平均下來每個應用感興趣的配置數據並不大。

長輪詢

Client會不斷長輪詢server,獲取最新的配置推送,盡量保證本地數據的時效性。 
長輪詢

Client默認啟動周期任務對server進行長輪詢感知server的配置變化,server感知到配置變化就發送變更的數據編號,客戶端通過數據編號再去拉取最新配置數據;否則超時結束請求(默認10秒)。拉取到新配置后,client會通知監聽者(MessageListener)做相應處理,用戶可以通過Diamond#addListener監聽。 
長輪詢客戶端 
服務端通過AsyncContext對請求做非阻塞處理,通過定時任務感知配置變化。 
長輪詢server 
詳細描述下上圖, 
1. server收到請求后啟動AsyncContext,並基於它構造ClientLongPulling。ClientLongPulling除了AsyncContext還有一個超時回復任務對長輪詢請求做超時處理 
2. 之后ClientLongPulling被加入等待列表。LongPullingService關聯一個感知數據變化的定時任務,當有數據變化時(收到LocalDataChangeEvent),就會循環等待列表里的ClientLongPulling,推送數據變化回客戶端。 
4. Dump是抽象出來的一塊兒概念,server的數據變化都會觸發響應的dump task,並會發送相應的事件,由server感知,DataChangeTask也是一個事件監聽者,能感知local file的數據變化。

服務端架構設計

Diamond集群是去中心化的,使用通知機制保證集群各節點數據一致。 
集群數據同步
1. Diamond集群內每個節點都有其他節點的地址信息,當一台節點收到寫請求后首先寫數據庫,接着就會發送ConfigDataChangeEvent,監聽者收到該事件后通知所有節點做數據變更。通知的所有節點也包括自己,下發配置的請求只會更新數據庫,並不會更新本地文件緩存。 
2. 通知發送到所有節點后,通過dump更新local file。Dump是將配置對象dump進本地文件的過程,dump完畢后發送LocalDataChangeEvent,見上節。

任務管理

Diamond收到配置請求,先執行數據庫操作,然后再向任務管理器的任務棧里插入一條任務,任務管理器感知到新任務后,pick相應的TaskProcessor處理。TaskProcessor和Task的關系通過TaskManager#addProcessor(或setDefaultProcessor)設置。 
Diamond的任務管理器是FIFO的,這會造成長延時任務阻塞其他任務的執行。為解決這個問題,Diamond的開發者為每個Task都定制TaskManager。用戶可以做些優化,參考hadoop的公平算法,針對應用場景(比如長延時,離線,實時等等)定制TaskProcessor。 
任務管理

其他一些任務

為了保證Diamond的數據一致,除了以上介紹的兩類任務,還有其他一些task,見下圖: 
server心跳任務 
1. Merge任務用於合並aggr。App下發聚合配置到diamond后,會觸發合並任務生成single,同時廣播配置變更事件(ConfigDataChangeEvent),各節點收到通知后拉取數據庫相應single數據並更新local file。這與上面描述的server數據同步基本類似,只是事件源頭換成了merge。 
merge任務 
2. DumpAllTask會每6小時run一次做全量dump,全量刪除老的緩存數據,生成新緩存。 
2. DumpChangeTask做增量dump。通過和數據庫的配置做md5對比,刪除被移除配置的文件緩存,更新md5不一致的文件緩存等等。 
3. 清除歷史數據用於清除1周前的數據庫his表數據。 
4. 心跳任務用於記錄心跳時間,節點服務重啟時會判斷距離上次心跳時間是否已經超過一小時,超過一小時則做全量dump,否則做增量。

剩下的都很好理解,不再一一介紹,需要注意的是,這些任務並不是都是定時做,有些是事件觸發的,例如DumpTask和merge;還有些在Diamond服務啟動時會觸發,如merge,DumpChangeTask等。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM