2009年3月4日 #
優(yōu)化雜談
Author :放翁
Blog:http://blog.csdn.net/cenwenchu79/
當(dāng)應(yīng)用遇到規(guī)模化問題的時(shí)候,就是考慮性能優(yōu)化的時(shí)候了。今天同事和我聊起了NIO在客戶端的使用與BIO有什么優(yōu)勢,也勾起了我前一陣子和其他同學(xué)交流優(yōu)化的一些想法,純粹個(gè)人的一點(diǎn)想法。
CPU利用率和Load
在過去做壓力測試的時(shí)候,我們經(jīng)常會(huì)關(guān)注兩個(gè)指標(biāo),CPU和Load。有同學(xué)覺得CPU利用率上去了Load肯定也上去了,Load上去了CPU利用率同樣會(huì)上去。但是在一些需要優(yōu)化的場景下,常常會(huì)看到Load很高,CPU利用率卻可能比較低(多核更是可能出現(xiàn)分配不均的情況)。Load其實(shí)就是等待處理的任務(wù)隊(duì)列,當(dāng)你的應(yīng)用在等待同步消息返回處理的同時(shí),CPU還是會(huì)將時(shí)間切片分配給這些線程,而真正需要CPU的線程,卻不得不在到了時(shí)間片以后暫時(shí)放棄工作被掛起。因此在程序設(shè)計(jì)的時(shí)候就要考慮如何利用好CPU的這個(gè)資源,如何均勻的將壓力分?jǐn)偟礁鱾€(gè)CPU上(有時(shí)候就一個(gè)線程在不斷循環(huán),導(dǎo)致單個(gè)CPU負(fù)荷很高)。
NIO在客戶端的使用
Http消息設(shè)置keepalive和采用NIO的方式復(fù)用信道、BIO結(jié)合連接池的方式,最基本的目的就是降低建立TCP產(chǎn)生握手的成本,最大限度的復(fù)用已有的資源,但是否NIO就只有復(fù)用信道這點(diǎn)呢?
NIO和BIO在數(shù)據(jù)傳輸和處理的模式上有不同,NIO采用的是BufferPacket+Channel的模式,這其實(shí)和操作系統(tǒng)本身的傳輸模式很類似,而BIO的Stream的模式是Java自己獨(dú)特的模式。在采用NIO的這種數(shù)據(jù)傳輸模式以后,可以充分利用操作系統(tǒng)本身對傳輸?shù)膬?yōu)化,因此這是一方面好處。另一方面異步和事件機(jī)制的使用,可以降低對于昂貴的資源申請,在高并發(fā)下提高處理能力。
NIO客戶端的編程模型最大特點(diǎn):依賴反置,松耦合帶來性能提升。在請求流程協(xié)議中支持“票根”,也就是我們說的回執(zhí)。例如,你今天面試完了,不需要你在阿里巴巴前臺等著結(jié)果,直接留個(gè)電話,有消息就會(huì)直接通知,電話就是通知結(jié)果和服務(wù)請求者的關(guān)聯(lián)手段。(此時(shí)阿里巴巴前臺和會(huì)議室就會(huì)有足夠的空間給其他人來面試,這就是資源)
服務(wù)端使用NIO就不多說了,這里主要說一下在客戶端的使用場景。兩者是否真的有很大的差別,是否NIO有絕對的優(yōu)勢,其實(shí)還是和場景有關(guān)。簡單說來就一個(gè)判斷標(biāo)準(zhǔn):應(yīng)用對于通道的利用率是否夠高。下面列了4種場景:
1. 一次請求數(shù)據(jù)量很少,服務(wù)處理速度很快。
2. 一次請求數(shù)據(jù)量很多,服務(wù)處理速度很快。
3. 一次請求數(shù)據(jù)量很少,服務(wù)處理速度很慢。
4. 一次請求數(shù)據(jù)量很多,服務(wù)處理速度很慢。
場景1,傳輸效率很高,服務(wù)處理速度很快,一次請求很快就被完成,采用NIO和BIO,在性能優(yōu)勢上除了操作系統(tǒng)對NIO的優(yōu)化以外,BIO連接池不輸于NIO。在易用性上,BIO更加容易處理。(NIO的異步機(jī)制,就要求消息傳輸協(xié)議需要有會(huì)話碼來提供異步處理入口選擇如何處理)
場景2,傳輸過程比較長,消耗時(shí)間比較多,服務(wù)處理速度很快,因此交互的時(shí)間大部分都還是在數(shù)據(jù)通道傳輸上,由于NIO在傳輸過程中依然是串行化的,因此BIO的連接池優(yōu)于NIO,同時(shí)NIO一個(gè)客戶端只有一個(gè)通道,因此BIO開的連接池越大,并行處理能力越強(qiáng),因此BIO效率比較好一些。
場景3,傳輸量比較少,服務(wù)處理比較慢,很明顯這是通道利用率低的表現(xiàn),NIO有絕對的優(yōu)勢,特別是在高并發(fā)下。信道和服務(wù)端客戶端資源被充分利用。
場景4,傳輸量比較多,服務(wù)處理也比較慢,這時(shí)候可以發(fā)現(xiàn)信道利用率取決于服務(wù)事件和傳輸消耗時(shí)間的比例,這類場景某些情況下BIO也會(huì)優(yōu)于NIO。
單線程和多線程
在使用多線程來優(yōu)化程序的時(shí)候,是否考慮過多線程的使用場景,多線程不是萬能藥,在某些情況下還可能是毒藥。使用多線程的過程中,需要考慮這么幾個(gè)因素:
1. 資源競爭,復(fù)雜度增加。
為什么前面提到的NIO客戶端在處理數(shù)據(jù)流發(fā)送和讀取的時(shí)候都是采用單線程,數(shù)據(jù)流的發(fā)送和讀取都是在一個(gè)數(shù)據(jù)通道上的,而讀取和發(fā)送本身時(shí)間消耗是固定的(不論是多線程還是單線程),同時(shí)增加了復(fù)雜度(需要處理數(shù)據(jù)包整合問題)。這其實(shí)就是在資源上的串行化操作直接導(dǎo)致了任務(wù)的串行化,因此任務(wù)多線程反而起到了反作用。
2. 是否是關(guān)鍵路徑的工作,占關(guān)鍵路徑的比例。
首先,在優(yōu)化以前需要考慮優(yōu)化的內(nèi)容是否是關(guān)鍵路徑的工作,如果不是,那么增加復(fù)雜度實(shí)現(xiàn)的多線程模式,就沒有價(jià)值。其次就是看是否是在關(guān)鍵路徑中占有比較大的比例,同樣的,還是投入產(chǎn)出比例(多線程帶來的復(fù)雜度以及在高并發(fā)下的一些資源保護(hù)措施都需要很多的維護(hù)成本)。
3. 任務(wù)的合理切分。
在NIO的客戶端,接受數(shù)據(jù)的事件將會(huì)寫得很輕量級,但是接受到數(shù)據(jù)然后分析數(shù)據(jù)還原成業(yè)務(wù)對象,則會(huì)通過線程池的方式來分別處理。就好比監(jiān)聽連接到來,和實(shí)際的去建立連接分成了兩個(gè)階段的任務(wù),讓事件型的任務(wù)單純,快速執(zhí)行,讓與業(yè)務(wù)相關(guān)的部分通過多線程并行的方式提高處理效率。總的來說就是把任務(wù)劃分成為系統(tǒng)性的任務(wù)和業(yè)務(wù)性的任務(wù),前者消耗時(shí)間少,設(shè)計(jì)盡量簡單高效,采用單線程處理即可,后者通常情況下在處理流程和資源上不沖突的情況可以通過多線程并行提高效率。
優(yōu)化應(yīng)用關(guān)注點(diǎn):
A.關(guān)鍵路徑是否可以優(yōu)化,關(guān)鍵路徑的任務(wù)拆分。
B.關(guān)鍵路徑上的單個(gè)任務(wù)是否可以拆分并行執(zhí)行。(是否有資源競爭,是否會(huì)有流程上的前后依賴,是否增加復(fù)雜度引入新的不穩(wěn)定因素)
C.系統(tǒng)資源和依賴外部系統(tǒng)是否會(huì)成為瓶頸。(單機(jī)的CPU,IO都會(huì)在一定的壓力下成下降趨勢,并行執(zhí)行反而降低了處理能力)
因此,可以看到不論是MapReduce設(shè)計(jì)下的Hadoop,還是Erlang語言級別的特性,都盡量的希望任務(wù)之間可以并行執(zhí)行,相互之間低耦合,通過異步事件消息通知方式來交互,同時(shí)數(shù)據(jù)沒有共享,防止資源競爭導(dǎo)致無法并行高效處理。系統(tǒng)設(shè)計(jì)還是要根據(jù)場景來判斷使用什么方式優(yōu)化,越簡單越好。
中午左右收到一個(gè)看我blog的朋友的郵件,最近他在研究mapreduce,然后想用hadoop來做一些工作,不過遇到了一些問題,我這邊也貼一下他的幾個(gè)問題,同時(shí)覺得自己把自己的一些看法分享一下,當(dāng)然只是自己的一些想法,也許對新學(xué)習(xí)的同學(xué)有幫助。
問題:
- 從Map(K,V)的方式來看,難道m(xù)apreduce只能做統(tǒng)計(jì)?
- 目前我想除了日志分析之類的功能外,還想做一個(gè)全文檢索的功能,類似windows查詢一下,通過關(guān)鍵字查詢文件的位置即可(可能還要根據(jù)匹配度做排序),這個(gè)我很迷茫不知道怎么下手,痛苦ing
- 你的實(shí)踐是一個(gè)單機(jī)模式,如果用戶把一個(gè)1G的log已經(jīng)上傳到hdfs了,此時(shí)分割工作已經(jīng)完成,只需要從client那里得到文件基本信息和塊的location就可以了,那mapreduce怎么進(jìn)行下去呢?
我給回復(fù)的郵件內(nèi)容:
首先,MapReduce的思想和Hadoop的MapReduce的架構(gòu)不是一個(gè)概念,說的具體一點(diǎn)也就是Hadoop的架構(gòu)設(shè)計(jì)只是MapReduce的一個(gè)子集思想的實(shí)現(xiàn)。每個(gè)人都可以根據(jù)自己對MapReduce的理解去實(shí)現(xiàn)業(yè)務(wù)處理,簡單來說多線程處理就是MapReduce的一種最簡單的實(shí)現(xiàn),復(fù)雜來說多機(jī)協(xié)調(diào)工作就是一種復(fù)雜的實(shí)現(xiàn)。
MapReduce的思想里面最值得借鑒的:
a.問題分而治之。(找到流程的關(guān)鍵路徑,優(yōu)化可以并行處理的工作)
b.計(jì)算靠近數(shù)據(jù)。(這也是hdfs存在的最重要的特點(diǎn),計(jì)算的轉(zhuǎn)移往往要比數(shù)據(jù)轉(zhuǎn)移廉價(jià),特別是對海量數(shù)據(jù)的處理)
c.數(shù)據(jù)規(guī)模化隨著并行處理成數(shù)量級遞減。
剩下的內(nèi)容就是各個(gè)框架對于非業(yè)務(wù)性需求的處理,例如容災(zāi),如何盡量少穿數(shù)據(jù)協(xié)調(diào)處理等等。
針對他提出的三個(gè)問題:
1. Hadoop的mapreduce從架構(gòu)上來說最適合的就是統(tǒng)計(jì)分析計(jì)算。做其他方面的工作需要考慮是否適合,而不是為了技術(shù)而技術(shù),先有需求再有技術(shù)選型。
2. 對于你這個(gè)需求直接用搜索技術(shù)實(shí)現(xiàn)就可以了,不一定要硬套在mapreduce上。
3. 對于海量數(shù)據(jù)是否一定要到hdsf上,或者就簡單得數(shù)據(jù)物理或者邏輯切割來直接處理,根據(jù)自己業(yè)務(wù)場景選擇。hdfs的特點(diǎn)就是對文件切割,容災(zāi),數(shù)據(jù)邏輯存儲和物理存儲無關(guān)性(便于擴(kuò)容管理,同時(shí)也是計(jì)算靠近數(shù)據(jù)的技術(shù)保證)。
是否使用MapReduce框架,HDFS存儲關(guān)鍵還是看你是否真的需要,當(dāng)現(xiàn)有框架對自己來說并不合適的時(shí)候可以對小規(guī)模問題定制MapReduce的處理,最簡化就是你去多線程或者多進(jìn)程處理問題,需求決定技術(shù)選型。
Email:fangweng@taobao.com
Blog:http://blog.csdn.net/cenwenchu79
當(dāng)前問題:
1. 不小比重的Rest請求都是無效請求,全部接納數(shù)據(jù)消耗比較多的時(shí)間。
2. Multipart類型的大文件流請求無法做到合理快速過濾。(參數(shù)錯(cuò)誤請求,數(shù)據(jù)文件過多請求,文件大小過大請求)
歸結(jié)來說,TOP平臺處理的服務(wù)在解析參數(shù)時(shí)比較消耗時(shí)間和帶寬(客戶端網(wǎng)絡(luò)速度慢導(dǎo)致傳輸字節(jié)流比較慢,文件比較大導(dǎo)致帶寬占用嚴(yán)重)
處理方式:
通過自行解析字節(jié)流方式來lazy化處理請求,減少無效請求對于解析參數(shù)時(shí)間消耗(導(dǎo)致web容器連接消耗)及帶寬消耗。
優(yōu)化目標(biāo):
Get由于內(nèi)容長度有限不列入在優(yōu)化范圍。
優(yōu)化Post方式的請求(普通的和Multipart),要求優(yōu)化后:在正常請求處理上兩者處理速度不低于傳統(tǒng)方式,非正常請求在策略命中情況下(后面會(huì)談到什么情況下優(yōu)化失效),性能有明顯提高。
具體實(shí)現(xiàn):
由于現(xiàn)在用的是傳統(tǒng)IO模式,因此可以用流的方式來lazy解析和處理請求(NIO用channel + buffer package就無法lazy了)。
一共有三個(gè)組件角色:
1. 請求處理配置策略:配置在解析參數(shù)時(shí),優(yōu)先的規(guī)則(參數(shù)可以從header,uri,post body中獲取,相互之間的優(yōu)先性),異常拋出規(guī)則(字節(jié)流長度,文件大小,文件個(gè)數(shù)限制等),字節(jié)流解析模塊的參數(shù)配置(字節(jié)流解析的窗口大小,超時(shí)時(shí)間等)。
2. 線程上下文:用來保存處理過的請求參數(shù)。一來復(fù)用,二來也是由于請求字節(jié)流處理不可逆(不保存字節(jié)流副本),必須保留。
3. Http請求字節(jié)流解析模塊。根據(jù)具體的配置以及解析策略來解析字節(jié)流,同時(shí)將解析結(jié)果保存在線程上下文中。主要的實(shí)現(xiàn)代碼在于對Post消息體逐步解析部分(普通的Post和multipart)
壓力測試結(jié)果:
• 正常請求場景( 100并發(fā)用戶,multipart 文件大小300k,當(dāng)前業(yè)務(wù)場景這個(gè)值已經(jīng)滿足了):
普通post的處理能力1000TPS。(servlet方式處理差不多,不過有波動(dòng))
multipart處理能力610TPS。(apache開源項(xiàng)目fileupload,處理能力400TPS左右)
錯(cuò)誤請求場景
異常情況的處理有了很大提高,對于遠(yuǎn)程客戶端傳輸較慢或者是大流量圖片的錯(cuò)誤請求都有很大的優(yōu)化。
優(yōu)化存在問題:
1. 參數(shù)缺失導(dǎo)致優(yōu)化失效。
2. sign類似的交驗(yàn),導(dǎo)致獲取所有的參數(shù)。
3. 當(dāng)前圖片限制在300k,由于考慮處理速度快,就都沒有設(shè)置超過閥值存儲到本地,因此在高并發(fā)大流量的情況下也會(huì)有內(nèi)存問題,當(dāng)然已經(jīng)做了部分保護(hù)。
針對上面的兩個(gè)問題,作了部分的協(xié)議限制,對于API2.0希望將所有的系統(tǒng)參數(shù)和業(yè)務(wù)參數(shù)區(qū)分開,放入到Http header中或者url中,這樣可以避免系統(tǒng)參數(shù)缺失導(dǎo)致優(yōu)化失敗,同時(shí)大量過濾系統(tǒng)參數(shù)出現(xiàn)問題的無效請求。
Sign類似的交驗(yàn)放在流程最后,避免過早獲取所有參數(shù)。
作安全保護(hù),設(shè)定簡單丟棄或者io交互來緩解這個(gè)問題。
這部分內(nèi)容還有很多可以做得工作,其實(shí)最初的目的就是為了防止系統(tǒng)對于無效請求的處理消耗,我想在很多系統(tǒng)都會(huì)有這樣的問題,利用緩存設(shè)置黑名單防止攻擊也是這樣的初衷。因此這點(diǎn)可以考慮在很多系統(tǒng)設(shè)計(jì)的時(shí)候都作一樣的優(yōu)化,對正常的不能優(yōu)化,起碼對錯(cuò)誤的可以做一些優(yōu)化,防止在異常請求高漲的時(shí)候,系統(tǒng)被擊垮.
Email:fangweng@taobao.com
Blog:http://blog.csdn.net/cenwenchu79
其實(shí)想說這句話很久了,和很多同事接觸,有時(shí)候或多或少的都會(huì)發(fā)現(xiàn)大家會(huì)陷入在自己的一畝三分地里面.
主要表現(xiàn)得癥狀
1. PD的需求就是目標(biāo),踏實(shí)的實(shí)現(xiàn),不懂的就猜。
2. 經(jīng)驗(yàn)蓋過一切,設(shè)計(jì)系統(tǒng)就是要夠完備夠復(fù)雜。
從開發(fā)人員角度來看,第一種人多半比較有自己的想法,同時(shí)也有不少的工作經(jīng)驗(yàn),同時(shí)可能對技術(shù)比較著迷。另一種人多半是剛剛工作或者經(jīng)驗(yàn)不足,要么就是習(xí)慣性把工作當(dāng)任務(wù),而不是愛好,寫程序也就是一份賺錢的活。但看起來其實(shí)各自都在自己的一畝三分地上搗鼓,忘記了作為一個(gè)開發(fā)人員最基本的原則:“滿足客戶需求”。
先說1類型吧,在我們的Team有一個(gè)剛畢業(yè)一年多的同學(xué),很勤奮,不論從學(xué)習(xí)以及工作,實(shí)實(shí)在在,踏踏實(shí)實(shí)。我們這邊來需求,通常大需求我們都會(huì)全體過一下,一些小點(diǎn)的需求他就自己考慮一下就作了。那天正要上線,突然說了一下設(shè)計(jì)修改的內(nèi)容,發(fā)現(xiàn)不僅滿足不了PD原有的需求,而且給系統(tǒng)帶來了緩存暴增的隱患。然后找來PD一談,其實(shí)他要的功能已經(jīng)在現(xiàn)有系統(tǒng)中已經(jīng)實(shí)現(xiàn),只是需要做部分的修改,而不需要新的去建立一套機(jī)制。這樣的情況其實(shí)在前前后后出現(xiàn)了不少次數(shù)了,但其實(shí)一直沒有和他細(xì)談。后來我下班時(shí)候和他一起回家的時(shí)候說:“很多時(shí)候, PD為了讓你理解,從開發(fā)的角度想要去描述一個(gè)需求,但其實(shí)最終失去了他自己想要的東西。因此對你來說第一步不是急忙的去考慮如何實(shí)現(xiàn)PD的想法或者和他爭論他的設(shè)計(jì)是否合理,而是需要先問他:你想要什么,想要實(shí)現(xiàn)的東西最終目的是什么,能滿足客戶的什么需求?當(dāng)他能夠說清楚他想要什么,也知道要的東西能給客戶帶來什么價(jià)值的時(shí)候,我們再回過頭來看,究竟應(yīng)該怎么做?”這其實(shí)和我每次和同學(xué)分享一些設(shè)計(jì)的時(shí)候步驟是一樣的,首先為什么要這么做,然后才是考慮如何從我的目標(biāo)去尋找行動(dòng)的方法方式,不然你會(huì)發(fā)現(xiàn)你和別人討論了許久的東西,實(shí)現(xiàn)出來的時(shí)候已經(jīng)背離了你的目標(biāo)很遠(yuǎn)。因此在做任何需求或者設(shè)計(jì)的時(shí)候第一個(gè)問題就要問自己為什么要做,作的過程中時(shí)刻要記得我的目標(biāo)是什么。這讓我想起了我在離開阿軟的那些日子和王堅(jiān)博士談話以及聽他的一些對于設(shè)計(jì)的理念,很多時(shí)候還沒有到規(guī)模化的情況下,先解決客戶的需求,在解決客戶需求以后,逐步的去考慮規(guī)模化問題的設(shè)計(jì)。(當(dāng)然不是說第一版設(shè)計(jì)就可以隨便作,良好的基礎(chǔ)能夠提升后續(xù)改進(jìn)的速度)。
二類型的就比較多了,其實(shí)是很多開發(fā)人員的通病,包括有時(shí)候我自己也會(huì)陷入這樣的誤區(qū)。通常情況下有兩種場景會(huì)陷入這樣的誤區(qū),同時(shí)當(dāng)事人卻又不愿意改變。第一種情況就是覺得自己有不少的經(jīng)驗(yàn),同時(shí)對技術(shù)很執(zhí)著,希望設(shè)計(jì)出來的都是很完美的,一次發(fā)布就可以滿足個(gè)1,2年,但其實(shí)從這些年的設(shè)計(jì)角度來看,首先系統(tǒng)都是不斷迭代進(jìn)化的,因此一步到位的說法基本上不靠譜(除非就是一模一樣的場景代碼重復(fù)使用),其次系統(tǒng)的架構(gòu)要做的足夠靈活,通常情況就需要先做核心功能,預(yù)留出足夠的空間和切入點(diǎn),這樣對未來擴(kuò)展和需求變化有足夠的適應(yīng)度。從這兩點(diǎn)來看,其實(shí)設(shè)計(jì)初期就是要求找到客戶最想要的,擴(kuò)展可以實(shí)現(xiàn)客戶可能要的,防范客戶沒有估量到的。但這其實(shí)就需要和我們的產(chǎn)品設(shè)計(jì)師有充分的交流,好的產(chǎn)品設(shè)計(jì)師不會(huì)告訴你你怎么去實(shí)現(xiàn),但是他會(huì)告訴你我想要的是什么,這些能給客戶帶來什么,這時(shí)候你可以告訴他我能夠通過什么方式來滿足你的需求。這樣的開發(fā)和產(chǎn)品設(shè)計(jì)交流的結(jié)果才是技術(shù)化的產(chǎn)品,大家各司其職,同時(shí)也通曉對方領(lǐng)域的一些情況,對對方領(lǐng)域的只能給出建議,不是指導(dǎo),這點(diǎn)在TOP我很慶幸有很好的黑羽同學(xué),我們的交流就是這樣產(chǎn)生良性互動(dòng)。這有點(diǎn)撤遠(yuǎn)了,剛才說了第一種場景,然后說說第二種場景,就是初期其實(shí)大家都沒有明確細(xì)節(jié),但是在實(shí)施過程中開發(fā)人員會(huì)根據(jù)自己的接觸面來選擇一些技術(shù)和架構(gòu)設(shè)計(jì),最后看起來很復(fù)雜,很完美,但其實(shí)越是復(fù)雜的設(shè)計(jì)背后有越多的隱患。但是此時(shí)因?yàn)橐呀?jīng)設(shè)計(jì)好了,就不愿意再去簡化,也不愿意聽任何人的意見,其實(shí)這是很危險(xiǎn)的。我過去也犯過類似的錯(cuò)誤,但是其實(shí)當(dāng)你冷靜下來,想想那句話,我們的目標(biāo)是什么:“滿足客戶需求”,這時(shí)候你就會(huì)考慮,這么復(fù)雜的系統(tǒng)會(huì)不會(huì)給客戶帶來更多的不穩(wěn)定以及復(fù)雜度,其實(shí)客戶不關(guān)心你背后如何實(shí)現(xiàn)的,但是你需要滿足客戶的最基本的需求,用起來方便,高效,實(shí)實(shí)在在提供了解決問題的手段。
今天下午面試了一個(gè)外部的同學(xué),工作年限比我長,看了簡歷也經(jīng)歷了很多項(xiàng)目,同時(shí)在描述的時(shí)候?qū)懥藢Ω卟l(fā),分布式等等都很熟悉和熱衷,我開始看了簡歷就擔(dān)心,可能我這邊不一定要他,因?yàn)槲遗滤_口就是說一大堆如何做高并發(fā)和分布式的內(nèi)容。在我看來如果你沒有搞清楚你什么時(shí)候要用牛刀,什么時(shí)候要用剪刀的人,和你談?wù)撆5兜臉?gòu)造其實(shí)沒啥意思,因?yàn)樵谖铱磥恚夹g(shù)只要你肯花時(shí)間去學(xué),沒什么學(xué)不到的,但是做事方式和項(xiàng)目設(shè)計(jì)經(jīng)驗(yàn)卻是長時(shí)間積累的。幸好今天和他一談,他對于技術(shù)的態(tài)度以及架構(gòu)設(shè)計(jì)的思想都和我想的比較接近,不是為了技術(shù)而技術(shù),不是為了過程而過程,了解如何從簡如繁,再從繁入簡,最終能夠找到自己的目標(biāo)。當(dāng)然后來還是談了很多技術(shù)細(xì)節(jié)的問題,畢竟干活還是要一個(gè)好手,作了那么多年如果沒有經(jīng)驗(yàn)和技術(shù)積累也是很可怕的事情。最后我問了他兩個(gè)問題:1.你學(xué)習(xí)一個(gè)新技術(shù)的過程是怎么樣的?2.你和你同事如果在設(shè)計(jì)方案上有沖突你怎么解決?他告訴我他學(xué)習(xí)新技術(shù)首先會(huì)去考慮這個(gè)技術(shù)的特點(diǎn)是什么,和其他技術(shù)的差別,他的擅長領(lǐng)域是什么,這樣才能夠用到實(shí)處。第二個(gè)問題他和我說就是開會(huì)討論,最后大家群體決定。我對他第一個(gè)問題感到很滿意,因?yàn)槲揖托枰@樣的同事,第二個(gè)問題我給了他一個(gè)建議,其實(shí)在很多時(shí)候,將別人的架構(gòu)設(shè)計(jì)的優(yōu)點(diǎn)融入到自己的設(shè)計(jì)中,不再以方案作為邊界,那么大家最終就很容易達(dá)成一致,因?yàn)槟阍诮邮軇e人的思想時(shí)其實(shí)能夠看到自己的不足,同時(shí)對待別人不是用否定的態(tài)度,會(huì)讓你更容易得到認(rèn)可和接受。(這點(diǎn)作起來需要不斷的改變程序員自身的好勝個(gè)性,我起碼還是出于變化中…)
我記得我小時(shí)候上政治課的時(shí)候,老師給我們劃分了三種人:有能力但是沒有道德的人是危險(xiǎn)的人,沒有能力但是有道德的人是對社會(huì)無害的人(覺得像葛優(yōu)說的那個(gè)對社會(huì)無害的海龜一個(gè)概念),有能力同時(shí)也有道德的人是對社會(huì)有益的人。我覺得其實(shí)程序員也就可以從兩個(gè)緯度看:
1. 有能力,有經(jīng)驗(yàn),對技術(shù)有追求。
2. 對產(chǎn)品化和客戶沒有任何感覺。
擁有了素質(zhì)1但是沒有素質(zhì)2,那么最多也就只能說是試驗(yàn)室的花朵,在大學(xué)搞搞研究還不錯(cuò),實(shí)際要做出產(chǎn)品來可能就是紙上談兵,好鋼始終用不到刀刃上,有力沒地使。
素質(zhì)1有所欠缺,素質(zhì)2很明晰,對自己目標(biāo)不斷追求,其實(shí)這樣的人,有時(shí)候笨鳥也會(huì)飛的比聰明的鳥更高。
擁有1,2的人,當(dāng)然就是最好的人,只需要學(xué)會(huì)做人那么就可以發(fā)揮自己的能量。(程序員有時(shí)候就是很難改變自己的個(gè)性,去學(xué)會(huì)如何溝通和理解)
最后一類就是自以為有1和2的人,這類人最怕就是面試的時(shí)候被考官通過,那么后續(xù)的問題就大了。
說了怎么多,其實(shí)也無非想說出一個(gè)程序員這些年的經(jīng)歷,從做開發(fā)到做基礎(chǔ)平臺,到做業(yè)務(wù)平臺,該怎么踏實(shí)做事,該在什么時(shí)候找到自己的瓶頸,該在什么時(shí)候改變自己的狀態(tài),都需要自己好好的讓自己冷靜下來想想。做基礎(chǔ)平臺需要耐得住寂寞,同時(shí)也要知道自己是有客戶的,服務(wù)不好客戶,那么基礎(chǔ)組件平臺就是玩具。做業(yè)務(wù)平臺需要學(xué)會(huì)去分析和溝通,需要去了解每一個(gè)層次的設(shè)計(jì)如何協(xié)作,同時(shí)在兼顧業(yè)務(wù)需求的同時(shí)滿足隱性需求(穩(wěn)定性,可用性,響應(yīng)速度,規(guī)模化等等)。但歸根到底,能給開發(fā)人員不斷能量的不是技術(shù)本身,而是你用技術(shù)給你的客戶帶來的價(jià)值,對你的認(rèn)可是長期做事的一個(gè)最基本的動(dòng)力,因?yàn)楫?dāng)你現(xiàn)在覺得純做技術(shù)能夠支持你不斷向前走的時(shí)候,其實(shí)在不遠(yuǎn)的將來你會(huì)體會(huì)到原來過程和目標(biāo)是同樣重要的。走出自己的一畝三分地,給自己多一點(diǎn)的空間,會(huì)讓自己看得更遠(yuǎn),走的更高。
今年blog更新的速度比去年慢很多,當(dāng)然最大的原因就是工作的轉(zhuǎn)變。當(dāng)選擇留在云公司還是去淘寶,自己做了很快的抉擇,去淘寶。其實(shí)在阿軟的后面這一年,對自己來說是一個(gè)技術(shù)提升的階段,工作任務(wù)不緊,技術(shù)預(yù)研范圍較大,但對于自己這么一個(gè)已經(jīng)到了30的人來說,應(yīng)該是把技術(shù)轉(zhuǎn)變?yōu)楫a(chǎn)品的時(shí)候了,因此義無反顧地選擇了TOP作為我新的開端。
其實(shí)每個(gè)人都會(huì)有自己不同的階段,任何階段都有自己的目標(biāo),同時(shí)當(dāng)你發(fā)現(xiàn)在一個(gè)階段停留很久,都沒有什么突破,或者漸漸失去目標(biāo)的時(shí)候,那么就需要考慮如何找到新的起點(diǎn)。對我來說,技術(shù)追求和提升是沒有止盡的,但是需要真正的將所學(xué)的作出一點(diǎn)實(shí)在的產(chǎn)品,同時(shí)在參與產(chǎn)品團(tuán)隊(duì)的過程中,學(xué)會(huì)溝通,交流,分析問題,全面地看問題,這些也是不可缺少的成長經(jīng)驗(yàn),如果僅僅局限在狹隘的某一個(gè)技術(shù)立領(lǐng)域,那么就和普通的學(xué)生無異。
到了TOP,自己的工作分成了三大塊:1.救火及防火。2.整體架構(gòu)支持。3.核心代碼的編寫。前期花了不少時(shí)間在1上,同時(shí)和各個(gè)Team交流,參與各個(gè)團(tuán)隊(duì)的關(guān)鍵性設(shè)計(jì)評審,以及對平臺的統(tǒng)一規(guī)劃,讓我實(shí)實(shí)在在的作了一點(diǎn)2的事情。(說道實(shí)實(shí)在在,記得在阿軟很多團(tuán)隊(duì)都抱怨我所在的架構(gòu)組整天派一個(gè)人掛個(gè)名字,然后就算是架構(gòu)支持了,當(dāng)然這有很多原因造成,并不一定是負(fù)責(zé)架構(gòu)的同學(xué)的問題)。對于3這點(diǎn)當(dāng)然是自己最樂意做的,也是自己一直告誡自己要不斷提升的,不論自己有多少理由說自己忙碌,寫代碼是我們這種人的生命所在,不然就會(huì)漂浮在空中,漸漸的走向“另一個(gè)世界”。 但自己覺得其實(shí)還少了一塊,就是對業(yè)界的發(fā)展深入了解,這會(huì)讓我看的不夠遠(yuǎn)(幸好我們的產(chǎn)品經(jīng)理黑羽同學(xué)總還會(huì)給我一些新的思路),到了年底將會(huì)多花一點(diǎn)時(shí)間作這部分內(nèi)容。
去年年底我寫了關(guān)于對于Open API的思考和探索的一篇文章作為年底總結(jié),今年一樣,對于當(dāng)前自己的工作將會(huì)有一份總結(jié)和規(guī)劃,即是對今年平臺發(fā)展的一個(gè)回顧,也是對平臺未來的一點(diǎn)思考,大致已經(jīng)列了一個(gè)綱要,對外可能部分內(nèi)容不能全寫出來,不過就算不寫細(xì)節(jié)也會(huì)將一些思路寫一下,大家可以相互探討一下。這部分內(nèi)容也將會(huì)成為我12月份參加淘寶內(nèi)部淘寶大學(xué)講課的內(nèi)容,希望能夠?qū)⒔衲晷逻M(jìn)淘寶的同學(xué)吸引到TOP來,為TOP增加人氣。
下面是一個(gè)mind 圖,大致描述了一些內(nèi)容:
今天是轉(zhuǎn)崗到淘寶的第七天,也算是一周吧,期待來這個(gè)團(tuán)隊(duì)已經(jīng)有快大半年了,這次阿軟的重組給了一個(gè)機(jī)會(huì),過去的就過去吧,不再回首有任何的抱怨和遺憾,需要面對的是新的將來。
很奇怪,來到淘寶,都是熟人,Boss是早就相識的菲青,TOP團(tuán)隊(duì)的自雪,鳳先,秀芳及我不認(rèn)識但是認(rèn)識我的其他同學(xué)都很熱情,運(yùn)營,PD,OST都是以前阿軟的老同學(xué),還有其他幾個(gè)團(tuán)隊(duì)的朋友,感覺回到了家,而不是離開了家。
原先來淘寶是比較堅(jiān)決的,同時(shí)也得到王博士的支持,心里還是比較有底的,不過就是擔(dān)心過來以后和淘寶已有的團(tuán)隊(duì)合作可能會(huì)有磨合期,因?yàn)閾?dān)心有“小圈子”。結(jié)果卻是很出乎我的意料,TOP的人就和做的事情一樣,是一批開放的人,自雪,鳳先,張三各個(gè)都很放的開的和我聊,對于架構(gòu),對于技術(shù),對于未來的發(fā)展,這些人坐在一起什么都可以說,自己覺得自己早先是用老思維來看待這個(gè)團(tuán)隊(duì)了。這個(gè)團(tuán)隊(duì)很年輕,很有活力和創(chuàng)造力,缺少的只是一些經(jīng)驗(yàn),而我經(jīng)驗(yàn)是有一些,但是那些斗志已經(jīng)在去年一年被磨礪的差不多了,正好是我回爐好好再熱一熱的時(shí)候了。來之前就和黑羽有過接觸,也看過他對于TOP的一些構(gòu)想,在我的計(jì)劃中就有和他交流的部分,上周找了一個(gè)時(shí)間碰了一下,果然有很多和我一致的想法,同時(shí)還有一些比我更加深入的idea,特別是對于大淘寶未來的一個(gè)構(gòu)想。其實(shí)來到TOP我所要做的就是在技術(shù)的架構(gòu)上找到商業(yè)的感覺,讓商業(yè)驅(qū)動(dòng)技術(shù),技術(shù)沉淀積累來支持商業(yè)的暢想。
這七天過的很快,全身心投入的工作,時(shí)間總是過的很快,而且過去那種沉悶的心情和處事的態(tài)度在這里得到了改變。明天基本上就看完了TOP的大部分代碼,整理了一些review的建議,同時(shí)昨天還花了一些時(shí)間去看了看google appengine,寫了幾個(gè)小應(yīng)用,看了看源碼(部分反編譯),因?yàn)橐oboss對于小應(yīng)用hosting方面的一些想法。
總的來說還是和我原先的計(jì)劃一樣,商業(yè)上和PD運(yùn)營交流,了解未來TOP商業(yè)發(fā)展方向,以及對技術(shù)架構(gòu)的一些需求。架構(gòu)上從代碼和文檔看起,文檔不是很多,所以就只好每個(gè)工程看過來,也不錯(cuò),看到自雪同學(xué)寫的代碼還是不錯(cuò)的,同時(shí)也看到了淘寶的基礎(chǔ)組件的推廣力度之大,這比在阿里軟件強(qiáng)的多,其實(shí)也是我一直希望看到的,人人都是技術(shù)牛人,都在做重復(fù)的事情,但是卻沒有技術(shù)沉淀,其實(shí)大家完全可以吧自己的構(gòu)想增強(qiáng)在別人的基礎(chǔ)之上,而不是什么都自己搞一套,淘寶的技術(shù)應(yīng)該來說在政策上得到了支持,技術(shù)積累效果還是不錯(cuò)的,這里還不得不提到我的淘寶同學(xué)畢玄同學(xué)的服務(wù)基礎(chǔ)框架HSF,雖然現(xiàn)在還沒有接觸,但是應(yīng)該已經(jīng)發(fā)展的挺好的。
有兩個(gè)能夠用人,擔(dān)得起起技術(shù)團(tuán)隊(duì)發(fā)展的Boss,有這么一些年輕有沖勁的小同學(xué),有這么一些樂于傾聽分享協(xié)作的老同學(xué),有這么一些很有商業(yè)feeling的非技術(shù)團(tuán)隊(duì)同學(xué),要做好TOP,我想只有三個(gè)字:“沒問題”。這是我在入職七天寫的隨記,一年后再來回看我今天說的這些話,在來看看這個(gè)團(tuán)隊(duì)創(chuàng)造的價(jià)值。
附:在淘寶申請好了花名:放翁。陸游的字,武俠小說的人就連掃地的都沒有了,歷史名人也沒有了,不過詩人倒是沒有人用,指不定還開創(chuàng)了淘寶同學(xué)入職的花名新取法。
好好工作,天天向上,為了TOP,為了家里的BB,為了自己的一點(diǎn)理想,踏踏實(shí)實(shí)的走自己的路,讓別人開車去吧,^_^
本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/cenwenchu79/archive/2009/08/12/4440248.aspx
昨天是去淘寶工作的第一天,最近最頭痛的就是花名,在我兒子出生的時(shí)候我就知道起名字是最麻煩的事情,而起花名更是痛苦,因?yàn)槟愕倪x擇余地更小,同時(shí)還不能和前人重復(fù),好不容易找到兩個(gè)還不錯(cuò)的,結(jié)果一個(gè)給其他部門的老大保留了,一個(gè)因?yàn)槠匆艉鸵粋€(gè)同學(xué)相似而無法使用。想用文初,結(jié)果還給一個(gè)淘寶的活躍用戶使用了,問了HR不取花名是否可以,回答說,不可以,太折騰了。
昨天開了一整天的會(huì),主要還是協(xié)調(diào)兩個(gè)平臺之間將來的合作模式,同時(shí)也梳理了雙方的現(xiàn)有功能,將未來雙方的邊界做了初步定奪,同時(shí)也對將來的一些需求做了初步的規(guī)劃,系統(tǒng)的模塊化也提上了最近的日程。
今天會(huì)化一些時(shí)間看看已有的代碼熟悉一下Top的情況,同時(shí)也看看一些流程性的文檔,希望能夠盡快的對Top全方位的了解,這樣便于從細(xì)節(jié)實(shí)現(xiàn)到整體架構(gòu)設(shè)計(jì)都能給出自己的意見。
初來乍到不容易,很多需要從新開始的,不過對我來說合作的人,做的事情還是有一定的基礎(chǔ),因此只是需要一周左右的過渡期,后續(xù)應(yīng)該會(huì)走的更加順暢。
Author : 岑文初
Email: wenchu.cenwc@alibaba-inc.com
Blog: http://blog.csdn.net/cenwenchu79
Date: 2009-5-26
目錄
需求轉(zhuǎn)而學(xué)習(xí)
很多時(shí)候不少做開發(fā)的同學(xué)都認(rèn)為技術(shù)更新的快,新技術(shù)、新概念層出不窮,大家樂此不疲的去跟隨著所謂的“技術(shù)趨勢”走在風(fēng)頭浪尖上,但其實(shí)往往忘記了一個(gè)最重要的問題“滿足客戶需求”。其實(shí)技術(shù)就是為滿足需求服務(wù)的,用最小的代價(jià)來滿足用戶的需求,以最簡單高效的方式來達(dá)到目標(biāo),就是每個(gè)開發(fā)者應(yīng)該追求的。(不要因?yàn)樽约旱募軜?gòu)很簡單就臉紅拿不出手,只要你在滿足用戶當(dāng)前需求的基礎(chǔ)上對未來有所考慮,那么化繁為簡就是一種能力的表現(xiàn))
SIP(服務(wù)集成平臺)5.7版本中對于未來多個(gè)服務(wù)提供商,多種類型的服務(wù),在每日幾億的調(diào)用壓力下,需要找到一個(gè)解決方案:可以分流不同服務(wù)提供商的服務(wù),分流不同類型的服務(wù),服務(wù)隔離化來減少服務(wù)相互之間影響以及服務(wù)提供商之間的影響。
當(dāng)前SIP的前端是通過硬件F5作負(fù)載均衡,因此是無狀態(tài)無差別的服務(wù)負(fù)載,這也使得無法區(qū)分不同的服務(wù)提供商的服務(wù)請求和不同類型的服務(wù)請求,導(dǎo)致服務(wù)提供商之間的服務(wù)會(huì)產(chǎn)生相互影響(旺旺即時(shí)通信類API在峰值占用了大部分的服務(wù)處理資源,淘寶寶貝上傳類API占用了大量的帶寬)。近期還有更大的兩類API將會(huì)接入,因此尋找一個(gè)服務(wù)可分流的方案勢在必行。(當(dāng)然過去也考慮通過三級域名配置在負(fù)載均衡上來解決這些問題,但是這樣首先對于開發(fā)者來說不透明,其次也是一種比較僵化的設(shè)計(jì)方案,擴(kuò)展和維護(hù)也有一定的難度)
在過去也嘗試過Apache等Web容器自己的一些load balance特性,當(dāng)然效果不是很好,和硬件基本無法比擬,而一些專有的“軟”負(fù)載均衡方案和開源項(xiàng)目也沒有深入的去了解,因此借著這次機(jī)會(huì),好好深入的挖一挖“軟”負(fù)載均衡。
“軟”負(fù)載均衡
作為互聯(lián)網(wǎng)應(yīng)用,隨時(shí)都需要做好用戶量突然增大,訪問量突然上升的準(zhǔn)備。今年熱門的詞匯“云”我就不多說了,這里就簡單說說服務(wù)器的橫向擴(kuò)展。其實(shí)和DB,文件系統(tǒng)等一樣,當(dāng)資源成為瓶頸的時(shí)候,就需要考慮如何通過擴(kuò)展或者提升資源能力來滿足用戶的需求,這就是我們常說的橫向擴(kuò)展和縱向擴(kuò)展。(對于橫向擴(kuò)展和縱向擴(kuò)展的優(yōu)劣大家應(yīng)該都很清楚了,這里也不做贅述)橫向擴(kuò)展中就會(huì)要求使用負(fù)載均衡的能力,如何根據(jù)資源能力不同以及資源在運(yùn)行期負(fù)荷動(dòng)態(tài)變化將負(fù)載合理分配是判斷負(fù)載均衡優(yōu)劣的標(biāo)準(zhǔn)。
軟件負(fù)載均衡一般通過兩種方式來實(shí)現(xiàn):基于操作系統(tǒng)的軟負(fù)載實(shí)現(xiàn)和基于第三方應(yīng)用的軟負(fù)載實(shí)現(xiàn)。LVS就是基于Linux操作系統(tǒng)實(shí)現(xiàn)的一種軟負(fù)載,HA Proxy就是基于第三應(yīng)用實(shí)現(xiàn)的軟負(fù)載。(后面會(huì)詳細(xì)介紹這兩種方式的使用)
最早期也是最原始的軟負(fù)載均衡:“Round Robin DNS”,通過輪詢方式在DNS綁定多個(gè)IP的情況下,將用戶對于同一個(gè)域名的請求分配到后端不同的服務(wù)節(jié)點(diǎn)。這種方案的優(yōu)點(diǎn):配置簡單,負(fù)載分配效率高。缺點(diǎn):無法知曉后端服務(wù)節(jié)點(diǎn)服務(wù)情況(是否已經(jīng)停止服務(wù)),無法保證在一個(gè)Session中多次請求由一個(gè)服務(wù)節(jié)點(diǎn)服務(wù),每一個(gè)節(jié)點(diǎn)都要求有一個(gè)外網(wǎng)IP。
另一種較為常見的就是基于分發(fā)器的Load balance。服務(wù)使用者通過向分發(fā)器發(fā)起請求獲得服務(wù),分發(fā)器將請求分發(fā)給后端實(shí)際服務(wù)處理的節(jié)點(diǎn),給客戶提供服務(wù),最常說的反向代理模式就是典型的分發(fā)器Load Balance。這類負(fù)載均衡處理可以基于應(yīng)用級轉(zhuǎn)發(fā),也可以基于IP級別轉(zhuǎn)發(fā),當(dāng)然基于應(yīng)用轉(zhuǎn)發(fā)效率和損耗比較大,同時(shí)分發(fā)器本身也會(huì)成為瓶頸。
LVS (Linux Virtual Server)
LVS是在Linux操作系統(tǒng)基礎(chǔ)上建立虛擬服務(wù)器,實(shí)現(xiàn)服務(wù)節(jié)點(diǎn)之間的負(fù)載均衡。LVS主要是處理OSI模型中的4層消息包,根據(jù)一定的規(guī)則將請求直接轉(zhuǎn)發(fā)到后端的服務(wù)處理節(jié)點(diǎn),有較高轉(zhuǎn)發(fā)效率。
Virtual Server是Load Balancer和一組服務(wù)器的邏輯組合統(tǒng)稱,使用服務(wù)者只需要與Virtual Server進(jìn)行交互就可以獲得高效的服務(wù)。真實(shí)服務(wù)器和Load Balancer通過高速LAN進(jìn)行交互。Load Balancer能夠?qū)⒄埱蠓职l(fā)到不同的服務(wù)端,在一個(gè)虛擬IP下并行處理多個(gè)請求。
Virtual Server三種模式介紹
Virtual Server有三種基于IP級別的負(fù)載均衡實(shí)現(xiàn)方式:IP address translation(NAT)、Direct routing、IP Tunneling。
NAT(Network address translation):由于IPV4的某些缺陷和安全原因,某些網(wǎng)段例如(10.0.0.0/255.0.0.0, 172.16.0.0/255.240.0.0 and 192.168.0.0/255.255.0.0)不能被用于互聯(lián)網(wǎng),因此常常被用作內(nèi)部局域網(wǎng),通過網(wǎng)絡(luò)地址翻譯的方式可以讓這些網(wǎng)段的服務(wù)器訪問互聯(lián)網(wǎng)或者被互聯(lián)網(wǎng)訪問。網(wǎng)絡(luò)地址翻譯主要作用就是將一組ip地址映射到其他的一組ip地址,當(dāng)映射比例為1:1的時(shí)候通常稱作靜態(tài)映射,而當(dāng)映射地址為M:N(M>N)的時(shí)候(M為被映射地址數(shù)量,通常是內(nèi)部ip),則成為動(dòng)態(tài)映射。而對于Virtual Server的NAT模式來說,就是利用了NAT的特性,將內(nèi)部的一組服務(wù)器通過映射到一個(gè)虛擬的IP,然后以一個(gè)外網(wǎng)虛擬服務(wù)節(jié)點(diǎn)的身份對外提供服務(wù)。
上圖是一個(gè)實(shí)際的NAT范例,對外的服務(wù)IP為202.103.106.5,內(nèi)部建立了虛擬IP為172.16.0.1,然后將內(nèi)部其他兩臺實(shí)際服務(wù)的服務(wù)器172.16.0.2,172.16.0.3映射到172.16.0.1這個(gè)虛擬IP。客戶端向202.103.106.5發(fā)起請求服務(wù),Load Balancer查看請求數(shù)據(jù)包,如果是請求目標(biāo)地址是注冊的虛擬IP及監(jiān)聽端口的時(shí)候,那么通過NAT按照一定算法選擇某一臺實(shí)體服務(wù)器,再重寫報(bào)文目標(biāo)地址,轉(zhuǎn)發(fā)請求到實(shí)際的目標(biāo)服務(wù)器,當(dāng)目標(biāo)服務(wù)器處理完畢以后,將處理結(jié)果返回給Load Balancer,由Load Balancer修改源地址,返回給客戶端。
IP Tunneling:IP管道技術(shù)是在IP報(bào)文上再次封裝IP報(bào)文協(xié)議的一種技術(shù)。允許將一個(gè)目標(biāo)為A的IP數(shù)據(jù)報(bào)文封裝成為目標(biāo)為B的IP數(shù)據(jù)報(bào)文,在特定的IP 管道中傳輸。
上圖就是IP Tunneling模式的運(yùn)作原理。首先客戶端還是通過訪問對外的一個(gè)服務(wù)IP請求服務(wù),當(dāng)Load Balancer接受到請求以后,檢查VIP注冊信息,然后根據(jù)算法選擇實(shí)際的一臺后臺服務(wù)器,通過IP管道封裝技術(shù)對IP報(bào)文再次封裝,然后將消息通過IP管道轉(zhuǎn)發(fā)到實(shí)際的服務(wù)器,實(shí)際的服務(wù)器通過解包處理請求,然后根據(jù)包體內(nèi)實(shí)際的服務(wù)請求地址,將處理結(jié)果直接返回給客戶端。 Direct routing:利用Load Balancer和實(shí)際服務(wù)器共享同一VIP,簡單的通過修改消息報(bào)體目標(biāo)MAC地址,轉(zhuǎn)發(fā)請求,然后再通過實(shí)際服務(wù)器配置VIP為本地回環(huán),直接處理消息報(bào)文,而不再轉(zhuǎn)發(fā),當(dāng)處理完以后,直接將處理結(jié)果返回給客戶端。
上圖就是Direct Routing的運(yùn)作流程,當(dāng)外部請求到Load Balancer時(shí),通過查找VIP注冊信息,直接選擇一臺后端服務(wù)器作為新的目標(biāo)地址,修改消息報(bào)文中的目標(biāo)地址Mac地址,轉(zhuǎn)發(fā)到目標(biāo)服務(wù)器,目標(biāo)服務(wù)器由于配置VIP在本地網(wǎng)卡回路中,因此直接處理消息,將處理完的結(jié)果直接返回給客戶端。
Virtual Server三種模式的比較
下表是官方整理出的關(guān)于Virtual Server三種不同模式的區(qū)別:
NAT |
TUNNEL |
DR |
|
服務(wù)器要求 |
無要求 |
需要支持IP管道 |
無 arp組件(當(dāng)前也有補(bǔ)丁) |
網(wǎng)絡(luò)要求 |
Private |
LAN/WAN |
LAN |
可支持后端服務(wù)器節(jié)點(diǎn)數(shù) |
較少(10-20) |
較多 |
較多 |
服務(wù)網(wǎng)關(guān) |
Load Balancer |
本身 |
本身 |
NAT:根據(jù)其實(shí)現(xiàn)原理,可以知道這種模式對于操作系統(tǒng),網(wǎng)絡(luò)都沒有太多的要求和約束,但是由于消息需要打解包,同時(shí)消息的響應(yīng)都必須經(jīng)過Load Balancer,因此Load Balancer自身成為了瓶頸,這樣一個(gè)Load Balancer能夠支持的后端服務(wù)節(jié)點(diǎn)數(shù)量就有限了。當(dāng)然可以采用混合模式來解決這個(gè)問題,也就是通過TUNNEL或者DR模式作為前端模式串聯(lián)起多個(gè)NAT模式Balancer。
TUNNEL:這種模式要求操作系統(tǒng)支持IP Tunnel,通過對IP報(bào)文再次封裝轉(zhuǎn)發(fā),達(dá)到負(fù)載均衡的目的。設(shè)計(jì)這種模式的初衷是考慮,對于互聯(lián)網(wǎng)很多服務(wù)來說,服務(wù)請求數(shù)據(jù)量和返回?cái)?shù)據(jù)量是不對稱的,返回的數(shù)據(jù)往往要遠(yuǎn)遠(yuǎn)大于請求的數(shù)據(jù)量,因此如果請求和返回都走Load Balancer會(huì)大量占用帶寬,影響處理能力。IP Tunnel設(shè)計(jì)中請求是通過Load Balancer,但是返回是直接返回到客戶端的,因此節(jié)省了返回的帶寬,提高了請求處理的能力。
DR:這種模式要求Load Balancer和后端服務(wù)器處于同一個(gè)局域網(wǎng)段。DR模式處理消耗最小,消息轉(zhuǎn)發(fā)和回復(fù)基本沒有損耗,因此效率應(yīng)該是最高的,但是約束是相對來說最多的。
小A,30,所在公司在去年的經(jīng)濟(jì)危機(jī)中沒有倒下,但是在今年卻倒下了。小A覺得能夠把一個(gè)公司混倒閉了,也算是人生的一點(diǎn)經(jīng)歷。
公司是沒了,但是工作還要繼續(xù),生活還要繼續(xù),現(xiàn)在將要面對一個(gè)新的環(huán)境,環(huán)境很陌生,但也比較熟悉,工作職責(zé)很清晰,但也充滿了挑戰(zhàn)。人過30,有了孩子,真的成熟了很多,知道了什么叫做責(zé)任感,知道了未來真的需要好好規(guī)劃,需要一個(gè)機(jī)會(huì),需要一個(gè)平臺來找到自己,實(shí)現(xiàn)自己的價(jià)值,不讓這黃金時(shí)代就這么過去。
小A將要面對的挑戰(zhàn)在心里面已經(jīng)做好了準(zhǔn)備,也有了自己的一套短期的規(guī)劃及工作安排,要成長有時(shí)候就要有壓力。在小A即將離開原來團(tuán)隊(duì)的時(shí)候,和手下的一個(gè)同學(xué)發(fā)了火,因?yàn)樵谶@陣子調(diào)整過程中,同學(xué)的心態(tài)一直變的很差,但是小A已經(jīng)竭盡全力去分析他的未來,雖然聽進(jìn)去,但是過幾天依然又開始放棄自己,這種態(tài)度讓小A原本很看好他發(fā)展的心情變得很沉重,最后就在那個(gè)探討會(huì)上說了他一些比較重的話,雖然說完以后自己也有些后悔,可能我對他和對我自己一樣,要求太高了吧,就像博士說的,如果對一個(gè)人沒有想法了,就恭維幾句即可,大家你好我好大家好,只有當(dāng)對這個(gè)人還存在一定的期望的時(shí)候才會(huì)表現(xiàn)出這種比較急切的感覺。
新的開始,新的挑戰(zhàn),新的環(huán)境,新的機(jī)遇,新的難題,新的稱呼
好的心態(tài),好的溝通,好的未來
一切都需要小A用自己的能力去證明,走自己的路,讓自己走的更好。
生活:
兒子提早10天在六月八號來到我們這個(gè)小家庭,每個(gè)好友在祝福我的同時(shí)告訴我,辛苦的日子剛剛開始。不過和大家的感覺一樣,辛苦但快樂著,在別人忙著在互聯(lián)網(wǎng)上種花種草,養(yǎng)豬養(yǎng)雞的時(shí)候,我開始扛起培養(yǎng)祖國新一代的責(zé)任。睡覺基本上很難保證連續(xù)性,早晨的運(yùn)動(dòng)也移到了晚上給兒子洗好澡以后。以前覺得就算到30歲還是覺得自己比較年輕,但是在那個(gè)23:25分兒子出來的一瞬間,自己覺得自己真的老了,需要成熟一點(diǎn)了,對兒子,對老婆。
工作:
其實(shí)今年年初的時(shí)候就有些彷徨,自己一手培養(yǎng)出來的SIP和原來的目標(biāo)漸行漸遠(yuǎn),7月份我在產(chǎn)品會(huì)議上提出了SIP6(第一階段最終版),功能,性能,可擴(kuò)展性都能夠滿足到明年中旬。雖然日訪問量就快突破1億,年底可能會(huì)到幾個(gè)億,但是這些數(shù)字對我來說只能證明這個(gè)架構(gòu)還可以,但是SIP原有的目標(biāo)已經(jīng)被拋棄,成為了一個(gè)內(nèi)部的服務(wù)集成平臺。
下個(gè)階段會(huì)在做一些中心來滿足團(tuán)隊(duì)的需要,但在我看來其實(shí)這些東西對我對團(tuán)隊(duì)的價(jià)值有限,創(chuàng)新有限,但這就是工作。
公司內(nèi)部有些變化,當(dāng)然是好是壞不得而知,不過作為我們這些level已經(jīng)處于地面的人來說也沒啥影響。
文章:
最近的文章素材其實(shí)不少,但是受到內(nèi)部技術(shù)專利申請,外部投稿的影響,能夠?qū)懗鰜碇苯淤N的越來越少,有時(shí)候也是這樣,分享固然好,但是有些時(shí)候有些東西只能夠小范圍分享。
睡覺,睡覺,中午的休息是很寶貴的,一覺醒來還繼續(xù)自己的路。(走自己的路,讓自己無路可走。沒寫錯(cuò),呵呵,覺得這樣挺搞笑的)
這篇blog的問題不能算是解決,僅僅只是一種分析和猜測,后續(xù)的一些行動(dòng)可能會(huì)證明一些猜想,也可能什么都解決不了。如果有和我相同情況的同學(xué),也知道是什么問題造成的,請不吝賜教。
問題:
上周周末,沒有和同事們出去Outing,在家管孩子,去生產(chǎn)環(huán)境觀察了一下集群機(jī)器的當(dāng)前運(yùn)行狀態(tài),發(fā)現(xiàn)應(yīng)用在這些多核機(jī)器上壓力極端不均勻。
Top一下大致狀態(tài)如下:
峰值的時(shí)候,單CPU的使用率都到了80%,這種情況對于多核服務(wù)器來說是很不正常的使用。對于Java的開發(fā)者來說,多線程編程是無法控制線程如何在CPU上分配的,因?yàn)?/span>Java本身不實(shí)現(xiàn)線程機(jī)制,說是跨平臺的語言,但是性能及特性會(huì)根據(jù)操作系統(tǒng)的實(shí)現(xiàn)有很大的差異,因此Java調(diào)優(yōu)有時(shí)候需要對系統(tǒng)配置甚至內(nèi)核作調(diào)優(yōu)。
分析:
首先在測試環(huán)境下作了多次同樣的壓力測試,嘗試了與線上一樣的操作系統(tǒng)版本,相似的配置,但測試結(jié)果卻是負(fù)載分配很均勻。
此時(shí)重新啟動(dòng)了一臺問題機(jī)器,發(fā)現(xiàn)負(fù)載降下來了,同時(shí)也很均衡,也就是說在當(dāng)前的壓力下不應(yīng)該有這樣高的cpu消耗,同時(shí)也排除了硬件或者操作系統(tǒng)的一些配置問題。
在CPU滿負(fù)荷的情況下,很多時(shí)候會(huì)認(rèn)為應(yīng)該是循環(huán)造成的,對于單個(gè)CPU的消耗更是。通過Top H查看具體到底哪一個(gè)線程會(huì)長時(shí)間消耗CPU。
可以看到PID為13659的線程是“罪魁禍?zhǔn)?#8221;,但13659究竟在干什么,是應(yīng)用的線程還是系統(tǒng)的線程,是否是陷入了死循環(huán),不得而知。接著就按照Java的土辦法,Kill -3 pid,然后看看輸出日志。
根據(jù)線程號來查找dump出來的日志中nid,發(fā)現(xiàn)這個(gè)線程是VM Thread,也就是虛擬機(jī)線程。(這里作一下轉(zhuǎn)換,將13659轉(zhuǎn)換成為16進(jìn)制就是0x355b)
用pstack看了一下這個(gè)線程的工作,結(jié)果如下:
Thread 2074 (Thread 1846541216 (LWP 13659)):
#0 0x0659fa65 in ObjectSynchronizer::deflate_idle_monitors ()
#1 0x065606e5 in SafepointSynchronize::begin ()
#2 0x06613e83 in VMThread::loop ()
#3 0x06613a6f in VMThread::run ()
#4 0x06506709 in java_start ()
#5 0x00aae3cc in start_thread () from /lib/tls/libpthread.so.0
#6 0x00a1896e in clone () from /lib/tls/libc.so.6
搜索了一下ObjectSynchronizer::deflate_idle_monitors,發(fā)現(xiàn)了sun的bug庫中有bug關(guān)于jdk1.6中由于這個(gè)方法導(dǎo)致運(yùn)行期問題的說法:http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=803cb2d95886bffffffff9a626d3b9b28573?bug_id=6781744
然后就直接去openjdk官方網(wǎng)站去查找這個(gè)類的代碼,大致了解一下他的作用,具體的代碼鏈接如下:http://xref.jsecurity.net/openjdk-6/langtools/db/d8b/synchronizer_8cpp-source.html
主要工作應(yīng)該是對資源對象的回收,在加上pstack的結(jié)果,應(yīng)該大致知道是對線程資源的管理。但具體代碼就沒有進(jìn)一步分析了。
接著就分析一下自己的應(yīng)用:
壓力測試(高強(qiáng)度、長時(shí)間)都做過,沒有發(fā)現(xiàn)什么異常。
本身應(yīng)用是否會(huì)存在的缺陷導(dǎo)致問題呢。有人說VM Thread兼顧著GC的工作,因此內(nèi)存泄露,對象長期積壓過多也可能影響,但其實(shí)在dump的結(jié)果可以看到,GC有單獨(dú)的工作線程,同時(shí)我也觀察到GC這些線程的工作時(shí)間長度,因此由于GC繁忙導(dǎo)致CPU上去,基本上來說可以排除。
其次在SIP項(xiàng)目中使用了JDK的線程池(ExecutorService)和LinkedBlockingQueue。后者以前的文章里面提到在1.5版本里使用poll方法會(huì)有內(nèi)存泄露,到1.6雖然沒有內(nèi)存泄露,但是臨時(shí)鎖對象增長的很快,會(huì)導(dǎo)致GC的頻度增加。
行動(dòng):
上面零零散散的一些分析,最終讓我決定有如下的行動(dòng):
1. 升級某一臺服務(wù)器的JDK,當(dāng)前是1.6.0_10-b33,打算升級到1.6的14版本。比較觀察多臺機(jī)器的表現(xiàn),看是否升級了JDK可以解決問題。
2. 去除LinkedBlockingQueue作為消息隊(duì)列,直接由生產(chǎn)者將生產(chǎn)結(jié)果按照算法分配給消費(fèi)者線程,避免競爭,鎖的消耗,同時(shí)也防止LinkedBlockingQueue帶來的資源消耗。
3. 測試環(huán)境繼續(xù)作長時(shí)間的壓力測試,同時(shí)可以結(jié)合Jprofile之類的工具來分析長時(shí)間后可能出現(xiàn)的問題。
后話:
這年頭真的啥都要學(xué)一點(diǎn),求人不如求己。
SA,DBA,測試都需要能夠去學(xué)習(xí)一些,起碼在初期排查問題上自己能夠做點(diǎn)啥,要不然別人也忙,自己又無從下手。就好比這次壓力測試好不容易排上隊(duì),但是還是滿足不了及時(shí)上線的需求,因此自己去LoadRunner壓,好歹給出一個(gè)零時(shí)的報(bào)告先大家看著。應(yīng)用的異常有時(shí)候是應(yīng)用本身設(shè)計(jì)問題,也可能是開發(fā)語言的問題,也可能是操作系統(tǒng)的問題,因此要去定位這種比較復(fù)雜的問題,真的需要有耐心去好好的學(xué)習(xí)各種知識,現(xiàn)在看來知識還是匱乏啊,要不然就可以分析出openjdk中可能存在的問題。
昨天在看Cache Client代碼的時(shí)候,發(fā)現(xiàn)在從資源池中獲取SocketIO部分代碼在高并發(fā)情況下效率不高,因此考慮通過一些變通的方式來提高效率,下面說的內(nèi)容僅僅是當(dāng)前自己琢磨出來可以部分提高效率的方法,希望看了這篇文章的同學(xué)能夠有更好的方式或者算法來提高效率。
情景:
Cache Client 的SocketIO資源池是一個(gè)兩級的Map,具體定義為:ConcurrentMap<String, ConcurrentMap<SockIO, Integer>>。第一級Map以Host作為Key,第二級Map以SockIO本身作為Key,三種SockIO狀態(tài)(可用,占用,廢棄)作為value。之所以采用一個(gè)Pool來存儲三種狀態(tài)主要是考慮到在高并發(fā)下,多個(gè)池之間保持原子性的復(fù)雜。
每一次獲取可用的SocketIO的操作需要經(jīng)歷:1.遍歷Host所在的Map。2.逐個(gè)比較狀態(tài)。3.原子方法獲取可用SocketIO。(并發(fā)問題所要求的,具體代碼可以下載:http://memcache-client-forjava.googlecode.com/files/alisoft-xplatform-asf-cache-2.5.1-src.jar )。
在修改過去的版本里面,首先遍歷的過程是一個(gè)固定順序的過程(keyset),這樣會(huì)導(dǎo)致在高并發(fā)的情況下,越來越多的資源申請命中率會(huì)下降,因?yàn)閴毫偸锹湓?/span>keyset靠前的那些SockIO上(重復(fù)比較)。需要考慮通過什么手段可以提高在高并發(fā)下的申請命中率。
思考:
1. 資源申請的越早,被釋放的可能性越高,因此是否可以考慮采用更新SockIO最后申請時(shí)間來作為后續(xù)申請的初步依據(jù)。(本身復(fù)雜度帶來的耗時(shí)可能會(huì)超過命中率降低帶來的損耗)
2. 采用隨機(jī)數(shù)的方式來確定keyset的起始游標(biāo),也就不是每次都從keyset第一位開始(可以把keyset看作一個(gè)首尾相接的數(shù)組)。
3. 在每次資源回收的時(shí)候紀(jì)錄下該資源為可用(當(dāng)前為每一個(gè)Host就記錄一個(gè)可能可用的資源,簡單化操作),作為申請的首選嘗試。(嘗試不成功在去遍歷)。
當(dāng)前實(shí)現(xiàn)了2,3組合,發(fā)現(xiàn)效果明顯,在500個(gè)并發(fā)下,每個(gè)線程200次操作(一系列動(dòng)作),壓力測試結(jié)果如下:
Cache test consume(cache測試總共耗時(shí)),average boundle consume(每個(gè)線程總耗時(shí)),average per request(每個(gè)線程每次操作總耗時(shí))
沒有作任何改動(dòng)以前的測試結(jié)果:
cache test consume: 11507741, average boundle consume: 57538, average per request :115
采用了2策略以后的測試結(jié)果:
cache test consume: 10270512, average boundle consume: 51352, average per request :102
采用了2,3策略以后的測試結(jié)果:
cache test consume: 9140660, average boundle consume: 45703, average per request :91
服務(wù)集成平臺5.6的性能測試進(jìn)入尾聲,這期的優(yōu)化也算告一段落。這次主要的優(yōu)化工作還是在三個(gè)方面:應(yīng)用服務(wù)器(Apache,JBoss)配置,業(yè)務(wù)流程,Cache Client包(http://code.google.com/p/memcache-client-forjava/ )。這里把過去和這次優(yōu)化對于Cache的使用作一個(gè)經(jīng)驗(yàn)分享,希望大家能夠用好Cache,提速你的應(yīng)用。
這里還是通過一些點(diǎn)滴的啟示來介紹優(yōu)化的一些心得,很多時(shí)候還是要根據(jù)具體情況來判斷如何去具體實(shí)施,因此這里所說的僅僅是在一些場景下適用,并非放之四海皆準(zhǔn)的教條。同時(shí)也希望看此文的各位同學(xué),如果有更好的思路可以給我反饋,技術(shù)在交流中才會(huì)有發(fā)展。
積少成多,集腋成裘
性能提不上去,多半是在一些容易成為瓶頸的“暗點(diǎn)”(IO,帶寬,連接數(shù),資源競爭等等)。Memcached Cache現(xiàn)在已經(jīng)被大家廣泛使用,但是千萬不要認(rèn)為對Cache的操作是低損耗的,要知道這類集中式Cache對Socket連接數(shù)(會(huì)牽涉到linux操作系統(tǒng)文件句柄可用數(shù)),帶寬,網(wǎng)絡(luò)IO都是有要求的,有要求就意味著會(huì)有損失,因此積少成多,集腋成裘。服務(wù)集成平臺是一個(gè)高速的服務(wù)路由器,其大部分的業(yè)務(wù)數(shù)據(jù),訪問控制策略,安全策略以及對應(yīng)的一些控制閥值被緩存在Cache服務(wù)端,因此對于Cache的依賴性很強(qiáng)。每一次對于客戶端的性能提升,總會(huì)給服務(wù)集成平臺性能帶來不小的影響,但是每一次優(yōu)化速度后,客戶端可以優(yōu)化的空間越來越小,這時(shí)候需要一些策略來配合,提升應(yīng)用整體性能。當(dāng)前主要采用了以下幾點(diǎn)策略:
1. 從數(shù)據(jù)獲取角度來做優(yōu)化,采用本地?cái)?shù)據(jù)緩存。(因?yàn)榇蠹业膽?yīng)用需要能夠線形擴(kuò)展,支持集群,所以才不使用應(yīng)用服務(wù)器本地緩存,但是在某些緩存數(shù)據(jù)時(shí)間性不敏感或者修改幾率較小的情況下,可以采用本地緩存結(jié)合集中式緩存,減少對遠(yuǎn)端服務(wù)器訪問次數(shù),提升應(yīng)用性能)。
Cache Client的IMemcachedCache 接口中的public Object get(String key,int localTTL)方法就是本地?cái)?shù)據(jù)緩存結(jié)合遠(yuǎn)程Cache獲取數(shù)據(jù)的接口。具體流程參看下圖:
2. 從數(shù)據(jù)更新角度,采用異步數(shù)據(jù)更新。(即不等待數(shù)據(jù)更新結(jié)果,直接進(jìn)行其他業(yè)務(wù)流程)。這類操作使用場景比較局限,首先數(shù)據(jù)不會(huì)用作判斷(特別是高并發(fā)系統(tǒng)中的閥值),其次不需要返回結(jié)果作為后續(xù)流程處理輸入(例如計(jì)數(shù)器),時(shí)時(shí)性要求比較低。(這類操作其實(shí)是采用了集群數(shù)據(jù)傳播的一種策略,原先對于集群中所有節(jié)點(diǎn)都想即時(shí)傳播到,但是這樣對于性能損失很大,因此采用key對應(yīng)的主Node采用即時(shí)設(shè)置數(shù)據(jù),其他的通過后臺任務(wù)數(shù)據(jù)傳播來實(shí)現(xiàn),由于key對應(yīng)的主Node是數(shù)據(jù)第一操作和讀取節(jié)點(diǎn),因此這類數(shù)據(jù)傳播操作時(shí)時(shí)性要求較低,適合這樣處理)。具體接口參見Cache Client 使用文檔。
3. 一次獲取,多次使用。這點(diǎn)和系統(tǒng)設(shè)計(jì)有關(guān),當(dāng)前服務(wù)集成平臺的安全流程是鏈狀的,一次請求會(huì)經(jīng)歷很多安全攔截器,而在每一個(gè)安全攔截器中會(huì)根據(jù)情況獲取具體的業(yè)務(wù)數(shù)據(jù)或者流程控制策略等緩存數(shù)據(jù),每一個(gè)安全攔截器都是彼此獨(dú)立的,在很早以前是每一個(gè)安全攔截器各自在需要數(shù)據(jù)的時(shí)候去遠(yuǎn)程獲取,但是壓力測試下來發(fā)現(xiàn)請求次數(shù)相當(dāng)多,而且好些重復(fù)獲取,因此將這些業(yè)務(wù)數(shù)據(jù)作為上下文在鏈?zhǔn)綑z查中傳遞,按需獲取和設(shè)置,最大程度上復(fù)用了數(shù)據(jù)。(其實(shí)也是一種減少數(shù)據(jù)獲取的方式)。
4. 規(guī)劃好你的Cache區(qū)。有些同學(xué)在使用Cache的時(shí)候問我是否有什么需要注意的,我覺得在使用Cache之前,針對需要緩存的數(shù)據(jù)需要做好規(guī)劃。那些數(shù)據(jù)需要放在一個(gè)Cache虛擬節(jié)點(diǎn)上,那些數(shù)據(jù)必須分開放。一方面是根據(jù)自己業(yè)務(wù)系統(tǒng)的數(shù)據(jù)耦合程度(未來系統(tǒng)是否需要合并或者拆分),另一方面根據(jù)數(shù)據(jù)量及讀寫頻繁度來合理分配(畢竟網(wǎng)絡(luò)IO還是稀缺資源)。當(dāng)然有時(shí)候業(yè)務(wù)系統(tǒng)設(shè)計(jì)者自己也不知道未來的發(fā)展,那么最簡單的方式給Key加上前綴,當(dāng)前可以合并,未來也可以拆分。同時(shí)數(shù)據(jù)粒度也需要考慮,粒度設(shè)計(jì)太小,那么交互頻繁度就會(huì)很高,如果粒度太大,那么網(wǎng)絡(luò)流量就會(huì)很大,同時(shí)將來業(yè)務(wù)模塊拆分就會(huì)有問題。
巧用Memcached Cache特有接口
Memcached Cache提供了計(jì)數(shù)器一整套接口和add,replace兩個(gè)接口。這些特有接口可以很好的滿足一些應(yīng)用的高并發(fā)性處理需求。例如對于資源訪問次數(shù)控制,采用Cache的計(jì)數(shù)器接口就可以實(shí)現(xiàn)在集群中的數(shù)量控制,原本通過Cache的get和put是無法解決并發(fā)問題的(就算是本地緩存一樣),這就是一組原子操作的接口。而Add和Replace可以滿足無需通過get方法獲取內(nèi)容,就可以對于key是否存在的不同情況作出相應(yīng)處理,也是一種原子性操作。這些原子操作接口對于高并發(fā)系統(tǒng)在集群中的設(shè)計(jì)會(huì)很有幫助。
Cache Client Cluster
Memcached Cache是集中式Cache,它僅僅是支持將數(shù)據(jù)能夠分片分區(qū)的存儲到一臺或者多臺的Cache Server實(shí)例中,但是這些數(shù)據(jù)并沒有作冗余,因此任何一個(gè)服務(wù)實(shí)例不可用,都會(huì)導(dǎo)致部分緩存數(shù)據(jù)丟失。當(dāng)然很多人采取持久化等方式來保證數(shù)據(jù)的完整性,但是這種方式對于效率以及恢復(fù)的復(fù)雜性都會(huì)有影響。
簡單的來想,為什么不把數(shù)據(jù)在多保存一份或者多份呢,當(dāng)其中一份不可用的情況下,就用另外一份補(bǔ)上。這就是最原始的Cache Client Cluster的構(gòu)想。在這里具體的設(shè)計(jì)細(xì)節(jié)就不多說了,主要說一下幾個(gè)要點(diǎn),也讓使用Cache Client Cluster的同學(xué)有大致的一個(gè)了解。
先來看看Cache Cluster的結(jié)構(gòu)圖:
這張圖上需要注意四個(gè)角色:Application(使用Cache的應(yīng)用),Cache Cluster(Cache配置的虛擬集群),Cache Node(Cache的虛擬節(jié)點(diǎn),在同一個(gè)Cluster中的Cache Node數(shù)據(jù)保持完全一致),Cache Instance(Cache虛擬節(jié)點(diǎn)中實(shí)際包含的Memcached Cache服務(wù)端實(shí)例)。
應(yīng)用僅僅操作Cache Node,不了解具體數(shù)據(jù)存儲或數(shù)據(jù)獲取是操作哪一個(gè)Cache 服務(wù)端實(shí)例。(這點(diǎn)也就是Memcached Cache可擴(kuò)展性的基礎(chǔ)設(shè)計(jì))。Cache Cluster又將多個(gè)Cache Node組成了虛擬的集群,通過數(shù)據(jù)冗余,保證了服務(wù)可用性和數(shù)據(jù)完整性。
當(dāng)前 Cache Client Cluster主要有兩種配置模式:active 和 standby。(這里是借鑒了硬件的名詞,其實(shí)并不完全一樣,因?yàn)檫€是考慮到了效率問題)
Cache Client Cluster主要的功能點(diǎn):
1. 容錯(cuò)。當(dāng)被分配到讀取或者操作數(shù)據(jù)的Cache虛擬節(jié)點(diǎn)不可用的情況下,集群其他節(jié)點(diǎn)支持代替錯(cuò)誤節(jié)點(diǎn)服務(wù)于客戶端應(yīng)用。
2. 數(shù)據(jù)冗余。當(dāng)操作集群中某一個(gè)Cache虛擬節(jié)點(diǎn)時(shí),數(shù)據(jù)會(huì)異步傳播到其他集群節(jié)點(diǎn)。
3. 軟負(fù)載。客戶端通過對操作的key作算法(當(dāng)前采用簡單的key hash再取余的方式)選擇集群中的節(jié)點(diǎn),達(dá)到集群中節(jié)點(diǎn)簡單的負(fù)載分擔(dān)。同時(shí)也由于這種模式,可以使得key都有默認(rèn)的第一操作節(jié)點(diǎn),此節(jié)點(diǎn)的操作保持時(shí)時(shí)更新,而其他節(jié)點(diǎn)可以通過客戶端異步更新來實(shí)現(xiàn)效率提升。
4. 數(shù)據(jù)恢復(fù)。當(dāng)集群中某一節(jié)點(diǎn)失效后恢復(fù)時(shí),其數(shù)據(jù)可能已經(jīng)完全丟失,此時(shí)通過配置成為Active模式可以將其他節(jié)點(diǎn)上冗余的數(shù)據(jù)Lazy復(fù)制到該節(jié)點(diǎn)(獲取一個(gè)復(fù)制一個(gè),同時(shí)只支持一個(gè)冗余節(jié)點(diǎn)的數(shù)據(jù)獲取(不采取遍歷,防止低效))。
Active模式擁有1,2,3,4的特性。Standby模式擁用1,2,3特性。(其實(shí)本來只考慮讓Standby擁有1特性)。未來不排除還會(huì)有更多需要的特性加入。Active在key不存在的情況下會(huì)有些低效,因?yàn)闀?huì)判斷一個(gè)冗余節(jié)點(diǎn)是否存在內(nèi)容,然后決定是否修復(fù)當(dāng)前節(jié)點(diǎn)。(考慮采用短期失敗標(biāo)示之類的,不過效率不一定高,同時(shí)增加了復(fù)雜度)
運(yùn)行期動(dòng)態(tài)擴(kuò)容部署
Memcached cache客戶端算法中比較出名的是Consistent Hashing算法,其目的也就是為了在節(jié)點(diǎn)增加或者減少以后,通過算法盡量減小數(shù)據(jù)重新分布的代價(jià)。采用虛擬節(jié)點(diǎn),環(huán)狀和二叉樹等方式可以部分降低節(jié)點(diǎn)增加和減少對于數(shù)據(jù)分布的影響,但是始終還是有部分?jǐn)?shù)據(jù)會(huì)失效,這點(diǎn)還是由于Memcached Cache是集中式Cache所決定的。
但如果有了Cache Cluster的話,數(shù)據(jù)有了冗余,就可以通過逐步修改集群中虛擬節(jié)點(diǎn)配置,達(dá)到對于單個(gè)虛擬節(jié)點(diǎn)的配置動(dòng)態(tài)擴(kuò)容。
支持動(dòng)態(tài)部署前提:
配置文件動(dòng)態(tài)加載。(配置文件可以在Classpath中,也可以是Http資源的方式)通過Cache Client 中Cache Manager可以停止Cache 服務(wù),重新加載配置文件,即時(shí)生效。
當(dāng)前動(dòng)態(tài)部署的兩種方式:
1. 修改集群配置中某一套虛擬節(jié)點(diǎn)的服務(wù)實(shí)例配置(socketPool配置),增加或者減少后端數(shù)據(jù)存儲實(shí)例。然后動(dòng)態(tài)加載新的配置文件(可以通過指定遠(yuǎn)端的http配置作為新的配置文件),通過集群的lazy的修復(fù)方式,逐漸的將數(shù)據(jù)從冗余節(jié)點(diǎn)復(fù)制到新的節(jié)點(diǎn)上來,最終實(shí)現(xiàn)數(shù)據(jù)遷移。
2. 修改集群配置中某一套虛擬節(jié)點(diǎn)的服務(wù)實(shí)例配置(socketPool配置),增加或者減少后端數(shù)據(jù)存儲實(shí)例。然后動(dòng)態(tài)加載新的配置文件(可以通過指定遠(yuǎn)端的http配置作為新的配置文件),在調(diào)用Cache Manager主動(dòng)將數(shù)據(jù)由某一虛擬節(jié)點(diǎn)復(fù)制到指定的集群中,實(shí)現(xiàn)數(shù)據(jù)批量遷移,然后根據(jù)需要看是否需要修改其他幾套虛擬節(jié)點(diǎn)配置。
存在的問題:
1. 當(dāng)前沒有做到不停止服務(wù)來動(dòng)態(tài)部署。(后續(xù)考慮實(shí)現(xiàn),當(dāng)前將編譯配置和重新啟動(dòng)服務(wù)器的工作節(jié)省了)
2. 不論是lazy復(fù)制還是批量數(shù)據(jù)遷移,都是會(huì)將原本有失效時(shí)間的數(shù)據(jù)變成了無失效時(shí)間的數(shù)據(jù)。(這個(gè)問題暫時(shí)還沒有一種可行的高效的方式解決)
后話
性能優(yōu)化這點(diǎn)事還是那句老話,需要了再去做也不遲。同時(shí)如果你開發(fā)的是一個(gè)每天服務(wù)訪問量都是上億,甚至更高的系統(tǒng),那么有時(shí)候斤斤計(jì)較會(huì)收獲不少。(當(dāng)然是不影響系統(tǒng)本身業(yè)務(wù)流程的基礎(chǔ))。
Cache客戶端自從作為開源放在Google上也收到了不少朋友的支持和反饋,同時(shí)自己業(yè)務(wù)系統(tǒng)以及其他部門同學(xué)的使用促使我不斷的去優(yōu)化和滿足必要的一些功能擴(kuò)展(但是對于Cache來說,還是那句話,簡單就是美,高效是使用Cache的最原始的需求)。
當(dāng)前Cache Client版本已經(jīng)到了2.5版本,在Google上有詳細(xì)的Demo(單元測試,壓力測試,集群測試)和說明使用文檔。是否速度會(huì)慢于其他Memcached客戶端,這不好說的很絕對,反正大家自己拉下去比較一下看看就知道了,當(dāng)然為了集群和其他的一些必要的附加功能還是做了一些性能犧牲。
項(xiàng)目地址在:http://code.google.com/p/memcache-client-forjava/
在首頁的右側(cè)有demo,doc,binary,src的鏈接,直接可以下載使用和察看。希望對需要的同學(xué)有幫助。
愛這行
從事任何行業(yè)都一樣,只有真正的愛上了這份工作,才會(huì)投入熱情,才會(huì)在順境中自我警醒,在逆境中尋找突破。這個(gè)行業(yè)的競爭很激烈,你停下來走,別人就立刻會(huì)跑步超過你,沒有對這一行業(yè)的一種熱情,就很難在困境中保持一種執(zhí)著的態(tài)度堅(jiān)持到底。
踏踏實(shí)實(shí)“扎馬步”
今天無意中看了“校長”的“程序員&司機(jī)”,其中談到了關(guān)于程序員速成的問題。其實(shí)速成班畢業(yè)的 “系統(tǒng)殺手”早已在遍布大江南北,只是在互聯(lián)網(wǎng)時(shí)代,互聯(lián)網(wǎng)的應(yīng)用型軟件生命周期越來越短,業(yè)務(wù)驅(qū)動(dòng)主導(dǎo)的情況下,這種速成方式看起來反而提高了企業(yè)生產(chǎn)效率。但這樣的人才也就只能寫幾個(gè)Facebook上的插件應(yīng)用或者iGoogle上的Gadget,真的要出Google,Amazon,Yahoo改變互聯(lián)網(wǎng)世界的企業(yè),還是需要踏踏實(shí)實(shí)先學(xué)“扎馬步”的人。
很多在學(xué)校的同學(xué)或者剛剛畢業(yè)的朋友都看什么熱門學(xué)什么,Spring,AJAX,Hibernate等等,又有多少人在看Spring之前把J2SE的NIO,XML,Collection等先好好學(xué)習(xí)一下,在看AJAX之前把Http協(xié)議、DTD、XML Schema好好看一下,在學(xué)習(xí)Hibernate以前先把J2EE事務(wù)規(guī)范搞清楚。Java最大的好處就是開源,能夠讓人們站在更高的起點(diǎn)來作出更多的創(chuàng)新,但是對于學(xué)習(xí)者來說,不了解自己站在什么上面的時(shí)候,可能摔下來會(huì)很痛。在用的時(shí)候多問一些為什么,在遇到問題的時(shí)候多找找原因,在了解以后多提出一些優(yōu)化的方案,這樣才會(huì)進(jìn)步的更快,走的更遠(yuǎn)。
記得我前一陣子回家的時(shí)候和媽媽聊起最近的工作,雖然媽媽不太明白,但是也知道我現(xiàn)在做的東西技術(shù)含量比較高,囑咐我“千萬不要什么都教給自己的同事,徒弟帶出就不要師傅了”(這當(dāng)然是老一輩的觀念了)。我和她說:“不要擔(dān)心,這種學(xué)的會(huì)的不教遲早也會(huì),學(xué)不會(huì)的教了也學(xué)不會(huì)”。其實(shí)這里說的學(xué)的會(huì)的就是技術(shù),而學(xué)不會(huì)的就是經(jīng)驗(yàn)和能力。這個(gè)行業(yè)的人在日積月累過程中并不會(huì)去比較掌握的知識面有多廣多深,畢竟這行業(yè)更新很快,其實(shí)能力強(qiáng)的人在多年的學(xué)習(xí)中就積累了很多的找問題,分析問題,總結(jié)問題,提出建議,發(fā)掘創(chuàng)新的能力,這些才是這行業(yè)人在發(fā)展中最寶貴的財(cái)富,也是一個(gè)人成長的標(biāo)志。開始的過程中,踏踏實(shí)實(shí)地“扎馬步”,了解一些最基本的知識,那么上層技術(shù)的發(fā)展對于他來說僅僅只是一個(gè)短暫的學(xué)習(xí)過程,甚至可以觸類旁通。因此還是要奉勸每一個(gè)新入行的同學(xué),踏踏實(shí)實(shí),靜下心來做技術(shù),就算工作安排得都是一些浮躁和重復(fù)的工作,用高效的方式來結(jié)束那些重復(fù)勞動(dòng),多留一些時(shí)間給自己打基礎(chǔ)。
逆境養(yǎng)兵、順境攻城掠地
普通人的工作經(jīng)歷通常都是起伏不定的,一個(gè)人的能力是否能夠得到體現(xiàn),不僅僅靠自己的努力,有時(shí)候也需要“天時(shí)”、“地利”。馬云比較有名的一句話:“今天很殘酷,明天更殘酷,后天很美好,但是大多數(shù)人死在明天晚上,看不到后天的太陽!!!”,其實(shí)也在說明一件事,就是很多時(shí)候需要一種堅(jiān)持的精神才能得到寶貴的機(jī)會(huì)。
今天是我進(jìn)入阿里巴巴滿3年,這3年讓我感觸很深的是:1.逆境不要?dú)怵H,厚積薄發(fā)。2.順境不要懈怠,一股作氣,把握機(jī)會(huì)展現(xiàn)自己最大的能力。3.在逆境和順境的轉(zhuǎn)換過程中,創(chuàng)造機(jī)會(huì),不要坐等機(jī)會(huì),要學(xué)會(huì)不在其位,也謀其職。最后一點(diǎn)就拿我自己的親身經(jīng)歷來說,我原來就職于一家通信公司,因此對于互聯(lián)網(wǎng)應(yīng)用的開發(fā)和架構(gòu)設(shè)計(jì)要比很多人弱,進(jìn)入阿里巴巴以后工作了半年(主要作業(yè)務(wù)開發(fā)),正好阿里軟件創(chuàng)立,當(dāng)時(shí)被分配到了阿里軟件第一個(gè)產(chǎn)品負(fù)責(zé)客戶模塊,當(dāng)時(shí)的應(yīng)用是通過MDA框架配置搭建的,開發(fā)人員很大程度上不需要自己做太多的編碼,但是這個(gè)平臺并沒有搭建過如此復(fù)雜的大型應(yīng)用,因此存在著不少問題,當(dāng)然這些問題都是通過業(yè)務(wù)產(chǎn)品線的人反饋給平臺部的人,當(dāng)時(shí)平臺部門人員很少,但是卻要修復(fù)和完善諾大一個(gè)平臺,因此常常擱置開發(fā)人員的反饋。當(dāng)時(shí)在自己工作之余就琢磨和研究平臺,同時(shí)跟蹤調(diào)試平臺,最后直接給出解決方案,逐漸的就融入到了平臺開發(fā)中,最后被吸收到了平臺部門,進(jìn)入平臺部門以后遇到了兩位很好的老大,根據(jù)我的特質(zhì)給我安排了研究和學(xué)習(xí)的工作。接下去就是不斷地參與阿里軟件各個(gè)基礎(chǔ)平臺的構(gòu)建,核心技術(shù)的研究和探索,找到了興趣和工作的最佳結(jié)合點(diǎn)。因此,當(dāng)你困惑的時(shí)候首先不是去抱怨,而是審視一下自己是否還有作的不夠的,是否還有可以提升的空間,多給自己制造一些機(jī)會(huì),也許我們不用等到后天,也不會(huì)死在明天夜里,明天早晨我們就看到了太陽。
海納百川、冰凍三尺
很多朋友可能聽老師或者前輩也說過類似的話,就是作為一個(gè)技術(shù)人員要廣也要鉆。就好比現(xiàn)在很多人都要DB Scale out,同時(shí)也要Scale up。我從自己的角度來說一下廣和鉆的看法。廣:1.要有容人之量。(很多時(shí)候程序員最大的毛病就是喜歡在技術(shù)上比較,未嘗不是好事,但是一個(gè)人的能力總歸有限,多看看別人的,多聽聽別人的,也許能夠讓自己少用時(shí)間獲得更多的收獲,特別是自己戰(zhàn)友的聲音)2.觸類旁通,多問個(gè)為什么,多跨過界去學(xué)習(xí)。在阿里巴巴,PD、SA、DBA、UI等等職位各司其職,作為開發(fā)的我們其實(shí)也應(yīng)該去了解如何去畫Use Case,如何假設(shè)服務(wù)器和應(yīng)用環(huán)境,如何寫一些略微復(fù)雜的SQL,了解一些DB的特性,如何能夠簡單的作出一些基礎(chǔ)的頁面,使用簡單的css來美化一下門面。這些就是需要多跨過界,多虛心的去學(xué)習(xí)。鉆:1.本職工作技術(shù)一定要扎實(shí),每作一個(gè)技術(shù)點(diǎn)就要把技術(shù)吃透,同時(shí)延伸開來,發(fā)掘更多的技術(shù)亮點(diǎn)。2.多接觸新鮮事物,但是有選擇的去了解,有目的的去學(xué)習(xí)和實(shí)踐(目的的源泉就是工作的需求)。3.學(xué)會(huì)分享,一個(gè)人自己搞懂一個(gè)技術(shù)很容易,一個(gè)人要把他熟悉的技術(shù)寫下來就會(huì)發(fā)覺原來自己還有那么多沒有搞清楚,一個(gè)人如果要把寫下來的東西宣講給別人聽,他就會(huì)發(fā)現(xiàn),原來寫下來的僅僅是那么一小塊,因此學(xué)會(huì)分享,從自己了解,到記錄分享,到演講傳播就是一個(gè)不斷深化和廣化的過程。個(gè)人覺得小公司鍛煉人(啥都自己干),大公司培養(yǎng)人(該干的要干好),因此自己常回頭看看自己在廣和鉆上的不足,可以讓自己進(jìn)步的更快,學(xué)的更全面。
學(xué)中醫(yī)積累經(jīng)驗(yàn),學(xué)西醫(yī)尋找突破
中醫(yī)以對人體經(jīng)絡(luò)血脈了解為基礎(chǔ),通過望聞問切來尋找病理根源,行醫(yī)年限越久,找問題解決問題的經(jīng)驗(yàn)越強(qiáng)。西醫(yī)以科學(xué)技術(shù)為手段,通過試驗(yàn)化的方式不斷尋找突破,并且將成果積累并且傳遞給更多的人,但是否年限越久越有能力,或者是使用得器材越廣越資深,這點(diǎn)全要看個(gè)人對于醫(yī)術(shù)的理解,如果僅僅停留在對器械的使用和對成果的依賴,那么只會(huì)成為一個(gè)庸醫(yī)。當(dāng)然這里絕對沒有對中西醫(yī)的差別化或者評價(jià),僅僅要說明的是,在手段豐富的情況下,容易忽視了本質(zhì),只看到了皮毛,積累的時(shí)候多一些追根溯源,站在別人的成果上才更踏實(shí),因此在對經(jīng)驗(yàn)積累上向中醫(yī)多學(xué)一些,在尋找突破,傳播技術(shù)上多學(xué)一點(diǎn)西醫(yī)的風(fēng)格。不過說到低,還是要看學(xué)習(xí)的人,靜的下心,沉得住氣,才會(huì)有積累,才會(huì)有突破.
不做一個(gè)純粹的“技術(shù)人員”
不做一個(gè)純粹的“技術(shù)人員”,其實(shí)也就是說要培養(yǎng)自己多方面的能力,我僅僅把自己想到的一些點(diǎn)列出來說說:
1. 項(xiàng)目產(chǎn)品化的思想。現(xiàn)在就算在學(xué)校里面給導(dǎo)師作項(xiàng)目都講究一個(gè)商業(yè)價(jià)值,更不要說在企業(yè)里工作。作為一個(gè)開發(fā)或者架構(gòu)師最重要的就是要有產(chǎn)品化的概念,這也是項(xiàng)目是否成功的關(guān)鍵。軟件的目的是為人服務(wù),如何服務(wù)的好,那就要以一個(gè)產(chǎn)品的思路去做項(xiàng)目,而不是作為實(shí)驗(yàn)室的實(shí)驗(yàn)品,為客戶提供好服務(wù)就會(huì)給公司帶來商業(yè)價(jià)值,對自己的工作也會(huì)有很好的肯定。這是一個(gè)良性循環(huán),反之則是惡性循環(huán)(多贏變成多輸)。如何做到產(chǎn)品化,首先就是需要去了解需求,而不是布置需求,其次就是設(shè)計(jì)時(shí)多聽取一些不同角色的意見,最后就是在客戶的反饋過程中反省。
2. 多一些設(shè)計(jì),少砌兩塊磚。代碼寫的再好,其實(shí)也只是用磚塊砌墻砌的比較好罷了,這年代已經(jīng)不會(huì)為了節(jié)省兩塊磚而給一個(gè)優(yōu)秀工作者了,同時(shí)技術(shù)的日新月異,總是擺弄技巧,學(xué)習(xí)花拳繡腿已經(jīng)跟不上時(shí)代了。多了解一些行業(yè)背景,多參與一些架構(gòu)設(shè)計(jì),將業(yè)務(wù)設(shè)計(jì)用良好的架構(gòu)體系來實(shí)現(xiàn),那才是一個(gè)稱得上有能力的技術(shù)人員。
3. 學(xué)會(huì)前瞻,學(xué)會(huì)自己找事。記得我剛進(jìn)平臺組,最不適應(yīng)的就是我的老大基本不太給我布置太詳細(xì)的任務(wù),這就好比進(jìn)入大學(xué),老師不給作業(yè),自己反而心里沒底了,其實(shí)自己找事的過程就是一個(gè)自己學(xué)習(xí)的過程,當(dāng)我一天下來感覺沒干什么,沒學(xué)到什么,心里就開始發(fā)虛。如何能夠前瞻性的去選擇一些目標(biāo),如何對現(xiàn)有情況提出一些創(chuàng)新和建議,都是一種更高能力的要求。現(xiàn)在SIP組也是一樣,在我們這個(gè)組里雖然現(xiàn)在每周還是布置一定工作,但是我對其他兩個(gè)同學(xué)的要求也是希望能夠有前瞻性,學(xué)會(huì)發(fā)現(xiàn)問題,預(yù)防問題,更甚者就是提出創(chuàng)新。當(dāng)你具備了這種環(huán)境的時(shí)候,你就需要鍛煉自己的能力了。
4. 做個(gè)讓老大放心的人。這點(diǎn)也許很多人和我一樣在業(yè)務(wù)上很早就讓老大覺得可以安心睡覺了,但是其實(shí)另一方面,如何在商業(yè)角度看問題,如何培養(yǎng)新人,如何協(xié)調(diào)部門合作等等,都會(huì)讓你的老大更加安心。另一方面來看,其實(shí)在這些能力的培養(yǎng)過程中,你不再局限于業(yè)務(wù)水平的提升,讓自己在更多方面更加成熟。
六脈神劍
今天是我進(jìn)入阿里巴巴3年整。在阿里巴巴有個(gè)說法,只有在阿里巴巴工作了3年,才能算是一個(gè)真正的阿里人,因?yàn)槔斫獍⒗锇桶偷奈幕枰陼r(shí)間的沉淀。這里就從一個(gè)寫代碼的角度分享一下阿里巴巴的六脈神劍文化。
客戶第一:如果你是做架構(gòu)的,作平臺的,作開發(fā)工具的,那么客戶就是和自己一樣的開發(fā)者,多學(xué)習(xí)一下開源項(xiàng)目的精神,多從使用者角度去考慮問題,那么你的東西才會(huì)被更多的人認(rèn)可和使用,永遠(yuǎn)不要去做一個(gè)“玩具”的開發(fā)者。如果你是做產(chǎn)品的,那么就多聽,多想,多問,永遠(yuǎn)不要急著去寫代碼。
擁抱變化:敏捷開發(fā)的基本原則。互聯(lián)網(wǎng)應(yīng)用尤其如此,不要害怕變化,在需求和架構(gòu)之間找到平衡點(diǎn)(說起來比較容易^_^)。
團(tuán)隊(duì)合作:一個(gè)人的力量始終有限,分享,交流,合作能夠讓自己事半功倍,學(xué)的更多,看得更遠(yuǎn)。
誠信:說到就要做到,做了就要做好,做軟件開發(fā)一樣也需要有責(zé)任感,貼滿狗皮膏藥的代碼上如果注釋是你的名字未來也會(huì)給你蒙羞。踏踏實(shí)實(shí)地用心去寫代碼,去設(shè)計(jì)架構(gòu),不經(jīng)意間得到的要遠(yuǎn)遠(yuǎn)比那么一點(diǎn)工資來的多。
激情:還是那句話,你如果不愛這行,乘著年輕趕快轉(zhuǎn)行。
敬業(yè):專業(yè)執(zhí)著,精益求精
很感謝各位能看完這篇感受分享,以上都僅僅是個(gè)人的一點(diǎn)感受,能夠引起共鳴那么證明我們的經(jīng)歷很相似,如果能夠給到你一點(diǎn)幫助,那寫這些就真的有意義了。不論你在別人眼里是一個(gè)資深架構(gòu)師還是開發(fā)人員,其實(shí)如果你愛這個(gè)行業(yè)的話,你應(yīng)該就是一個(gè)寫代碼的,但是每個(gè)人的經(jīng)歷都是一本“寫代碼的自我修養(yǎng)”,珍惜自己的選擇,讓自己在興趣和工作中找到最佳結(jié)合點(diǎn)。
今天看了“Database Sharding at Netlog, with MySQL and PHP”一文,和去年我們討論擴(kuò)展的思路很類似(不過這種分布式擴(kuò)展,計(jì)算,存儲的思路都很類似),但是這片文章的作者是在日益爆炸式增長的用戶數(shù)據(jù)下實(shí)踐的分享,因此這里將文中的一些思想記錄下來分享一下。
Netlog擁有4000萬活躍用戶,每個(gè)月有超過5000萬的獨(dú)立用戶訪問網(wǎng)站,每個(gè)月有5億多的PV。數(shù)據(jù)量應(yīng)該算是比較大的。作者是Jurriaan Persyn,他從一個(gè)開發(fā)者角度而非DBA或者SA角度來談Netlog是如何通過數(shù)據(jù)切分來提高網(wǎng)站性能,橫向擴(kuò)展數(shù)據(jù)層的。原文在:http://www.jurriaanpersyn.com/archives/2009/02/12/database-sharding-at-netlog-with-mysql-and-php/
首先,還是先談到關(guān)于數(shù)據(jù)庫在數(shù)據(jù)日益龐大的情況下一個(gè)演變過程。
第一階段:讀寫同在一臺數(shù)據(jù)庫服務(wù)器
第二階段:讀寫分離(可以解決讀寫比例均衡或者讀居多的情況,但是帶入了數(shù)據(jù)復(fù)制同步的問題)
第三階段:部分?jǐn)?shù)據(jù)獨(dú)立部署結(jié)合讀寫分離。(部分?jǐn)?shù)據(jù)根據(jù)其業(yè)務(wù)獨(dú)立性情況,可以將所有的數(shù)據(jù)獨(dú)立存儲到數(shù)據(jù)庫服務(wù)器,分擔(dān)數(shù)據(jù)讀寫壓力,前提是要求數(shù)據(jù)具有較高的業(yè)務(wù)獨(dú)立性)
第四階段:數(shù)據(jù)分拆結(jié)合讀寫分離(三階段的增強(qiáng))
第五階段:問題出現(xiàn),分拆也無法解決數(shù)據(jù)爆炸性增長,同時(shí)讀寫處于同等比例。
解決問題兩種方式:DB Scale up ,DB Scale out。前者投入以及后期擴(kuò)展有限,因此需要進(jìn)行數(shù)據(jù)切分。
上圖就是將photo的數(shù)據(jù)切分到了10臺數(shù)據(jù)庫服務(wù)器上。
切分?jǐn)?shù)據(jù)的兩個(gè)關(guān)鍵點(diǎn):
1. 如何根據(jù)存儲的數(shù)據(jù)內(nèi)容判斷數(shù)據(jù)的存儲歸屬,也就是什么是內(nèi)容的分區(qū)主鍵。
2. 采用什么算法可以根據(jù)不同的主鍵將內(nèi)容存儲到不同的分區(qū)中。
分區(qū)主鍵的選擇還是要根據(jù)自身的業(yè)務(wù)場景來決定,Netblog選擇的是用戶ID。
采用什么方式將分區(qū)主鍵映射到對應(yīng)的分區(qū)可以通過以下四種方式:
1. 根據(jù)數(shù)據(jù)表來切分。(前提就是數(shù)據(jù)獨(dú)立性較強(qiáng),和前面提到的三階段類似)
2. 基于內(nèi)容區(qū)間范圍的分區(qū)。(就好比前1000個(gè)用戶的信息存儲在A服務(wù)器,1000-2000存儲在B服務(wù)器)
3. 采用Hash算法結(jié)合虛擬節(jié)點(diǎn)的方式。(這類在memcached等等分布式場景中最常見,其實(shí)也是一個(gè)難點(diǎn)),缺點(diǎn)就是在于動(dòng)態(tài)增加存儲節(jié)點(diǎn)會(huì)導(dǎo)致數(shù)據(jù)部分或者全部失效。
4. 目錄式的分區(qū)。最簡單也是最直接的方式,key和分區(qū)的對應(yīng)關(guān)系被保存,通過查找目錄可以得到分區(qū)信息。適合擴(kuò)展,就是增加查詢損耗。
如何將數(shù)據(jù)分布的盡量均勻,如何平衡各個(gè)服務(wù)器之間的負(fù)載,如何在新增存儲機(jī)器和刪除存儲機(jī)器的時(shí)候不影響原有數(shù)據(jù),同時(shí)能夠?qū)?shù)據(jù)均攤,都是算法的關(guān)鍵。在分布式系統(tǒng)中DHT(Distribute Hash Table)被很多人研究,并且有很多的論文是關(guān)于它的。
數(shù)據(jù)的橫向切分給應(yīng)用帶來的問題:
1. 跨區(qū)的數(shù)據(jù)查詢變得很困難。(對于復(fù)雜的關(guān)聯(lián)性數(shù)據(jù)查詢無法在一個(gè)請求中完成)
2. 數(shù)據(jù)一致性和引用完整性較難保證。(多物理存儲的情況下很難保證兼顧效率、可用性、一致性)
3. 數(shù)據(jù)分區(qū)之間的負(fù)載均衡問題。(數(shù)據(jù)本身的不均衡性,訪問和讀寫的不均衡性都會(huì)給數(shù)據(jù)分區(qū)的負(fù)載均衡帶來困難)
4. 網(wǎng)絡(luò)配置的復(fù)雜性。(需要保證服務(wù)器之間的大數(shù)據(jù)量頻繁的交互和同步)
5. 數(shù)據(jù)備份策略將會(huì)變得十分復(fù)雜。
解決這些問題當(dāng)前已經(jīng)有的一些開源項(xiàng)目:
1. MySql Cluster,解決讀寫分離問題已經(jīng)十分成熟。
2. MySql Partitioning,可以將一個(gè)大表拆分為很多小表,提高訪問速度,但是限制與這些小表必須在同一臺服務(wù)器上。
3. HSCALE和Spock Proxy都是建立與MySql Proxy基礎(chǔ)上的開源項(xiàng)目,MySql Proxy采用LUA腳本來進(jìn)行數(shù)據(jù)分區(qū)。
4. HiveDB是MySql分區(qū)框架的java實(shí)現(xiàn)。
5. 另外還有HyperTable,HBase,BigTable等等。
Netblog幾個(gè)需求:
1. 需要靈活的可擴(kuò)展性。對于存儲增加減少需要能夠動(dòng)態(tài)的及時(shí)實(shí)施,因?yàn)閿?shù)據(jù)量增長很快,如果策略會(huì)導(dǎo)致數(shù)據(jù)失效或者部署需要重新啟動(dòng),則就不能滿足需求。
2. 不想引入全新的數(shù)據(jù)層和與原有系統(tǒng)不匹配的抽象層,因?yàn)椴⒉皇撬袛?shù)據(jù)都需要切分,僅僅在需要的情況下通過API的方式來透明切分?jǐn)?shù)據(jù)。
3. 分區(qū)的主鍵需要可配置。
4. 需要封裝API,對開發(fā)人員透明數(shù)據(jù)切分的工作。
Netblog Sharding的實(shí)現(xiàn)
上圖就是Netblog的Sharding的結(jié)構(gòu)圖,主要分成了三部分:Shard,Sharddb,Sharddbhost。Shard就是一個(gè)表,里面存放了部分用戶數(shù)據(jù)。Sharddb是一個(gè)表的組合就像一個(gè)虛擬的DB。Sharddbhost是具體的存儲分區(qū)。Shard,Sharddb可以根據(jù)負(fù)載的情況被移動(dòng)到不同的host中去。
對于Shard的管理,Netblog采用的是目錄查詢的管理方式。目錄信息也存儲在MySql中,同時(shí)會(huì)通過互備,Memcache,集群來確保安全性和高效性。
Shard Table API采用了多一層的映射模式來適合各種不同屬性的查詢情況。數(shù)據(jù)和記錄在數(shù)據(jù)庫中存儲除了UserID以外還有對應(yīng)的ItemID,ItemID的作用就是定義了具體獲取數(shù)據(jù)的字段信息,例如關(guān)聯(lián)照片表時(shí),ItemID就是PhotoId,關(guān)聯(lián)視頻表時(shí),ItemID就是videoID。
一個(gè)獲取用戶id為26博客信息的范例:
1.Where is user 26?
User 26 is on shard 5.
2.On shard 5; Give me all the $blogIDs ($itemIDs) of user 26.
That user's $blogIDs are: array(10,12,30);
3.On shard 5; Give me all details about the items array(10,12,30) of user 26.
Those items are: array(array('title' => "foo", 'message' => "bar"), array('title' => "milk", 'message' => "cow"));
對于Shard的管理Netblog采取的措施主要有這些:
1. 服務(wù)器之間的負(fù)載均衡根據(jù)用戶數(shù),數(shù)據(jù)庫文件大小,讀寫次數(shù),cpu load等等作為參數(shù)來監(jiān)控和維護(hù)。根據(jù)最后的結(jié)果來遷移數(shù)據(jù)和分流數(shù)據(jù)。
2. 移動(dòng)數(shù)據(jù)時(shí)會(huì)監(jiān)控用戶是否在操作數(shù)據(jù),防止不一致性。
3. 對于數(shù)據(jù)庫的可用性,采用集群,master-master,master-slave復(fù)制等手段。
最后通過三種技術(shù)來解決三個(gè)問題:
1. Memcached解決shard多次查詢的效率問題。
根據(jù)上面的范例可以看到,一次查詢現(xiàn)在被分割成為了三部分:shard查詢,item查詢,最終結(jié)果查詢。通過memcached可以緩存三部分內(nèi)容,由前到后數(shù)據(jù)的穩(wěn)定性以及命中率逐漸降低,同時(shí)通過結(jié)合有效期(內(nèi)容存儲時(shí)效)和修改更新機(jī)制(add,update,delete觸發(fā)緩存更新),可以極大地解決效率問題。甚至通過緩存足夠信息減少大量的數(shù)據(jù)庫交互。
2. 并行計(jì)算處理。
由于數(shù)據(jù)的分拆,有時(shí)候需要得到對于多Shard數(shù)據(jù)處理的結(jié)果匯總,因此就會(huì)將一個(gè)請求分拆為多個(gè)請求,分別交由多個(gè)服務(wù)器處理,最后將結(jié)果匯總。(類似于Map-reduce)
3. 采用Sphinx全文搜索引擎解決多數(shù)據(jù)分區(qū)數(shù)據(jù)匯總查詢,例如察看網(wǎng)站用戶的最新更新情況或者最熱門日至。這個(gè)采用單獨(dú)系統(tǒng)部署,通過建立全局信息索引,來查詢數(shù)據(jù)情況。
以上是技術(shù)上的全部內(nèi)容,作者在最后的幾個(gè)觀點(diǎn)十分值得學(xué)習(xí),同時(shí)也不僅僅限于數(shù)據(jù)切分,任何框架設(shè)計(jì)都可以參考。
“Don't do it, if you don't need to!" (37signals.com)
"Shard early and often!" (startuplessonslearned.blogspot.com)
看起來矛盾的兩句話,卻是說出了對于數(shù)據(jù)切分的一些考慮。
首先在沒有必要的情況下就不要考慮數(shù)據(jù)切分,切分帶來的復(fù)雜性直接影響可用性,可維護(hù)性和一致性。在能夠采用Scale up的情況下,可以選擇Scale up降低框架復(fù)雜度。
另一方面,如果發(fā)現(xiàn)了業(yè)務(wù)增長情況出現(xiàn)必須要擴(kuò)展的趨勢,那么就要盡早著手去實(shí)施和規(guī)劃擴(kuò)展的工作,并且在切分和擴(kuò)展過程中要不斷地去優(yōu)化和重構(gòu)。
后話:
其實(shí)任何架構(gòu)設(shè)計(jì)首要就是簡單直接,不過度設(shè)計(jì),不濫竽充數(shù)。其實(shí)就是要平衡好:可用性、高效性、一致性、可擴(kuò)展性這四者之間的關(guān)系。良性循環(huán)、應(yīng)時(shí)應(yīng)事作出取舍和折中。用的好要比學(xué)會(huì)用更重要,更關(guān)鍵。