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