面向海量服務(wù)的設(shè)計(jì)原則和策略總結(jié)
互聯(lián)網(wǎng)服務(wù)的特點(diǎn)就是面向海量級(jí)的用戶,面向海量級(jí)的用戶如何提供穩(wěn)定的服務(wù)呢?這里,對(duì)這幾年的一些經(jīng)驗(yàn)積累和平時(shí)接觸的一些理念做一個(gè)總結(jié)。
一、原則
1.Web服務(wù)的CAP原理
CAP指的是三個(gè)要素:一致性(Consistency)、可用性(Availability)、分區(qū)容忍性(Partition tolerance)。CAP原理指的是這三個(gè)要素最多只能同時(shí)實(shí)現(xiàn)兩點(diǎn),不可能三者兼顧,對(duì)于海量級(jí)服務(wù),一般這是一條常記心中的基準(zhǔn)準(zhǔn)則。
如下是《Web服務(wù)的CAP 》關(guān)于CAP的定義:
一致性:可以參考數(shù)據(jù)庫(kù)的一致性。每次信息的讀取都需要反映最新更新后的數(shù)據(jù)。
可用性:高可用性意味著每一次請(qǐng)求都可以成功完成并受到響應(yīng)數(shù)據(jù)
分區(qū)寬容度:這個(gè)是容錯(cuò)機(jī)制的要求。一個(gè)服務(wù)需要在局部出錯(cuò)的情況下,沒(méi)有出錯(cuò)的那部分被復(fù)制的數(shù)據(jù)分區(qū)仍然可以支持部分服務(wù)的操作,可以簡(jiǎn)單的理解為可以很容易的在線增減機(jī)器以達(dá)到更高的擴(kuò)展性,即所謂的橫向擴(kuò)展能力。
面向海量級(jí)的分布式服務(wù)設(shè)計(jì),基本上分區(qū)容忍性(Partition tolerance)是第一要素,因此根據(jù)業(yè)務(wù)的情況,我們需要在一致性(Consistency)和可用性(Availability)之間做取舍。對(duì)于一些業(yè)務(wù),譬如支付寶或財(cái)付通,一致性會(huì)是第一考慮要素,即使是延遲的不一致也是不可接受的,這種時(shí)候只能犧牲可用性以保證一致性。對(duì)于一些應(yīng)用,譬如淘寶或拍拍交易中的評(píng)價(jià)信息,一般用戶是可以接受延遲的一致性,這種時(shí)候可以優(yōu)先考慮可用性,而用最終一致性來(lái)保證數(shù)據(jù)一致,譬如通過(guò)某種對(duì)帳機(jī)制。對(duì)于一些應(yīng)用,甚至一致性都并非要求,只需要保證差不多一致性即可,譬如Q-zone中的農(nóng)場(chǎng)游戲中的偷菜。
根據(jù)我們應(yīng)用的業(yè)務(wù)需求,選擇合適的一致性級(jí)別,以更好地保證系統(tǒng)的分區(qū)容忍性和可用性。
2.柔性可用
面向海量級(jí)的分布式服務(wù)設(shè)計(jì),我們要意識(shí)到,一切都是不可靠的,在不可靠的環(huán)境的環(huán)境中構(gòu)建可靠的應(yīng)用,其中最重要的一點(diǎn)就是保持系統(tǒng)的柔性。
1)不可靠的環(huán)境
我們可能已經(jīng)見慣一個(gè)遠(yuǎn)程服務(wù)提供不了服務(wù)了,運(yùn)行一段時(shí)間后WebServer突然不響應(yīng)了,數(shù)據(jù)庫(kù)隨著負(fù)載的不斷增加再放上一條SQL語(yǔ)句就會(huì)垮掉。但是,硬盤壞掉、電源斷掉、光纖中斷,聽起來(lái)似乎多么不可思議,然而,當(dāng)一個(gè)海量服務(wù)需要成千上萬(wàn)臺(tái)服務(wù)器、需要部署全國(guó)各地的數(shù)十個(gè)數(shù)據(jù)中心、需要橫跨電信網(wǎng)通教育網(wǎng)三大網(wǎng)絡(luò)的時(shí)候,一切聽起來(lái)不可思議的事情會(huì)變成常態(tài)。一切都是不可靠的,唯一可靠的就是不可靠本身。
2)劃分服務(wù)級(jí)別
我們應(yīng)該意識(shí)到,在這種不可靠的環(huán)境中提供完美的服務(wù),本身就是一個(gè)神話,即使不是說(shuō)完全不可能,但至少是代價(jià)高昂的,因此,當(dāng)某些問(wèn)題發(fā)生(環(huán)境變地不可靠的時(shí)候),我們必須做出取舍,選擇為用戶提供用戶最關(guān)心的服務(wù),這種服務(wù)雖然聽起來(lái)是有損的(至少是不完美的),但卻能在一定程度上滿足用戶大部分的需求。譬如,當(dāng)網(wǎng)絡(luò)帶寬無(wú)法為用戶提供最好的體驗(yàn)而擴(kuò)容又不是短期可以達(dá)到的時(shí)候,選擇降低一些非重要服務(wù)的體驗(yàn)是一個(gè)比較好的選擇。
在面向海量互聯(lián)網(wǎng)的設(shè)計(jì)當(dāng)中,對(duì)服務(wù)進(jìn)行分級(jí),當(dāng)系統(tǒng)變地不可靠的時(shí)候,優(yōu)先提供重要優(yōu)先級(jí)的服務(wù)。
3)盡快響應(yīng)
互聯(lián)網(wǎng)用戶的耐心是非常有限的,如果一個(gè)頁(yè)面需要3秒以上才能看到,也許大部分用戶的第一選擇就是關(guān)掉瀏覽器。在構(gòu)建柔性可用的互聯(lián)網(wǎng)服務(wù)的時(shí)候,響應(yīng)時(shí)間大部分情況下都是需要最優(yōu)先考慮。還是一句話,環(huán)境是不可靠的,當(dāng)我們無(wú)法盡快從遠(yuǎn)程服務(wù)獲得數(shù)據(jù)、當(dāng)數(shù)據(jù)庫(kù)已經(jīng)慢如蝸牛,也許當(dāng)后臺(tái)還在吭哧吭哧干活的時(shí)候,用戶老早已經(jīng)關(guān)閉了頁(yè)面,處理返回的數(shù)據(jù)也只是在浪費(fèi)表情,面向互聯(lián)網(wǎng)用戶,響應(yīng)就是生命。
二、策略
如何讓我們的應(yīng)用提供更高質(zhì)量的服務(wù)呢,這里是一些在日常開發(fā)使用到或者觀察到的一些策略的總結(jié):
1.數(shù)據(jù)sharding
海量服務(wù)相應(yīng)也意味著海量的用戶和海量的用戶數(shù)據(jù),大家都知道,即使是再?gòu)?qiáng)大的數(shù)據(jù)庫(kù)、再?gòu)?qiáng)大服務(wù)器,在單表上億規(guī)模的數(shù)據(jù)足夠讓一條簡(jiǎn)單的SQL語(yǔ)句慢如蝸牛(甚至于在百萬(wàn)、千萬(wàn)級(jí)別上,如果沒(méi)有采取合適的策略,都無(wú)法滿足服務(wù)要求),一般處理這種千萬(wàn)上億級(jí)數(shù)據(jù)的大家基本上都會(huì)想到的就是數(shù)據(jù)sharding,將數(shù)據(jù)切割成多個(gè)數(shù)據(jù)集,分散到多個(gè)數(shù)據(jù)庫(kù)的多個(gè)表中(譬如將用戶數(shù)據(jù)按用戶ID切割成4個(gè)數(shù)據(jù)庫(kù)每個(gè)數(shù)據(jù)庫(kù)100個(gè)表共400個(gè)表),由于每個(gè)表數(shù)據(jù)足夠小可以讓我們的SQL語(yǔ)句快速地執(zhí)行。而至于如何切割,實(shí)際上跟具體的業(yè)務(wù)策略有關(guān)系。
當(dāng)然,我們要認(rèn)識(shí)到,這種數(shù)據(jù)sharding并非全無(wú)代價(jià)的,這也意味著我們需要做出一些折中,譬如可能很難進(jìn)行跨表數(shù)據(jù)集的查詢、聯(lián)表和排序也變地非常困難、同時(shí)數(shù)據(jù)庫(kù)client程序編寫也會(huì)變地更加復(fù)雜、保證數(shù)據(jù)一致性在某些情況下會(huì)變地困難重重。sharding并非萬(wàn)能藥,選擇是否sharding、如何sharding、為sharding如何換用一個(gè)近似的業(yè)務(wù)描述方式,這是業(yè)務(wù)設(shè)計(jì)需要仔細(xì)考慮的問(wèn)題。
2.Cache
經(jīng)驗(yàn)會(huì)告訴我們,基本上大部分系統(tǒng)的瓶頸會(huì)集中在IO/數(shù)據(jù)庫(kù)上,常識(shí)也告訴我們,網(wǎng)絡(luò)和內(nèi)存的速度比IO/數(shù)據(jù)庫(kù)會(huì)提升甚至不止一個(gè)數(shù)量級(jí)。面向海量服務(wù),Cache基本上是一個(gè)必選項(xiàng),分布式Cache更是一個(gè)不二選擇,根據(jù)我們的需要,我們可以選擇memcached(非持久化)、memcachedb/Tokyo Tyrant(持久化),甚至構(gòu)建自己的cache平臺(tái)。
在使用Cache上,下面是需要仔細(xì)考慮的點(diǎn):
選擇合適的Cache分布算法,基本上我們會(huì)發(fā)現(xiàn)使用取模方式?jīng)Q定Cache位置是不可靠的,因?yàn)閴墓?jié)點(diǎn)的摘除或者節(jié)點(diǎn)擴(kuò)量會(huì)讓我們的Cache命中率在短時(shí)間內(nèi)下降到冰點(diǎn),甚至?xí)?dǎo)致系統(tǒng)在短期內(nèi)的負(fù)載迅速增長(zhǎng)甚至于崩潰,選擇一種合適的分布算法非常重要,譬如穩(wěn)定的一致性哈希
Cache管理:為每個(gè)應(yīng)用配置獨(dú)立的Cache通常不是一個(gè)好主意,我們可以選擇在大量的機(jī)器上,只要有空閑內(nèi)存,則運(yùn)行Cache實(shí)例,將Cache實(shí)例分成多個(gè)組,每個(gè)組就是一個(gè)完整的Cache池,而多個(gè)應(yīng)用共享一個(gè)Cache池
合理的序列化格式:使用緊湊的序列化方案存儲(chǔ)Cache數(shù)據(jù),盡量少存儲(chǔ)冗余數(shù)據(jù),一方面可以最大能力地榨取Cache的存儲(chǔ)利用率,另一方面,可以更方便地進(jìn)行容量預(yù)估。此外,不可避免地,隨著業(yè)務(wù)的升級(jí),存儲(chǔ)的數(shù)據(jù)的格式有可能會(huì)變更,序列化也需要注意向上兼容的問(wèn)題,讓新格式的客戶端能夠支持舊的數(shù)據(jù)格式。
容量估算:在開始運(yùn)行之前,先為自己的應(yīng)用可能使用到的容量做一個(gè)容量預(yù)估,以合理地分配合適的Cache池,同時(shí)為可能的容量擴(kuò)充提供參考。
容量監(jiān)控:Cache命中率怎么樣,Cache的存儲(chǔ)飽和度怎么樣,Client的Socket連接數(shù)等等,對(duì)這些數(shù)據(jù)的采集和監(jiān)控,將為業(yè)務(wù)的調(diào)整和容量的擴(kuò)充提供了數(shù)據(jù)支持。
選擇在哪層上進(jìn)行Cache,譬如數(shù)據(jù)層Cache、應(yīng)用層Cache和Web層Cache,越靠近數(shù)據(jù),Cache的通用性越高,越容易保持Cache數(shù)據(jù)的一致性,但相應(yīng)的處理流程也越長(zhǎng),而越靠近用戶,Cache的通用性越差,越難保證Cache數(shù)據(jù)的一致性,但是響應(yīng)也越快,根據(jù)業(yè)務(wù)的特點(diǎn),選擇合適的Cache層是非常重要的。一般而言,我們會(huì)選擇將粗粒度、極少變更、數(shù)據(jù)對(duì)用戶不敏感(即可以一定程度上接受誤差)、并且非針對(duì)用戶級(jí)的數(shù)據(jù),在最靠近用戶的層面上Cache,譬如圖片Cache、TOP X等數(shù)據(jù);而將一些細(xì)粒度、變更相對(duì)頻繁、用戶相對(duì)敏感的數(shù)據(jù)或者是針對(duì)用戶級(jí)的數(shù)據(jù)放在靠近數(shù)據(jù)的一段,譬如用戶的Profile、關(guān)系鏈等。
3.服務(wù)集群
面向海量服務(wù),系統(tǒng)的橫向擴(kuò)展基本上是第一要素,在我的經(jīng)驗(yàn)和經(jīng)歷中,服務(wù)集群需要考慮如下因素:
分層:合理地對(duì)系統(tǒng)進(jìn)行分層,將系統(tǒng)資源要求不同的部分進(jìn)行合理地邏輯/物理分層,一般對(duì)于簡(jiǎn)單業(yè)務(wù),Client層、WebServer層和DB層已經(jīng)足夠,對(duì)于更復(fù)雜業(yè)務(wù),可能要切分成Client層、WebServer層、業(yè)務(wù)層、數(shù)據(jù)訪問(wèn)層(業(yè)務(wù)層和數(shù)據(jù)訪問(wèn)層一般傾向于在物理上處于同一層)、數(shù)據(jù)存儲(chǔ)層(DB),太多的分層會(huì)導(dǎo)致處理流程變長(zhǎng),但相應(yīng)系統(tǒng)地靈活性和部署性會(huì)更強(qiáng)。
功能細(xì)粒度化:將功能進(jìn)行細(xì)粒度的劃分,并使用獨(dú)立的進(jìn)程部署,一方面能更有利于錯(cuò)誤的隔離,另一方面在功能變更的時(shí)候避免一個(gè)功能對(duì)其他功能產(chǎn)生影響
快慢分離/按優(yōu)先級(jí)分離部署:不同的服務(wù)具備不同的特點(diǎn),有些服務(wù)訪問(wèn)速度快有些訪問(wèn)速度慢,訪問(wèn)慢的服務(wù)可能會(huì)阻塞住導(dǎo)致整個(gè)服務(wù)不可用,有些服務(wù)優(yōu)先級(jí)別比較高(譬如打款之類的用戶比較關(guān)心的服務(wù)),有些服務(wù)優(yōu)先級(jí)別低(譬如日志記錄、發(fā)郵件之類),優(yōu)先級(jí)別低的服務(wù)可能會(huì)阻塞住優(yōu)先級(jí)別高的服務(wù),在部署上將不同特點(diǎn)的應(yīng)用分離部署避免相互影響是一個(gè)常用的做法
按數(shù)據(jù)集部署:如果每一層都允許對(duì)下一層所有的服務(wù)接口進(jìn)行訪問(wèn),將存在幾個(gè)嚴(yán)重的缺陷,一是隨著部署服務(wù)的增長(zhǎng),會(huì)發(fā)現(xiàn)下一層必須允許數(shù)量非常龐大的Socket連接進(jìn)來(lái),二是我們可能必須把不同的服務(wù)部署在不同的數(shù)據(jù)中心(DC)的不同機(jī)房上,即便是上G的光纖專線,機(jī)房間的穿梭流量也會(huì)變地不可接受,三是每個(gè)服務(wù)節(jié)點(diǎn)都是全數(shù)據(jù)容量接入,并不利于做一些有效的內(nèi)部?jī)?yōu)化機(jī)制,四是只能采用代碼級(jí)控制的灰度發(fā)布和部署。當(dāng)部署規(guī)模達(dá)到一定數(shù)量級(jí)的時(shí)候,按數(shù)據(jù)集橫向切割成多組服務(wù)集合,每組服務(wù)集合只為特定的數(shù)據(jù)集服務(wù),在部署上,每組服務(wù)集合可以部署在獨(dú)立的相同的數(shù)據(jù)中心(DC)上。
無(wú)狀態(tài):狀態(tài)將為系統(tǒng)的橫向擴(kuò)容帶來(lái)無(wú)窮盡的煩惱。對(duì)于狀態(tài)信息比少的情況,可以選擇將全部狀態(tài)信息放在請(qǐng)求發(fā)器端,對(duì)于狀態(tài)信息比較多的情況,可以考慮維持一個(gè)統(tǒng)一的Session中心。
選擇合適的負(fù)載均衡器和負(fù)載均衡策略:譬如在L4上負(fù)載均衡的LVS、L7上負(fù)載均衡的Nginx、甚至是專用的負(fù)載均衡硬件F5(L4),對(duì)于在L7上工作的負(fù)載均衡器,選擇合適的負(fù)載均衡策略也非常重要,一般讓用戶總是負(fù)載均衡到同一臺(tái)后端Server是一個(gè)很好的方式
4.灰度發(fā)布
當(dāng)系統(tǒng)的用戶增長(zhǎng)到一定的規(guī)模,一個(gè)小小功能的發(fā)布也會(huì)產(chǎn)生非常大的影響,這個(gè)時(shí)候,將功能先對(duì)一小部分用戶開放,并慢慢擴(kuò)展到全量用戶是一個(gè)穩(wěn)妥的做法,使用灰度化的發(fā)布將避免功能的BUG產(chǎn)生大面積的錯(cuò)誤。如下是一些常見的灰度控制策略:
白名單控制:只有白名單上的用戶才允許訪問(wèn),一般用于全新功能Alpha階段,只向被邀請(qǐng)的用戶開放功能
準(zhǔn)入門檻控制:常見的譬如gmail出來(lái)之初的邀請(qǐng)碼、QQ農(nóng)場(chǎng)開始階段的X級(jí)的黃鉆準(zhǔn)入,同樣一般用于新功能的Beta階段,慢慢通過(guò)一步一步降低門檻,避免在開始之處由于系統(tǒng)可能潛在的問(wèn)題或者容量無(wú)法支撐導(dǎo)致整個(gè)系統(tǒng)的崩潰。
按數(shù)據(jù)集開放:一般常用于成熟的功能的新功能開發(fā),避免新功能的錯(cuò)誤產(chǎn)生大面積的影響
5.設(shè)計(jì)自己的通信協(xié)議:二進(jìn)制協(xié)議、向上/下兼容
隨著系統(tǒng)的穩(wěn)定運(yùn)行訪問(wèn)量的上漲,慢慢會(huì)發(fā)現(xiàn),一些看起來(lái)工作良好的協(xié)議性能變地不可接受,譬如基于xml的協(xié)議xml-rpc,將會(huì)發(fā)現(xiàn)xml解析和包體的增大變地不可接受,即便是接近于二進(jìn)制的hessian協(xié)議,多出來(lái)的字段描述信息(按我的理解,hessian協(xié)議是類似于map結(jié)構(gòu)的,包含字段的名稱信息)和基于文本的http頭將會(huì)使協(xié)議效率變地低下。也許,在開始合適的時(shí)候而不是到最后不得已的時(shí)候,去設(shè)計(jì)一個(gè)良好的基于二進(jìn)制的高效的內(nèi)部通信協(xié)議是一個(gè)好的方式。按我的經(jīng)驗(yàn),設(shè)計(jì)自己的通信協(xié)議需要注意如下幾點(diǎn):
協(xié)議緊湊性,否則早晚你會(huì)為你浪費(fèi)的空間痛心疾首
協(xié)議擴(kuò)展性,早晚會(huì)發(fā)現(xiàn)舊的協(xié)議格式不能適應(yīng)新的業(yè)務(wù)需求,而在早期預(yù)留變地非常地重要,基本上,參見一些常用的規(guī)范,魔術(shù)數(shù)(對(duì)于無(wú)效果的請(qǐng)求可以迅速丟棄)、協(xié)議版本信息、協(xié)議頭、協(xié)議Body、每個(gè)部分(包括結(jié)構(gòu)體信息中的對(duì)象)的長(zhǎng)度這些信息是不能省的
向下兼容和向上兼容:但功能被大規(guī)模地調(diào)用的時(shí)候,發(fā)布一個(gè)新的版本,讓所有的client同時(shí)升級(jí)基本上是不可接受的,因此在設(shè)計(jì)之處就需要考慮好兼容性的問(wèn)題
6.設(shè)計(jì)自己的Application Server
事情進(jìn)行到需要自己設(shè)計(jì)通信協(xié)議,自己構(gòu)建Application Server也變地順理成章,下面是在自己開發(fā)Application Server的時(shí)候需要處理的常見的問(wèn)題:
過(guò)載保護(hù):當(dāng)系統(tǒng)的某個(gè)部件出現(xiàn)問(wèn)題的時(shí)候,最常見的情況是整個(gè)系統(tǒng)的負(fù)載出現(xiàn)爆炸性的增長(zhǎng)而導(dǎo)致雪崩效應(yīng),在設(shè)計(jì)application server的時(shí)候,必須注意進(jìn)行系統(tǒng)的過(guò)載保護(hù),當(dāng)請(qǐng)求可以預(yù)期無(wú)法處理的時(shí)候(譬如排隊(duì)滿載或者排隊(duì)時(shí)間過(guò)長(zhǎng)),丟棄是一個(gè)明智的選擇,TCP的backlog參數(shù)是一個(gè)典型的范例。
頻率控制:即便是同一系統(tǒng)中的其他應(yīng)用在調(diào)用,一個(gè)糟糕的程序可能會(huì)將服務(wù)的所有資源占完,因此,應(yīng)用端必須對(duì)此做防范措施,頻率控制是其中比較重要的一個(gè)
異步化/無(wú)響應(yīng)返回:對(duì)于一些業(yè)務(wù),只需要保證請(qǐng)求會(huì)被處理即可,客戶端并不關(guān)心什么時(shí)候處理完,只要最終保證處理就行,甚至最終沒(méi)有處理也不是很嚴(yán)重的事情,譬如郵件,對(duì)于這種應(yīng)用,應(yīng)快速響應(yīng)避免占著寶貴的連接資源,而將請(qǐng)求進(jìn)入異步處理隊(duì)列慢慢處理。
自我監(jiān)控:Application Server本身應(yīng)該具備自我監(jiān)控的功能,譬如性能數(shù)據(jù)采集、為外部提供內(nèi)部狀態(tài)的查詢(譬如排隊(duì)情況、處理線程、等待線程)等
預(yù)警:譬如當(dāng)處理變慢、排隊(duì)太多、發(fā)生請(qǐng)求丟棄的情況、并發(fā)請(qǐng)求太多的時(shí)候,Application Server應(yīng)該具備預(yù)警的能力以快速地對(duì)問(wèn)題進(jìn)行處理
模塊化、模塊間松耦合、機(jī)制和策略分離:如果不想一下子面對(duì)所有的復(fù)雜性或不希望在修改小部分而不得不對(duì)所有的測(cè)試進(jìn)行回歸的話,模塊化是一個(gè)很好的選擇,將問(wèn)題進(jìn)行模塊切割,每個(gè)模塊保持合理的復(fù)雜度,譬如對(duì)于這里的Application Server,可以切分成請(qǐng)求接收/管理/響應(yīng)、協(xié)議解析、業(yè)務(wù)處理、數(shù)據(jù)采集、監(jiān)控和預(yù)警等等模塊。這里同時(shí)要注意塊間使用松耦合的方式交互,譬如,請(qǐng)求接收和業(yè)務(wù)處理之間則可以使用阻塞隊(duì)列通信的方式降低耦合。另外還需要注意的是機(jī)制和策略的分離,譬如協(xié)議可能會(huì)變更、性能采集和告警的方式可能會(huì)變化等等,事先的機(jī)制和策略分離,策略變更的處理將變地更加簡(jiǎn)單。
7.Client
很多應(yīng)用會(huì)作為服務(wù)的Client,去調(diào)用其他的服務(wù),如下是在做為Client應(yīng)該注意的一些問(wèn)題:
服務(wù)不可靠:作為Client永遠(yuǎn)要記住的一點(diǎn)就是,遠(yuǎn)程服務(wù)永遠(yuǎn)是不可靠的,因此作為Client自己要注意做自我保護(hù),當(dāng)遠(yuǎn)程服務(wù)如果無(wú)法訪問(wèn)時(shí),做折中處理
超時(shí)保護(hù):還是上面所說(shuō)的,遠(yuǎn)程服務(wù)永遠(yuǎn)都是不可靠的,永遠(yuǎn)也無(wú)法預(yù)測(cè)到遠(yuǎn)程什么時(shí)候會(huì)響應(yīng),甚至可能不會(huì)響應(yīng)(譬如遠(yuǎn)程主機(jī)宕機(jī)),請(qǐng)求方要做好超時(shí)保護(hù),譬如對(duì)于主機(jī)不可達(dá)的情況,在linux環(huán)境下,有時(shí)會(huì)讓客戶端等上幾分鐘TCP層才會(huì)最終告訴你服務(wù)不可到達(dá)。
并發(fā)/異步:為了提速響應(yīng),對(duì)于很多可以并行獲取的數(shù)據(jù),我們總是應(yīng)該并行地去獲取,對(duì)于一些我們無(wú)法控制的同步接口——譬如讀數(shù)據(jù)庫(kù)或同步讀cache——雖然不是很完美,但多線程并行去獲取是一個(gè)可用的選擇,而對(duì)于服務(wù)端都是使用自構(gòu)建的Application Server,使用異步Client接口至關(guān)重要,將請(qǐng)求全部發(fā)送出去,使用異步IO設(shè)置超時(shí)等待返回即可,甚至于更進(jìn)一步異步anywhere,在將client與application server整合到一塊的時(shí)候,請(qǐng)求發(fā)送出去之后立即返回,將線程/進(jìn)程資源歸還,而在請(qǐng)求響應(yīng)回來(lái)符合條件的時(shí)候,觸發(fā)回調(diào)做后續(xù)處理。
8.監(jiān)控和預(yù)警
基本上我們會(huì)見慣了各種網(wǎng)絡(luò)設(shè)備或服務(wù)器的監(jiān)控,譬如網(wǎng)絡(luò)流量、IO、CPU、內(nèi)存等監(jiān)控?cái)?shù)據(jù),然而除了這些總體的運(yùn)行數(shù)據(jù),應(yīng)用的細(xì)粒度化的數(shù)據(jù)也需要被監(jiān)控,服務(wù)的訪問(wèn)壓力怎么樣、處理速度怎么樣、性能瓶頸在哪里、帶寬主要是被什么應(yīng)用占、Java虛擬機(jī)的CPU占用情況怎么樣、各內(nèi)存區(qū)的內(nèi)存占用情況如何,這些數(shù)據(jù)將有利于我們更好的了解系統(tǒng)的運(yùn)行情況,并對(duì)系統(tǒng)的優(yōu)化和擴(kuò)容提供數(shù)據(jù)指導(dǎo)。
除了應(yīng)用總體監(jiān)控,特定業(yè)務(wù)的監(jiān)控也是一個(gè)可選項(xiàng),譬如定時(shí)檢查每個(gè)業(yè)務(wù)的每個(gè)具體功能點(diǎn)(url)訪問(wèn)是否正常、訪問(wèn)速度如何、頁(yè)面訪問(wèn)速度如何(用戶角度,包括服務(wù)響應(yīng)時(shí)間、頁(yè)面渲染時(shí)間等,即網(wǎng)頁(yè)測(cè)速)、每個(gè)頁(yè)面的PV、每個(gè)頁(yè)面(特別是圖片)每天占用的總帶寬等等。這些數(shù)據(jù)將為系統(tǒng)預(yù)警和優(yōu)化提供數(shù)據(jù)上的支持,例如對(duì)于圖片,如果我們知道哪些圖片占用的帶寬非常大(不一定是圖片本身比較大,而可能是訪問(wèn)比較大),則一個(gè)小小的優(yōu)化會(huì)節(jié)省大量的網(wǎng)絡(luò)帶寬開銷,當(dāng)然,這些事情對(duì)于小規(guī)模的訪問(wèn)是沒(méi)有意義的,網(wǎng)絡(luò)帶寬開銷節(jié)省的成本可能都沒(méi)有人力成本高。
除了監(jiān)控,有效的預(yù)警機(jī)制也是必不可少,應(yīng)用是否在很好地提供服務(wù)、響應(yīng)時(shí)間是否能夠達(dá)到要求、系統(tǒng)容量是否達(dá)到一個(gè)閥值。有效的預(yù)警機(jī)制將讓我們盡快地對(duì)問(wèn)題進(jìn)行處理。
9.配置中心化
當(dāng)系統(tǒng)錯(cuò)誤的時(shí)候,我們?nèi)绾伪M快地恢復(fù)呢,當(dāng)新增服務(wù)節(jié)點(diǎn)的時(shí)候,如何盡快地讓真?zhèn)€系統(tǒng)感知到呢?當(dāng)系統(tǒng)膨脹之后,如果每次摘除服務(wù)節(jié)點(diǎn)或者新增節(jié)點(diǎn)都需要修改每臺(tái)應(yīng)用配置,那么配置和系統(tǒng)的維護(hù)將變地越來(lái)越困難。
配置中心化是一個(gè)很好的處理這個(gè)問(wèn)題的方案,將所有配置進(jìn)行統(tǒng)一地存儲(chǔ),而當(dāng)發(fā)生變更的時(shí)候(摘除問(wèn)題節(jié)點(diǎn)或者擴(kuò)量增加服務(wù)節(jié)點(diǎn)或新增服務(wù)),使用一些通知機(jī)制讓各應(yīng)用刷新配置。甚至于,我們可以自動(dòng)地檢測(cè)出問(wèn)題節(jié)點(diǎn)并進(jìn)行智能化的切換。
三、最后
構(gòu)建面向海量用戶的服務(wù),可以說(shuō)是困難重重挑戰(zhàn)重重,一些原則和前人的設(shè)計(jì)思路可以讓我們獲得一些幫助,但是更大的挑戰(zhàn)會(huì)來(lái)源于細(xì)節(jié)部分,按我們技術(shù)老大的說(shuō)法,原則和思路只要看幾本書是個(gè)技術(shù)人員都會(huì),但決定一個(gè)系統(tǒng)架構(gòu)師能力的,往往卻是對(duì)細(xì)節(jié)的處理能力。因此,在掌握原則和前人的設(shè)計(jì)思路的基礎(chǔ)上,更深入地挖掘技術(shù)的細(xì)節(jié),才是面向海量用戶的服務(wù)的制勝之道。
【編輯推薦】