主頁 > 知識庫 > 剖析Twitter處理峰值方面所做的一些改進(jìn)與優(yōu)化

剖析Twitter處理峰值方面所做的一些改進(jìn)與優(yōu)化

熱門標(biāo)簽:Linux服務(wù)器 鐵路電話系統(tǒng) 解決方案 科大訊飛語音識別系統(tǒng) Win7旗艦版 蘋果 電銷機(jī)器人 阿里云

背景補(bǔ)充:日本網(wǎng)民一直都有在電視節(jié)目播出的同時(shí),在網(wǎng)絡(luò)平臺上吐槽或跟隨片中角色喊出臺詞的習(xí)慣,被稱作“實(shí)況”行為。宮崎駿監(jiān)督的名作動畫《天空之城》于2013年8月2日晚在NTV電視臺迎來14次電視重播。當(dāng)劇情發(fā)展到男女主角巴魯和希達(dá)共同念出毀滅之咒“Blase”時(shí),眾多網(wǎng)友也在推特上同時(shí)發(fā)出這條推特,創(chuàng)造了每秒推特發(fā)送數(shù)量的新紀(jì)錄。
根據(jù)推特日本官方帳號,當(dāng)?shù)貢r(shí)間8月2日晚11時(shí)21分50秒,因?yàn)?ldquo;Blase祭”的影響,推特發(fā)送峰值達(dá)到了143,199次/秒。這一數(shù)字高于此前推特發(fā)送峰值的最高紀(jì)錄,2013年日本時(shí)區(qū)新年時(shí)的33,388次/秒。更高于拉登之死(5106次/秒)、東日本大地震(5530次/秒)、美國流行天后碧昂斯宣布懷孕(8868次/秒)。
下圖是峰值發(fā)生的鄰近時(shí)間段的訪問頻率圖,Twitter通常每天的推文數(shù)是 5 億條,平均下來每秒大概產(chǎn)生5700條。這個(gè)峰值大概是穩(wěn)定狀態(tài)下訪問量的25倍!

在這個(gè)峰值期間,用戶并沒有感覺到暫時(shí)性的功能異常。無論世界上發(fā)生了什么,Twitter始終在你身邊,這是Twitter的目標(biāo)之一。

“新的Tweets峰值誕生:143,199次Tweets每秒。通常情況:5億次每天;平均值5700Tweets每秒”

這個(gè)目標(biāo)在3年前還是遙不可及的,2010年世界杯直接把Twitter變成了全球即時(shí)溝通的中心。每一次射門、罰球、黃牌或者紅牌,用戶都在發(fā)推文,這反復(fù)地消耗著系統(tǒng)帶寬,從而使其在短時(shí)間內(nèi)無法訪問。工程師們在這期間徹夜工作,拼命想找到并實(shí)現(xiàn)一種方法可以把整個(gè)系統(tǒng)的負(fù)載提升一個(gè)量級。不幸的是,這些性能的提升很快被Twitter用戶的快速增長所淹沒,工程師們已經(jīng)開始感到黔驢技窮了。

經(jīng)歷了那次慘痛的經(jīng)歷,Twitter決定要回首反思。那時(shí)Twitter決定了要重新設(shè)計(jì)Twitter,讓它能搞定持續(xù)增長的訪問負(fù)載,并保證平穩(wěn)運(yùn)行。從那開始Twitter做了很大努力,來保證面臨世界各地發(fā)生的熱點(diǎn)事件時(shí),Twitter仍能提供穩(wěn)定的服務(wù)。Twitter現(xiàn)在已經(jīng)能扛住諸如播放“天空之城”,舉辦超級碗,慶祝新年夜等重大事件帶來的訪問壓力。重新設(shè)計(jì)/架構(gòu),不但使系統(tǒng)在突發(fā)訪問峰值期間的穩(wěn)定性得到了保證,還提供了一個(gè)可伸縮的平臺,從而使新特性更容易構(gòu)建,其中包括不同設(shè)備間同步消息,使Tweets包含更豐富內(nèi)容的Twitter卡,包含用戶和故事的富搜索體驗(yàn)等等特性。其他更多的特性也即將呈現(xiàn)。

開始重新架構(gòu)

2010年世界杯塵埃落定,Twitter總覽了整個(gè)項(xiàng)目,并有如下的發(fā)現(xiàn):

Twitter正運(yùn)行著世界上最大的Ruby on Rails集群,Twitter非??焖俚耐七M(jìn)系統(tǒng)的演進(jìn)–在那時(shí),大概200個(gè)工程師為此工作,無論是新用戶數(shù)還是絕對負(fù)載都在爆炸式的增長,這個(gè)系統(tǒng)沒有倒下。它還是一個(gè)統(tǒng)一的整體,Twitter的所有工作都在其上運(yùn)行,從管理純粹的數(shù)據(jù)庫,memcache連接,站點(diǎn)的渲染,暴露共有API這些都集中在一個(gè)代碼庫上。這不但增加了程序員搞清整個(gè)系統(tǒng)的難度,也使管理和同步各個(gè)項(xiàng)目組變得更加困難。
Twitter的存儲系統(tǒng)已經(jīng)達(dá)到閾值–Twitter依賴的MySQL存儲系統(tǒng)是臨時(shí)切分的,它只有一個(gè)單主節(jié)點(diǎn)。這個(gè)系統(tǒng)在消化/處理快速涌現(xiàn)的tweets時(shí)會陷入麻煩,Twitter在運(yùn)營時(shí)不得不不斷的增加新的數(shù)據(jù)庫。Twitter的所有數(shù)據(jù)庫都處于讀寫的熱點(diǎn)中。
Twitter面臨問題時(shí),只是一味的靠扔進(jìn)更多的機(jī)器來扛住,并沒有用工程的方式來解決它–根據(jù)機(jī)器的配置,前端Ruby機(jī)器的每秒事務(wù)處理數(shù)遠(yuǎn)沒有達(dá)到Twitter預(yù)定的能力。從以往的經(jīng)驗(yàn),Twitter知道它應(yīng)該能處理更多的事務(wù)。
最后,從軟件的角度看,Twitter發(fā)現(xiàn)自己被推到了一個(gè)”優(yōu)化的角落“,在那Twitter以代碼的可讀性和可擴(kuò)展性為代價(jià)來換取性能和效率的提升。
結(jié)論是Twitter應(yīng)該開啟一個(gè)新工程來重新審視Twitter的系統(tǒng)。Twitter設(shè)立了三個(gè)目標(biāo)來激勵(lì)自己。

Twitter一直都需要一個(gè)高屋建瓴的建構(gòu)來確保性能/效率/可靠性,Twitter想要保證在正常情況下有較好的平均系統(tǒng)響應(yīng)時(shí)間,同時(shí)也要考慮到異常峰值的情況,這樣才能保證在任何時(shí)間都能提供一致的服務(wù)和用戶體驗(yàn)。Twitter要把機(jī)器的需求量降低10倍,還要提高容錯(cuò)性,把失敗進(jìn)行隔離以避免更大范圍的服務(wù)中斷–這在機(jī)器數(shù)量快速增長的背景下尤為重要,因?yàn)闄C(jī)器數(shù)的快速增長也意味著單體機(jī)器故障的可能性在增加。系統(tǒng)中出現(xiàn)失敗是不可避免的,Twitter要做的是使整個(gè)系統(tǒng)處于可控的狀態(tài)。
Twitter要劃清相關(guān)邏輯間的界限,整個(gè)公司工作在一個(gè)的代碼庫上的方式把Twitter搞的很慘,所以Twitter開始嘗試以基于服務(wù)的松耦合的模式進(jìn)行劃分模塊。Twitter曾經(jīng)的目標(biāo)是鼓勵(lì)封裝和模塊化的最佳實(shí)踐,但這次Twitter把這個(gè)觀點(diǎn)深入到了系統(tǒng)層次,而不是類/模塊或者包層。
最重要的是要更快的啟動新特性。以小并自主放權(quán)的團(tuán)隊(duì)模式展開工作,他們可以內(nèi)部決策并發(fā)布改變給用戶,這是獨(dú)立于其他團(tuán)隊(duì)的。
針對上面的要求,Twitter構(gòu)建了原型來證明重新架構(gòu)的思路。Twitter并沒有嘗試所有的方面,并且即使Twitter嘗試的方面在最后也可能并像計(jì)劃中那樣管用。但是,Twitter已經(jīng)能夠設(shè)定一些準(zhǔn)則/工具/架構(gòu),這些使Twitter到達(dá)了一個(gè)憧憬中的更靠譜的狀態(tài)。

The JVM VS the Ruby VM

首先,Twitter在三個(gè)維度上評估了前端服務(wù)節(jié)點(diǎn):CPU,內(nèi)存和網(wǎng)絡(luò)?;赗uby的機(jī)器在CPU和內(nèi)存方面遭遇瓶頸–但是Twitter并未處理預(yù)計(jì)中那么多的負(fù)載,并且網(wǎng)絡(luò)帶寬也沒有接近飽和。Twitter的Rails服務(wù)器在那時(shí)還不得不設(shè)計(jì)成單線程并且一次處理一個(gè)請求。每一個(gè)Rails主機(jī)跑在一定數(shù)量的Unicorn處理器上來提供主機(jī)層的并發(fā),但此處的復(fù)制被轉(zhuǎn)變成了資源的浪費(fèi)(這里譯者沒太理清,請高手矯正,我的理解是Rails服務(wù)在一臺機(jī)器上只能單線程跑,這浪費(fèi)了機(jī)器上多核的資源)。歸結(jié)到最后,Rails服務(wù)器就只能提供200~300次請求每秒的服務(wù)。

Twitter的負(fù)載總是增長的很快,做個(gè)數(shù)學(xué)計(jì)算就會發(fā)現(xiàn)搞定不斷增長的需求將需要大量的機(jī)器。

在那時(shí),Twitter有著部署大規(guī)模JVM服務(wù)的經(jīng)驗(yàn),Twitter的搜索引擎是用Java寫的,Twitter的流式API的基礎(chǔ)架構(gòu)還有Twitter的社交圖譜系統(tǒng)Flock都是用Scala實(shí)現(xiàn)的。Twitter著迷于JVM提供的性能。在Ruby虛擬機(jī)上達(dá)到Twitter要求的性能/可靠性/效率的目標(biāo)不是很容易,所以Twitter著手開始寫運(yùn)行在JVM上的代碼。Twitter評估了這帶來的好處,在同樣的硬件上,重寫Twitter的代碼能給Twitter帶來10倍的性能改進(jìn)–現(xiàn)今,Twitter單臺服務(wù)器達(dá)到了每秒10000-20000次請求的處理能力。

Twitter對JVM存在相當(dāng)程度的信任,這是因?yàn)楹芏嗳硕紒碜阅切┻\(yùn)營/調(diào)配著大規(guī)模JVM集群的公司。Twitter有信心使Twitter在JVM的世界實(shí)現(xiàn)巨變?,F(xiàn)在Twitter不得不解耦Twitter的架構(gòu)從而找出這些不同的服務(wù)如何協(xié)作/通訊。

編程模型

在Twitter的Ruby系統(tǒng)中,并行是在進(jìn)程的層面上管理的:一個(gè)單個(gè)請求被放進(jìn)某一進(jìn)程的隊(duì)列中等待處理。這個(gè)進(jìn)程在請求的處理期間將完全被占用。這增加了復(fù)雜性,這樣做實(shí)際上使Twitter變成一個(gè)單個(gè)服務(wù)依賴于其他服務(wù)的回復(fù)的架構(gòu)?;赗uby的進(jìn)程是單線程的,Twitter的響應(yīng)時(shí)間對后臺系統(tǒng)的響應(yīng)非常敏感,二者緊密關(guān)聯(lián)。Ruby提供了一些并發(fā)的選項(xiàng),但是那并沒有一個(gè)標(biāo)準(zhǔn)的方法去協(xié)調(diào)所有的選項(xiàng)。JVM則在概念和實(shí)現(xiàn)中都灌輸了并發(fā)的支持,這使Twitter可以真正的構(gòu)建一個(gè)并發(fā)的編程平臺。

針對并發(fā)提供單個(gè)/統(tǒng)一的方式已經(jīng)被證明是有必要的,這個(gè)需求在處理網(wǎng)絡(luò)請求是尤為突出。Twitter都知道,實(shí)現(xiàn)并發(fā)的代碼(包括并發(fā)的網(wǎng)絡(luò)處理代碼)是個(gè)艱巨的任務(wù),它可以有多種實(shí)現(xiàn)方式。事實(shí)上,Twitter已經(jīng)開始碰到這些問題了。當(dāng)Twitter開始把系統(tǒng)解耦成服務(wù)時(shí),每一個(gè)團(tuán)隊(duì)都或多或少的采用了不盡相同的方式。例如,客戶端到服務(wù)的失效并沒有很好的交互:這是由于Twitter沒有一致的后臺抗壓機(jī)制使服務(wù)器返回某值給客戶端,這導(dǎo)致了Twitter經(jīng)歷了野牛群狂奔式的瘋狂請求,客戶端猛戳延遲的服務(wù)。這些失效的區(qū)域警醒Twitter–擁有一個(gè)統(tǒng)一完備的客戶/服務(wù)器間的庫來包含連接池/失效策略/負(fù)載均衡是非常重要的。為了把這個(gè)理念深入人心,Twitter引入了”Futures and Finagle”協(xié)議。

現(xiàn)在,Twitter不僅有了一致的做事手段,Twitter還把系統(tǒng)需要的所有東西都包含進(jìn)核心的庫里,這樣Twitter開新項(xiàng)目時(shí)就會進(jìn)展飛速。同時(shí),Twitter現(xiàn)在不需要過多的擔(dān)心每個(gè)系統(tǒng)是如何運(yùn)行,從而可以把更多的經(jīng)歷放到應(yīng)用和服務(wù)的接口上。

獨(dú)立的系統(tǒng)

Twitter實(shí)施了架構(gòu)上的重大改變,把集成化的Ruby應(yīng)用變成一個(gè)基于服務(wù)的架構(gòu)。Twitter集中力量創(chuàng)建了Tweet時(shí)間線和針對用戶的服務(wù)–這是Twitter的核心所在。這個(gè)改變帶給組織更加清晰的邊界和團(tuán)隊(duì)級別的責(zé)任制與獨(dú)立性。在Twitter古老的整體/集成化的世界,Twitter要么需要一個(gè)了解整個(gè)工程的大牛,要么是對某一個(gè)模塊或類清楚的代碼所有者。

悲劇的是,代碼膨脹的太快了,找到了解所有模塊的大牛越來越難,然而實(shí)踐中,僅僅依靠幾個(gè)對某一模塊/類清楚的代碼作者又不能搞定問題。Twitter的代碼庫變得越來越難以維護(hù),各個(gè)團(tuán)隊(duì)常常要像考古一樣把老代碼翻出來研究才能搞清楚某一功能。不然,Twitter就組織類似“捕鯨征程”的活動,耗費(fèi)大量的人力來搞出大規(guī)模服務(wù)失效的原因。往往一天結(jié)束,Twitter花費(fèi)了大量的時(shí)間在這上面,而沒有精力來開發(fā)/發(fā)布新特性,這讓Twitter感覺很糟。

Twitter的理念曾經(jīng)并一直都是–一個(gè)基于服務(wù)的架構(gòu)可以讓Twitter并行的開發(fā)系統(tǒng)–Twitter就網(wǎng)絡(luò)RPC接口達(dá)成一致,然后各自獨(dú)立的開發(fā)系統(tǒng)的內(nèi)部實(shí)現(xiàn)–但,這也意味著系統(tǒng)的內(nèi)部邏輯是自耦合的。如果Twitter需要針對Tweets進(jìn)行改變,Twitter可以在某一個(gè)服務(wù)例如Tweets服務(wù)進(jìn)行更改,然后這個(gè)更改會在整個(gè)架構(gòu)中得到體現(xiàn)。然而在實(shí)踐中,Twitter發(fā)現(xiàn)不是所有的組都在以同樣的方式規(guī)劃變更:例如一個(gè)在Tweet服務(wù)的變更要使Tweet的展現(xiàn)改變,那么它可能需要其他的服務(wù)先進(jìn)行更新以適應(yīng)這個(gè)變化。權(quán)衡利弊,這種理念還是為Twitter贏得了更多的時(shí)間。

這個(gè)系統(tǒng)架構(gòu)也反映了Twitter一直想要的方式,并且使Twitter的工程組織有效的運(yùn)轉(zhuǎn)。工程團(tuán)隊(duì)建立了高度自耦合的小組并能夠獨(dú)立/快速的展開工作。這意味著Twitter傾向于讓項(xiàng)目組啟動運(yùn)行自己的服務(wù)并調(diào)用后臺系統(tǒng)來完成任務(wù)。這實(shí)際也暗含了大量運(yùn)營的工作。

存儲

即使Twitter把Twitter板結(jié)成一坨的系統(tǒng)拆開成服務(wù),存儲仍然是一個(gè)巨大的瓶頸。Twitter在那時(shí)還把tweets存儲在一個(gè)單主的MySQL數(shù)據(jù)庫中。Twitter采用了臨時(shí)數(shù)據(jù)存儲的策略,數(shù)據(jù)庫中的每一行是一個(gè)tweet,Twitter把tweet有序的存儲在數(shù)據(jù)庫中,當(dāng)一個(gè)庫滿了Twitter就新開一個(gè)庫然后重配軟件開始往新庫中添加數(shù)據(jù)。這個(gè)策略為Twitter節(jié)省了一定的時(shí)間,但是面對突發(fā)的高訪問量,Twitter仍然一籌莫展,因?yàn)榇罅康臄?shù)據(jù)需要被串行化到一個(gè)單個(gè)的主數(shù)據(jù)庫中以至于Twitter幾臺局部的數(shù)據(jù)庫會發(fā)生高強(qiáng)度的讀請求。Twitter得為Tweet存儲設(shè)計(jì)一個(gè)不同的分區(qū)策略。

Twitter引入了Gizzard并把它應(yīng)用到了tweets,它可以創(chuàng)建分片并容錯(cuò)的分布式數(shù)據(jù)庫。Twitter創(chuàng)造了T-Bird(沒懂啥意思,意思是Twitter的速度快起來了?)。這樣,Gizzard充當(dāng)了MySQL集群的前端,每當(dāng)一個(gè)tweet抵達(dá)系統(tǒng),Gizzard對其進(jìn)行哈希計(jì)算,然后選擇一個(gè)適當(dāng)?shù)臄?shù)據(jù)庫進(jìn)行存儲。當(dāng)然,這意味著Twitter失去了依靠MySQL產(chǎn)生唯一ID的功能。Snowflake很好的解決了上述問題。Snowflake使Twitter能夠創(chuàng)建一個(gè)幾乎可以保證全局唯一的ID。Twitter依靠它產(chǎn)生新的tweet ID,作為代價(jià),Twitter將沒有“把某數(shù)加1產(chǎn)生新ID”的功能。一旦Twitter得到一個(gè)IDTwitter靠Gizzard來存儲它。假設(shè)Twitter的哈希算法足夠好,從而Twitter的tweets是接近于均勻的分布于各個(gè)儲存的,Twitter就能夠?qū)崿F(xiàn)用同樣數(shù)量的數(shù)據(jù)庫承載更多的數(shù)據(jù)。Twitter的讀請求同樣也接近平均的分布于整個(gè)分布式集群中,這也增加了Twitter的吞度量。

可觀察性和可統(tǒng)計(jì)性

把那坨脆弱的板結(jié)到一起的系統(tǒng)變成一個(gè)更健壯的/良好封裝的/但也蠻復(fù)雜的/基于服務(wù)的應(yīng)用。Twitter不得不搞出一些工具來使管理這頭野獸變得可能?;诖蠹叶荚诳焖俚臉?gòu)建各種服務(wù),Twitter需要一種可靠并簡單的方式來得到這些服務(wù)的運(yùn)行情況的數(shù)據(jù)。數(shù)據(jù)為王是默認(rèn)準(zhǔn)則,Twitter需要是使獲取上述的數(shù)據(jù)變得非常容易。

當(dāng)Twitter將要在一個(gè)快速增長的巨大系統(tǒng)上啟動越來越多的服務(wù),Twitter必須使這種工作變得輕松。運(yùn)行時(shí)系統(tǒng)組開發(fā)為大家開發(fā)了兩個(gè)工具:Viz和Zipkin。二者都暴露并集成到了Finagle,所以所有基于Finagle的服務(wù)都可以自動的獲取到它們。

復(fù)制代碼
代碼如下:

stats.timeFuture("request_latency_ms") {
// dispatch to do work
}

上面的代碼就是一個(gè)服務(wù)生成統(tǒng)計(jì)報(bào)告給Via所需做的唯一事情。從那里,任何Viz用戶都可以寫一個(gè)查詢來生成針對一些有趣的數(shù)據(jù)的時(shí)間/圖表,例如第50%和第99%的request_latency_ms。

運(yùn)行時(shí)配置和測試

最后,當(dāng)Twitter把所有的好東西放一起時(shí),兩個(gè)看似無關(guān)的問題擺在面前:第一,整個(gè)系統(tǒng)的啟動需要協(xié)調(diào)多個(gè)系列的不同的服務(wù),Twitter沒有一個(gè)地方可以把Twitter這個(gè)量級的應(yīng)用所需要的服務(wù)弄到一起。Twitter已經(jīng)不能依靠通過部署來把新特性展現(xiàn)給客戶,應(yīng)用中的各個(gè)服務(wù)需要協(xié)調(diào)。第二,Twitter已經(jīng)變得太龐大,在一個(gè)完全封閉的環(huán)境下測試整個(gè)系統(tǒng)變得越來越困難。相對而言,Twitter測試自己孤立的系統(tǒng)是沒有問題的–所以Twitter需要一個(gè)辦法來測試大規(guī)模的迭代。Twitter接納了運(yùn)行時(shí)配置。

Twitter通過一個(gè)稱作Decider的系統(tǒng)整合所有的服務(wù)。當(dāng)有一個(gè)變更要上線,它允許Twitter只需簡單開啟一個(gè)開關(guān)就可以讓架構(gòu)上的多個(gè)子系統(tǒng)都和這個(gè)改變進(jìn)行幾乎即時(shí)的交互。這意味著軟件和多個(gè)系統(tǒng)可以在團(tuán)隊(duì)認(rèn)為成熟的情況下產(chǎn)品化,但其中的某一個(gè)特性不需要已經(jīng)被激活。Decider還允許Twitter進(jìn)行二進(jìn)制或百分比的切換,例如讓一個(gè)特性只針對x%的用戶開放。Twitter還可以先把完全未激活并完全安全的特性部署上線,然后梯度的開啟/關(guān)閉,知道Twitter有足夠的自信保證特性可以正確的運(yùn)行并且系統(tǒng)可以負(fù)擔(dān)這個(gè)新的負(fù)荷。所有這些努力都可以減輕Twitter進(jìn)行團(tuán)隊(duì)之間溝通協(xié)調(diào)的活動,取而代之Twitter可以在系統(tǒng)運(yùn)行時(shí)做Twitter想要的定制/配置。

標(biāo)簽:三門峽 安陽 邵陽 呼倫貝爾 畢節(jié) 湘西 湖州 辛集

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《剖析Twitter處理峰值方面所做的一些改進(jìn)與優(yōu)化》,本文關(guān)鍵詞  ;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 收縮
    • 微信客服
    • 微信二維碼
    • 電話咨詢

    • 400-1100-266