高性能Web應(yīng)用打造攻略:擴(kuò)展過程中20個最大的絆腳石
Sean Hull是Heavyweight Internet Group的創(chuàng)始人兼高級顧問,擁有20年以上技術(shù)顧問相關(guān)經(jīng)驗,曾為多家知名機構(gòu)提供咨詢,其中包括The Hollywood Reporter、Billboard、NBC Universal、Zagats、Rent the Runway及ideeli,這些高速增長的公司每個月處理接近1億的獨立訪客。Hull在Amazon EC2部署和Linux及MySQL性能上有著豐富的經(jīng)驗。巨大流量的處理需涉及多個方面,其中包括網(wǎng)站擴(kuò)展性、業(yè)務(wù)連續(xù)性、安全及架構(gòu)挑戰(zhàn)等。近日,Hull分享了高性能Web應(yīng)用打造的經(jīng)驗,剖析了擴(kuò)展之路上20個最大的絆腳石。以下為譯文:
1. 二階段提交
通常情況下,當(dāng)數(shù)據(jù)庫中的數(shù)據(jù)發(fā)生改變時,它需要同時被寫入內(nèi)存和硬盤。當(dāng)一個提交發(fā)生時,傳統(tǒng)數(shù)據(jù)庫需要負(fù)責(zé)數(shù)據(jù)在真實存儲媒質(zhì)上的持久化。牢記,內(nèi)存的數(shù)據(jù)在崩潰或者重啟后都會消失。即使數(shù)據(jù)已經(jīng)在數(shù)據(jù)庫中緩存,數(shù)據(jù)庫仍然需要將其持久化到磁盤上,MySQL的二進(jìn)制日志及Oracle的redo日志都符合這個要求。
通過MySQL集群或者類似DRBD(Distributed Replicated Block Device)或者Amazon Multi-AZ(Multi-Availability Zone)的分布式文件系統(tǒng),提交并不僅僅是在本地發(fā)生,同時也在遠(yuǎn)端。二階段提交意味著需要從遠(yuǎn)端得到反饋,鑒于網(wǎng)絡(luò)及一些其它的延時,提交速度可能會被毫秒級的降低,仿佛高速公路上的所有汽車都因重載變慢。如有考慮使用Multi-AZ或者讀備份,不妨查看Amazon RDS(Relational Database Service)與MySQL的比較。
同步復(fù)制同樣會出現(xiàn)這些問題,因此MySQL解決方案是半同步的,這也可以看做是在二階段提交上的一些讓步。
2. 緩存不足
在所有層中緩存的作用都至關(guān)重要,那么什么地方最需要使用緩存:瀏覽器、頁面、對象還是數(shù)據(jù)庫存?下面不妨統(tǒng)統(tǒng)試一下。
瀏覽器緩存似乎遙不可及,除非你清楚瀏覽器是從Web Server中取出指令及其渲染的頁面。因此,如果包含的對象有一個比較長的生命周期,瀏覽器將會緩存他們,不需要再次進(jìn)行讀取。這不僅會加快用戶的瀏覽速度,同樣會有益于Server對網(wǎng)站的托管,因為會切實的減少用戶的二次讀取。
猛戳這里查看更多瀏覽器緩存相關(guān),確保設(shè)置了期滿頭文件及緩存控制。
頁面緩存需要使用類似Varnish的技術(shù),可以將它看成一個迷你的高速、低開銷Web Server。它不可以支撐類似Apache可以的復(fù)雜頁面,但是它可以讓非常簡單的頁面更快。因此位于Apache之前,用于減少負(fù)載,讓Apache可以處理更加復(fù)雜的頁面。就像交通警察,在專注更復(fù)雜的機動車前,先給自行車放行。
對象緩存由類似memcache的組件完成,可以把它當(dāng)做是應(yīng)用程序的便利貼。做數(shù)據(jù)庫查詢時會先訪問緩存尋求數(shù)據(jù),如果發(fā)現(xiàn)了所需的數(shù)據(jù),那么結(jié)果返回的時間將比訪問數(shù)據(jù)庫快10-100倍,這樣就可以快速的構(gòu)建頁面,從而在眨眼間為用戶呈現(xiàn)。如果它沒有發(fā)現(xiàn)所需的數(shù)據(jù),或者只發(fā)現(xiàn)了一部分,那么將會建立數(shù)據(jù)庫請求并將返回的數(shù)據(jù)放于緩存中,讓更多的后來者受益。
3. 緩慢的磁盤I/O、RAID 5、多租戶存儲
數(shù)據(jù)庫中的一切都受到存儲的限制,這里既包含了空間問題,也受設(shè)備讀寫的速度掣肘。
如果你使用實體服務(wù)器,那么一定要當(dāng)心RAID 5,獨立磁盤冗余陣列的一種,數(shù)據(jù)保護(hù)和奇偶性將嚴(yán)重的影響寫操作。同時,如果其中一個磁盤損壞,那么這個陣列在磁盤重建時將變得非常緩慢。
這個方案一般使用RAID 10,它將為你提供獨立的鏡像集。這導(dǎo)致沒有奇偶校驗計算,從而不會影響重建時的速度。
云環(huán)境可能會涉及到類似于Amazon EBS(Elastic Block Store,一個類似于SAN的虛擬化磁盤)的技術(shù)。鑒于其基于網(wǎng)絡(luò),你必須與其它租戶競爭存儲的讀寫。因為每個存儲能支撐的讀寫速度是固定的,所以你的鄰居可能會影響到你網(wǎng)站及應(yīng)用程序的讀寫速度。
最近,Amazon又公布了一個重量級產(chǎn)品Provisioned IOPS(每秒I/O操作)。對于技術(shù)專家來說看起來非常不錯,但是對于其它人來說毫無價值。盡管如此,其依然重要,這意味著你可以鎖定你數(shù)據(jù)庫所需的磁盤性能。如果你想在Amazon上托管數(shù)據(jù)庫,那么不妨多關(guān)注一下這個。
4. 串行處理
在超市結(jié)賬時,如果有10個收銀臺開放,那么從事的是并行處理。如果每個收銀臺都在休息,只有一個登記處開放,那么從事的是串行操作。那么結(jié)賬的隊伍將變得非常長,不僅是結(jié)賬人的心情受到影響,購物者也同樣如此。這點經(jīng)常發(fā)生在線路不夠的大橋收費站以及許多人一起離場的體育場所。
網(wǎng)絡(luò)應(yīng)用需要嚴(yán)格的避免串行,因等待API調(diào)用而產(chǎn)生的阻塞,所有的后端節(jié)點都在等待一個搜索服務(wù)器,只要你應(yīng)用程序的某處形成一個線就代表了串行化的發(fā)生,那么必須不惜一切代價去清除它。
5. 缺少Feature Flag
在給業(yè)務(wù)部門建立應(yīng)用時,開發(fā)者一般從特性和功能入手。Feature Flag將至關(guān)重要,它讓人們可以通過后端配置文件或管理員UI頁面關(guān)閉或者打開特性。
為什么他們?nèi)绱酥匾?如果你有早上4點的救火經(jīng)驗,那么你將明白啟動應(yīng)急計劃的必要性。你需要可以關(guān)閉評級、評論以及應(yīng)用程序其它的一些特性,這將不會導(dǎo)致整個系統(tǒng)崩潰。更重要的是,在新特性發(fā)布時,有些時候問題并不明顯,直到一群互聯(lián)網(wǎng)用戶同時涌入。Feature Flag讓你可以選擇性的關(guān)閉一些功能,而不是關(guān)掉整個網(wǎng)站。
6. 單一的數(shù)據(jù)庫副本
你必須使用一個以上的讀副本或者M(jìn)ySQL從節(jié)點,這允許在主節(jié)點出問題時的快速故障轉(zhuǎn)移。
擁有數(shù)據(jù)庫的多個副本意味著橫向擴(kuò)展。如果你有兩個,你就會看到3-4個會對你基礎(chǔ)設(shè)施的提升。
7. 使用數(shù)據(jù)庫進(jìn)行排隊
MySQL數(shù)據(jù)庫非常適合儲存表格、數(shù)據(jù)以及他們之間的關(guān)系,不幸的是,它并不適合處理應(yīng)用程序的隊列。盡管如此,許多開發(fā)者都習(xí)慣使用一個表格來達(dá)到這個目的。比如,讓你的應(yīng)用程序包含一些作業(yè)表格,或者一個狀態(tài)列,擁有一些類似“in-process”、“in-queue” 及“finished”的值。
因為鎖競爭、scan及 poll進(jìn)程將造成更多的工作,這些解決方案會帶來一些擴(kuò)展性問題,它們將會顯著的降低數(shù)據(jù)庫速度。幸運的是這里存在很多有效的開源解決方案,比如RabbitMQ及Amazon的SQS。
8. 使用一個做全文查詢的數(shù)據(jù)庫
頁面搜索是掣肘應(yīng)用程序的另一個方面,盡管MySQL一段時間也支撐了full-text索引。但是它們只對MyISAM表格有效,其它類型表格都不買賬,一直困擾著開發(fā)者。
一個解決方案是使用類似Solr的專業(yè)搜索引擎,這些技術(shù)擁有許多很好的庫去支撐你的編程語言,同時會提供一個更快的搜索速度。這些方案同樣易于擴(kuò)展,并且不會讓你的數(shù)據(jù)庫成為累贅。
替代方案是Sphinx SE,一個MySQL存儲引擎,將Sphinx服務(wù)器整合進(jìn)數(shù)據(jù)庫。此外,MySQL 5.6版本中還使用了InnoDB做全文搜索的默認(rèn)搜索引擎。
9. 對象關(guān)系模型
ORM,就像毒藥一樣,一旦進(jìn)行使用,就很難擺脫。有利的一面是ORM有益于快速原型,并且允許非專家級MySQL開發(fā)者使用對象或者內(nèi)存模式進(jìn)行讀寫訪問。如果你不進(jìn)行擴(kuò)展,那么他們的速度將非??欤⒆尮δ艿目焖俳桓兜玫奖U?。
然后DBA(數(shù)據(jù)庫管理員)會因為緩慢且丑陋的查詢來到開發(fā)團(tuán)隊并且說:“這個查詢在應(yīng)用程序什么地方,我們需要進(jìn)行修復(fù),它需要被重寫。”開發(fā)團(tuán)隊則會說:“我們也不知道!”從而會收到來自運營組一些質(zhì)疑的眼神。
有能力對bad sql進(jìn)行跟蹤并將其指出是非常重要的。DBA團(tuán)隊需要一定的指引找到bad sql的源頭。如果查詢是來自O(shè)RM,他們并不具備這些指引。這樣你的團(tuán)隊將面對一個巨大的技術(shù)負(fù)債,同樣也是個非常難以解決的挑戰(zhàn)。
10. 缺少Instrumentation
Instrumentation(儀表盤)為應(yīng)用程序提供了碼表和油表,這是汽車不可缺少的兩個部分。他們提供了應(yīng)用程序的內(nèi)部工作信息:他們記錄了時間信息,并且提供了應(yīng)用程序耗時最多的環(huán)節(jié)。
一個非常人氣的網(wǎng)絡(luò)解決方案就是New Relic,它提供了一個非常全面的可視化界面,針對各個領(lǐng)域工作者——項目經(jīng)理、開發(fā)者、運營團(tuán)隊,甚至是業(yè)務(wù)部門都可以從圖中發(fā)現(xiàn)問題所在。當(dāng)然,現(xiàn)在已經(jīng)有很多的開源Instrumentation。
11. 缺少代碼倉庫及版本管理
盡管現(xiàn)在這個問題已非常少見,但是還有有些互聯(lián)網(wǎng)公司在沒有版本控制下去建立應(yīng)用程序。當(dāng)然那些使用了的人,很清楚它將給團(tuán)隊帶來的日常優(yōu)勢和組織控制。
如果你沒有使用,隨著應(yīng)用程序變得更加復(fù)雜,你將被卷入技術(shù)負(fù)債的漩渦,為應(yīng)用不同部分添加員工將變得異常困難。
一旦你使用版本控制,確保囊括了所有的組件,包含配置文件以及其它要素。而丟失部署時需要用到的部分,將帶來額外的風(fēng)險。
12. 單點故障
如果你的數(shù)據(jù)只存在一個主數(shù)據(jù)庫上,這就是一個單點故障。如果你的服務(wù)器位于一個單獨的磁盤上,這也是個單點故障。單點故障可以比作“阿基里斯之踵”技術(shù)用語。
不惜任何代價,單點故障都要在應(yīng)用程序中移除。麻煩的是如何去認(rèn)識單點故障,即使是選擇單一的云供應(yīng)商都可以稱為單點故障,如果擁有多個供應(yīng)商,或者使用Amazon不同的部分,那么AirBNB的服務(wù)將幸免Amazon 2012年10月的部分宕機。
13. 缺乏只瀏覽模式
如果你深夜在Yelp、Facebook或者是Tumblr上發(fā)布評論,你可能就會收到這樣的信息:“該特性不可用,請稍后再試”。稍后可能是50或者60分鐘,也許可能還需多試幾次。對于非技術(shù)用戶,他們?nèi)匀桓杏X網(wǎng)站在正常運行,只是奇怪了一點而已。
實際情況是,應(yīng)用程序只允許你去瀏覽網(wǎng)站,但是不可以做任何改變??赡苁侵鲾?shù)據(jù)庫或者是一些存儲組件不可用了。
只瀏覽模式可以通過保留主數(shù)據(jù)庫的多個讀備份來實現(xiàn),使用MySQL副本或者是Amazon讀副本類似途徑。這樣就可以在沒有主數(shù)據(jù)庫情況下,保留網(wǎng)站全部瀏覽功能正常,這一點非常重要。
14. 脆弱的溝通
在擴(kuò)展上談溝通可能非常奇怪,但是應(yīng)用程序技術(shù)層不可能因為團(tuán)隊間社交和文化上的差異分離。
強大的通信線路是必要的,隊員必須要知道在錯誤發(fā)生時將找誰。好的交流需要自信及知識淵博的領(lǐng)導(dǎo),廣泛的聽取意見并加以改善。
15. 缺少文檔
當(dāng)Web應(yīng)用程序包含許多層時,文檔至關(guān)重要。開發(fā)者需要給程序、功能、頁面做文檔,讓后來者看代碼時可以清晰的發(fā)現(xiàn)所需的提示及見解。當(dāng)有程序發(fā)生故障時,運營程序需要在配置文件上添加評論去表明更改歷史。業(yè)務(wù)流程及關(guān)系同樣應(yīng)該出現(xiàn)在公司的wiki里,讓人們發(fā)現(xiàn)自己問題的解決方案。
文檔可以在各個層次起到幫助作用,每個人都應(yīng)該擁抱這個愛好。
16 .缺少應(yīng)急演習(xí)
應(yīng)急通常情況下總會被忽視,團(tuán)隊可能會有“我們覆蓋的地方都有備份”這類的說辭。不錯備份、恢復(fù)的途徑很通吃,關(guān)鍵是確保備份的文件萬無一失。一旦在故障轉(zhuǎn)移時發(fā)現(xiàn)備份有缺失,那么你不愿意發(fā)生的事情必然發(fā)生。
應(yīng)急演習(xí)讓事情發(fā)生之前有了相應(yīng)的經(jīng)驗,公司應(yīng)該將此作為運營團(tuán)隊工作的一部分,每年都需要進(jìn)行幾次。在云時代,應(yīng)急演習(xí)已經(jīng)變得比以前輕松許多。為保證所有組件都被備份而啟動服務(wù)器是非常值得的,在這個過程中你將學(xué)到這項操作該持續(xù)多長時間,以及困難所在的地方,更知道需要小心些什么。
17. 缺少監(jiān)視和指標(biāo)
監(jiān)視有著與版本控制同樣的重要性:非?;?,缺少它工作將無法進(jìn)行;然而確實有一些網(wǎng)站沒有監(jiān)視,或者是監(jiān)視力度不夠——有些服務(wù)器或者是核心組件并未被監(jiān)視。
不間斷的收集系統(tǒng)及服務(wù)器數(shù)據(jù),同時,應(yīng)用程序和業(yè)務(wù)級別的可用性也同等重要。如果你不想親自動手,不妨考慮一個Web服務(wù)方案。
18. 莽撞的運營
你騎著馬在街道上飛奔,明著帶槍進(jìn)入酒吧,你認(rèn)為這是在交朋友?肯定不是,你在暴力的脅迫別人遵循,所有人都不會有歸屬感。強大的信心是好的,但是團(tuán)隊的合作是不可缺少的,團(tuán)隊的智慧高于任何個人。
團(tuán)隊需要不斷的對改變做交流,用管理的角度進(jìn)行,準(zhǔn)備好應(yīng)對失敗等等。采取小心及規(guī)避風(fēng)險的態(tài)度,永遠(yuǎn)都有備用計劃,你應(yīng)該有能力撤銷所有改變,并且認(rèn)真對待破壞性的改變,以及那些不可恢復(fù)的地方。
19. 日益增長的技術(shù)負(fù)債
隨著應(yīng)用不斷的增長,隊伍需要花越來越多的時間在老代碼的維護(hù)和支持上,消除漏洞及缺陷。因此,花在新特性上的時間將越來越少。必須謹(jǐn)慎的維護(hù)好新特性與技術(shù)負(fù)債上投入時間的平衡。如果你發(fā)現(xiàn)你的技術(shù)負(fù)債增加,可能就是橫下決心重寫的時候了。重寫可能會影響到短期新特性及客戶特性的開發(fā),但是從長遠(yuǎn)的角度上看是非常好的。
技術(shù)負(fù)債并不總是能被輕易的認(rèn)知,在你建立特性或者是修復(fù)bug時,你更習(xí)慣于聚焦局部的細(xì)節(jié),非常容易失去全局觀,這也是為什么全面人才更益于Web擴(kuò)展的原因。
20. 不足的日志
日志直接影響到度量及監(jiān)視。你在尋找故障和排錯時肯定希望得到更多的日志,但是在一個不間斷運行的情況下,你同樣會需要一些關(guān)鍵服務(wù)的日志。服務(wù)器系統(tǒng)日志、Apache及MySQL日志、緩存日志等,這些都需要被保存。而在日志太多時,你總是會減少一些地方的日志,或者裁剪及循環(huán)日志文件,從而丟棄舊的。