系統(tǒng)優(yōu)化的方法知識點外貿(mào)建站優(yōu)化
一、前言
? ? ? ?最近工作不忙閑來無事,仔細分析了公司整個項目架構,發(fā)現(xiàn)用到了很多阿里巴巴集團開源的框架,今天要介紹的是中間件diamond.
二、diamond學習筆記
? ? ? 1、diamond簡介
? ? ? diamond是一個管理持久配置(持久配置是指配置數(shù)據(jù)會持久化到磁盤和數(shù)據(jù)庫中)的系統(tǒng)。無可厚非,淘寶內部正在使用diamond,在淘寶內部的絕大多數(shù)系統(tǒng)的配置都是由diamond統(tǒng)一管理的。diamond最大的特點就是簡單、可靠、易用。diamond的簡單是指diamond整體結構非常簡單,從而減少了出錯的可能性;diamond的可靠是指應用方在任何情況下都可以啟動,例如:淘寶的核心系統(tǒng)最初一年多是由diamond所管理,在這期間并沒有發(fā)生什么大的故障;diamond的易用是指客戶端使用只需要兩行代碼,暴露出的接口都非常簡單,易于理解。
? ? ?對于應用系統(tǒng)而言,diamond為其提供獲取配置的服務,應用不僅可以在啟動時從diamond獲取相關的配置,而且可以在運行中對配置數(shù)據(jù)的變化進行感知并獲取變化后的配置數(shù)據(jù)。
? ? ? 2、快速使用
? ? ? 源碼檢出:http://code.taobao.org/svn/diamond/trunk。
? ? ? server搭建:
? ? ? ? ?a. mysql
? ? ? ? ?mysql的安裝(安裝步驟請自行查閱資料,本人建議按照mysql官方文檔),以root用戶登錄,建立用戶并賦予權限,建立數(shù)據(jù)庫,然后建表。腳本如下:
create?database?diamond;??
grant?all?on?diamond.*?to?CK@'%'?identified?by?'abc';??use?diamond??
create?table?config_info?(??'id'?bigint(64)?unsigned?NOT?NULL?auto_increment,??'data_id'?varchar(255)?NOT?NULL?default?'?',??'group_id'?varchar(128)?NOT?NULL?default?'?',??'content'?longtext?NOT?NULL,??'md5'?varchar(32)?NOT?NULL?default?'?',??'gmt_create'?datetime?NOT?NULL?default?'2010-05-05?00:00:00',??'gmt_modified'?datetime?NOT?NULL?default?'2010-05-05?00:00:00',??PRIMARY?KEY??('id'),??UNIQUE?KEY?'uk_config_datagroup'?('data_id','group_id')??
);??
完成后,請將數(shù)據(jù)庫的配置信息(IP,用戶名,密碼)添加到diamond-server工程的src/resources/jdbc.properties文件中的db.url,db.user,db.password屬性上面,這里建立的庫名,用戶名和密碼,必須和jdbc.properties中對應的屬性相同。
? ? ? ? b. tomcat
? ? ? ??tomcat是diamond server的運行容器,而對于tomcat的安裝請自行查閱資料,推薦使用tomcat7和安裝tomcat的官方文檔。tomcat安裝后,不需要做任何改動。
? ? ? ? c. diamond server
? ? ? ??在diamond-server源代碼根目錄下,執(zhí)行mvn clean package -Dmaven.test.skip,成功后會在diamond-server/target目錄下生成diamond-server.war(如果沒有安裝maven,請參考maven官方文檔進行安裝)。打包完成后,將diamond-server.war放在tomcat的webapps目錄下。啟動tomcat,即啟動了diamond-server。
? ? ? ? d. http server
? ? ? ??http server用來存放diamond server等地址列表,可以選用任何http server,這里以tomcat為例。一般來講,http server和diamond server是部署在不同機器上的,這里簡單起見,將二者部署在同一個機器下的同一個tomcat的同一個應用中,注意,如果部署在不同的tomcat中,端口號一定是8080,不能修改(所以必須部署在不同的機器上)。在上一步的tomcat的webapps中的diamond-server中建立文件diamond,文件內容是diamond-server的地址列表,一行一個地址,地址為IP,例如:127.0.0.1。完成以上4步后,server端的搭建就完成了。
? ? ? 發(fā)布數(shù)據(jù):
? ? ? ? ?diamond發(fā)布數(shù)據(jù)通過手工的方式進行。在瀏覽器中輸入http://ip:8080/diamond-server/,ip為server搭建的第二步中的地址,以user為用戶名,123為密碼,登錄后進入后臺管理界面,然后點擊“配置信息管理”—— “添加配置信息”,在輸入框中輸入dataId、group、內容,最后點擊“提交”即可。成功后,可以在“配置信息管理”中查詢到發(fā)布的數(shù)據(jù)。
? ? ? 訂閱數(shù)據(jù):
? ? ? ? ?diamond客戶端API主要提供了訂閱數(shù)據(jù)的功能:
? ? ? ? ?a. 客戶端獲取服務端地址
? ? ? ? ?獲取服務端地址對客戶端是透明的,客戶端僅僅需要在本地進行如下域名綁定即可:ip a.b.c,ip為前面搭建的http-server的ip。
? ? ? ? ?b. 創(chuàng)建訂閱者 ? ? ? ?
- DiamondManager?manager?=?new?DefaultDiamondManager(group,?dataId,?new?ManagerListener()?{??
- ???public?Executor?getExecutor()?{??
- ???????return?null;??
- ???}??
- ??
- ???public?void?receiveConfigInfo(String?configInfo)?{??
- ??????//?客戶端處理數(shù)據(jù)的邏輯??
- ??
- ???}??
- });??
? ? ? ? 參數(shù)說明:group和dataId為String類型,二者結合為diamond-server端保存數(shù)據(jù)的惟一key。ManagerListener 是客戶端注冊的數(shù)據(jù)監(jiān)聽器, 它的作用是在運行中接受變化的配置數(shù)據(jù),然后回調receiveConfigInfo()方法,執(zhí)行客戶端處理數(shù)據(jù)的邏輯。如果要在運行中對變化的配置數(shù)據(jù)進行處理,就一定要注冊ManagerListener。
? ? ? ? c.?獲取配置數(shù)據(jù) ? ?
- String?configInfo?=?manager.getAvailableConfigureInfomation(timeout);??
? ? ? ??diamond-server端保存的配置全都為文本類型,返回給客戶端的配置數(shù)據(jù)為java.lang.String類型,timeout為從網(wǎng)絡獲取配置數(shù)據(jù)的超時時間。客戶端調用每次調用該方法,都能夠保證獲取一份最新的可用的配置數(shù)據(jù)。
? ? ? 2、核心原理
? ? ? diamond核心原理主要包括server集群的數(shù)據(jù)同步、client獲取server地址、client從server獲取數(shù)據(jù)、client運行時感知server的數(shù)據(jù)變化,這四部分。
? ? ? ? a.?server集群的數(shù)據(jù)同步
? ? ? ? diamond-server將數(shù)據(jù)存儲在mysql和本地文件中,mysql是一個中心,diamond認為存儲在mysql中的數(shù)據(jù)絕對正確,除此之外,server會將數(shù)據(jù)存儲在本地文件中。
? ? ? ? 同步數(shù)據(jù)有兩種方式:
? ? ? ? server寫數(shù)據(jù)時,先將數(shù)據(jù)寫入mysql,然后寫入本地文件,寫入完成后發(fā)送一個HTTP請求給集群中的其他server,其他server收到請求,從mysql中dump剛剛寫入的數(shù)據(jù)至本地文件。
? ? ? ? server啟動后會啟動一個定時任務,定時從mysql中dump所有數(shù)據(jù)至本地文件。
? ? ? ? b.?client獲取server地址
? ? ? ??diamond-client在使用時沒有指定server地址的代碼,地址獲取對用戶是透明的。server地址存儲在一臺具有域名的機器上的HTTP server中,我們稱它為地址服務器,diamond-client使用前需要在本地進行正確的域名綁定,啟動時它會根據(jù)域名綁定,去對應環(huán)境的地址服務器上獲取diamond-server地址列表。獲取的地址列表,會保存在client本地,當出現(xiàn)網(wǎng)絡異常,無法從網(wǎng)絡獲取地址列表時,client會使用本地保存的地址列表。client啟動后會啟動一個定時任務,定時從HTTP server上獲取地址列表并保存在本地,以保證地址是最新的。
? ? ? ? c.?client從server獲取數(shù)據(jù)
? ? ? ??client調用getAvailableConfigInfomation(), 即可獲取一份最新的可用的配置數(shù)據(jù),獲取過程實際上是拼接http url,使用http-client調用http method的過程。為了避免短時間內大量的獲取數(shù)據(jù)請求發(fā)向server,client端實現(xiàn)了一個帶有過期時間的緩存,client將本次獲取到的數(shù)據(jù)保存在緩存中,在過期時間內的所有請求,都返回緩存內的數(shù)據(jù),不向server發(fā)出請求。
? ? ? ? d.?client運行時感知server的數(shù)據(jù)變化
? ? ? ??這是diamond最為核心的一個功能。這個特性是通過比較client和server的數(shù)據(jù)的MD5值實現(xiàn)的。server在啟動時,會將所有數(shù)據(jù)的MD5加載到內存中(MD5根據(jù)某算法得出,保證數(shù)據(jù)內容不同,MD5不同,MD5存儲在mysql中),數(shù)據(jù)更新時,會更新內存中對應的MD5。client在啟動并第一次獲取數(shù)據(jù)后,會將數(shù)據(jù)的MD5保存在內存中,并且在啟動時會啟動一個定時任務,定時去server檢查數(shù)據(jù)是否變化。每次檢查時,client將MD5傳給server,server比較傳來的MD5和自身內存中的MD5是否相同,如果相同,說明數(shù)據(jù)沒變,返回一個標示數(shù)據(jù)不變的字符串給client;如果不同,說明數(shù)據(jù)變了,返回變化數(shù)據(jù)的dataId和group給client. ?client收到變化數(shù)據(jù)的dataId和group,再去server請求一次數(shù)據(jù),拿回數(shù)據(jù)后回調監(jiān)聽器。
? ? ?3、diamond架構
? ? ?diamond服務是一個集群,是一個去除單點的協(xié)作集群。如下圖所示:
? ???對該圖進行一些說明:
? ? ?a. 作為一個配置中心,diamond的功能分為發(fā)布和訂閱兩部分。因為diamond存放的是持久數(shù)據(jù),這些數(shù)據(jù)的變化頻率不會很高,甚至很低,所以發(fā)布采用手工的形式,通過diamond后臺管理界面發(fā)布;訂閱是diamond的核心功能,訂閱通過diamond-client的API進行。
? ? ?b. diamond服務端采用mysql加本地文件的形式存放配置數(shù)據(jù)。發(fā)布數(shù)據(jù)時,數(shù)據(jù)先寫到mysql,再寫到本地文件;訂閱數(shù)據(jù)時,直接獲取本地文件,不查詢數(shù)據(jù)庫,這樣可以最大程度減少對數(shù)據(jù)庫的壓力。
? ? ?c.?diamond服務端是一個集群,集群中的每臺機器連接同一個mysql,集群之間的數(shù)據(jù)同步通過兩種方式進行,一是每臺server定時去mysql dump數(shù)據(jù)到本地文件,二是某一臺server接收發(fā)布數(shù)據(jù)請求,在更新完mysql和本機的本地文件后,發(fā)送一個HTTP請求(通知)到集群中的其他幾臺server,其他server收到通知,去mysql中將剛剛更新的數(shù)據(jù)dump到本地文件。
? ? ?d.?每一臺server前端都有一個nginx,用來做流量控制。
? ? ?e.?圖中沒有將地址服務器畫出,地址服務器是一臺有域名的機器,上面運行有一個HTTP server,其中有一個靜態(tài)文件,存放著diamond服務器的地址列表??蛻舳藛訒r,根據(jù)自身的域名綁定,連接到地址服務器,取回diamond服務器的地址列表,從中隨機選擇一臺diamond服務器進行連接。
? ? ?4、容災機制
? ? ?diamond容災機制涉及到client和server兩部分,主要包括以下幾個方面:
? ? ?a.?server存儲數(shù)據(jù)的方式
? ? ?server存儲數(shù)據(jù)是“數(shù)據(jù)庫 + 本地文件”的方式,集群間的數(shù)據(jù)同步我們在之前的文章中講過(請參考專題二的原理部分),client訂閱數(shù)據(jù)時,訪問的是本地文件,不查詢數(shù)據(jù)庫,這樣即使數(shù)據(jù)庫出問題了,仍然不影響client的訂閱。
? ? ?b.?server是一個集群
? ? ?這是一個基本的容災機制,集群中的一臺server不可用了,client發(fā)現(xiàn)后可以自動切換到其他server上進行訪問,自動切換在client內部實現(xiàn)。
? ? ?c. client保存snapshot
? ? ?client每次從server獲取到數(shù)據(jù)后,都會將數(shù)據(jù)保存在本地文件系統(tǒng),diamond稱之為snapshot,即數(shù)據(jù)快照。當client下次啟動發(fā)現(xiàn)在超時時間內所有server均不可用(可能是網(wǎng)絡故障),它會使用snapshot中的數(shù)據(jù)快照進行啟動。
? ? ?d.?client校驗MD5
? ? ?client每次從server獲取到數(shù)據(jù)后,都會進行MD5校驗(數(shù)據(jù)保存在response body,MD5保存在response header),以防止因網(wǎng)絡故障造成的數(shù)據(jù)不完整,MD5校驗不通過直接拋出異常。
? ? ?e.?client與server分離
? ? ?client可以和server完全分離,單獨使用,diamond定義了一個“容災目錄”的概念,client在啟動時會創(chuàng)建這個目錄,每次主動獲取數(shù)據(jù)(即調用getAvailableConfigInfomation()方法),都會優(yōu)先從“容災目錄”獲取數(shù)據(jù),如果client按照一個固定的規(guī)則,在“容災目錄”下配置了需要的數(shù)據(jù),那么client直接獲取到數(shù)據(jù)返回,不再通過網(wǎng)絡從diamond-server獲取數(shù)據(jù)。同樣的,在每次輪詢時,都會優(yōu)先輪詢“容災目錄”,如果發(fā)現(xiàn)配置還存在于其中,則不再向server發(fā)出輪詢請求。 以上的情形, 會持續(xù)到“容災目錄”的配置數(shù)據(jù)被刪除為止。
? ??根據(jù)以上的容災機制,我們可以總結一下diamond整個系統(tǒng)完全不可用的條件:
? ? 數(shù)據(jù)庫不可用;
? ? 所有server均不可用;
? ? client主動刪除了snapshot;
? ? client沒有備份配置數(shù)據(jù),導致其不能配置"容災目錄";
? ? 本人在公司的線上環(huán)境仔細分析過,同時滿足這四點條件的概率那是相當小!
三、總結
? ? 通過對diamond源碼的閱讀及架構的分析,可以得出這樣一個結論:diamond簡單、可靠、易用的特點是相輔相成的,即diamond之所以簡單是因為使用的都是一些最常用的技術以及產(chǎn)品,它之所以表現(xiàn)得非常穩(wěn)定,跟其架構簡單是分不開的,當然,穩(wěn)定的另一個主要原因是它具備一套比較完善的容災機制。