07 | 複雜度來源:低成本、安全、規模

此爲筆記

課程鏈接

https://time.geekbang.org/column/intro/100006601?utm_source=time_web&utm_medium=menu&utm_term=timewebmenu


 

關於複雜度來源,前面的專欄已經講了高性能、高可用和可擴展性,今天我來聊聊複雜度另外三個來源低成本、安全和規模。

低成本

當我們的架構方案只涉及幾臺或者十幾臺服務器時,一般情況下成本並不是我們重點關注的目標,但如果架構方案涉及幾百上千甚至上萬臺服務器,成本就會變成一個非常重要的架構設計考慮點。例如,A 方案需要 10000 臺機器,B 方案只需要 8000 臺機器,單從比例來看,也就節省了 20% 的成本,但從數量來看,B 方案能節省 2000 臺機器,1 臺機器成本預算每年大約 2 萬元,這樣一年下來就能節省 4000 萬元,4000 萬元成本不是小數目,給 100 人的團隊發獎金每人可以發 40 萬元了,這可是算得上天價獎金了。通過一個架構方案的設計,就能輕鬆節約幾千萬元,不但展現了技術的強大力量,也帶來了可觀的收益,對於技術人員來說,最有滿足感的事情莫過於如此了。

當我們設計“高性能”“高可用”的架構時,通用的手段都是增加更多服務器來滿足“高性能”和“高可用”的要求;而低成本正好與此相反,我們需要減少服務器的數量才能達成低成本的目標。因此,低成本本質上是與高性能和高可用衝突的,所以低成本很多時候不會是架構設計的首要目標,而是架構設計的附加約束。也就是說,我們首先設定一個成本目標,當我們根據高性能、高可用的要求設計出方案時,評估一下方案是否能滿足成本目標,如果不行,就需要重新設計架構;如果無論如何都無法設計出滿足成本要求的方案,那就只能找老闆調整成本目標了。

低成本給架構設計帶來的主要複雜度體現在,往往只有“創新”才能達到低成本目標。這裏的“創新”既包括開創一個全新的技術領域(這個要求對絕大部分公司太高),也包括引入新技術,如果沒有找到能夠解決自己問題的新技術,那麼就真的需要自己創造新技術了。

類似的新技術例子很多,我來舉幾個。

  • NoSQL(Memcache、Redis 等)的出現是爲了解決關係型數據庫無法應對高併發訪問帶來的訪問壓力。

  • 全文搜索引擎(Sphinx、Elasticsearch、Solr)的出現是爲了解決關係型數據庫 like 搜索的低效的問題。

  • Hadoop 的出現是爲了解決傳統文件系統無法應對海量數據存儲和計算的問題。

我再來舉幾個業界類似的例子。

  • Facebook 爲了解決 PHP 的低效問題,剛開始的解決方案是 HipHop PHP,可以將 PHP 語言翻譯爲 C++ 語言執行,後來改爲 HHVM,將 PHP 翻譯爲字節碼然後由虛擬機執行,和 Java 的 JVM 類似。

  • 新浪微博將傳統的 Redis/MC + MySQL 方式,擴展爲 Redis/MC + SSD Cache + MySQL 方式,SSD Cache 作爲 L2 緩存使用,既解決了 MC/Redis 成本過高,容量小的問題,也解決了穿透 DB 帶來的數據庫訪問壓力(來源:http://www.infoq.com/cn/articles/weibo-platform-archieture )。

  • Linkedin 爲了處理每天 5 千億的事件,開發了高效的 Kafka 消息系統。

  • 其他類似將 Ruby on Rails 改爲 Java、Lua + redis 改爲 Go 語言實現的例子還有很多。

無論是引入新技術,還是自己創造新技術,都是一件複雜的事情。引入新技術的主要複雜度在於需要去熟悉新技術,並且將新技術與已有技術結合起來;創造新技術的主要複雜度在於需要自己去創造全新的理念和技術,並且新技術跟舊技術相比,需要有質的飛躍。

相比來說,創造新技術複雜度更高,因此一般中小公司基本都是靠引入新技術來達到低成本的目標;而大公司更有可能自己去創造新的技術來達到低成本的目標,因爲大公司纔有足夠的資源、技術和時間去創造新技術。

安全

安全本身是一個龐大而又複雜的技術領域,並且一旦出問題,對業務和企業形象影響非常大。例如:

  • 2016 年雅虎爆出史上最大規模信息泄露事件,逾 5 億用戶資料在 2014 年被竊取。

  • 2016 年 10 月美國遭史上最大規模 DDoS 攻擊,東海岸網站集體癱瘓。

  • 2013 年 10 月,爲全國 4500 多家酒店提供網絡服務的浙江慧達驛站網絡有限公司,因安全漏洞問題,致 2 千萬條入住酒店的客戶信息泄露,由此導致很多敲詐、家庭破裂的後續事件。

正因爲經常能夠看到或者聽到各類安全事件,所以大部分技術人員和架構師,對安全這部分會多一些瞭解和考慮。

從技術的角度來講,安全可以分爲兩類:一類是功能上的安全,一類是架構上的安全。

1. 功能安全

例如,常見的 XSS 攻擊、CSRF 攻擊、SQL 注入、Windows 漏洞、密碼破解等,本質上是因爲系統實現有漏洞,黑客有了可乘之機。黑客會利用各種漏洞潛入系統,這種行爲就像小偷一樣,黑客和小偷的手法都是利用系統或家中不完善的地方潛入,並進行破壞或者盜取。因此形象地說,功能安全其實就是“防小偷”

從實現的角度來看,功能安全更多地是和具體的編碼相關,與架構關係不大。現在很多開發框架都內嵌了常見的安全功能,能夠大大減少安全相關功能的重複開發,但框架只能預防常見的安全漏洞和風險(常見的 XSS 攻擊、CSRF 攻擊、SQL 注入等),無法預知新的安全問題,而且框架本身很多時候也存在漏洞(例如,流行的 Apache Struts2 就多次爆出了調用遠程代碼執行的高危漏洞,給整個互聯網都造成了一定的恐慌)。所以功能安全是一個逐步完善的過程,而且往往都是在問題出現後纔能有針對性的提出解決方案,我們永遠無法預測系統下一個漏洞在哪裏,也不敢說自己的系統肯定沒有任何問題。換句話講,功能安全其實也是一個“攻”與“防”的矛盾,只能在這種攻防大戰中逐步完善,不可能在系統架構設計的時候一勞永逸地解決。

2. 架構安全

如果說功能安全是“防小偷”,那麼架構安全就是“防強盜”。強盜會直接用大錘將門砸開,或者用炸藥將圍牆炸倒;小偷是偷東西,而強盜很多時候就是故意搞破壞,對系統的影響也大得多。因此架構設計時需要特別關注架構安全,尤其是互聯網時代,理論上來說系統部署在互聯網上時,全球任何地方都可以發起攻擊。

傳統的架構安全主要依靠防火牆,防火牆最基本的功能就是隔離網絡,通過將網絡劃分成不同的區域,制定出不同區域之間的訪問控制策略來控制不同信任程度區域間傳送的數據流。例如,下圖是一個典型的銀行系統的安全架構。

從圖中你可以看到,整個系統根據不同的分區部署了多個防火牆來保證系統的安全。

防火牆的功能雖然強大,但性能一般,所以在傳統的銀行和企業應用領域應用較多。但在互聯網領域,防火牆的應用場景並不多。因爲互聯網的業務具有海量用戶訪問和高併發的特點,防火牆的性能不足以支撐;尤其是互聯網領域的 DDoS 攻擊,輕則幾 GB,重則幾十 GB。2016 年知名安全研究人員布萊恩·克萊布斯(Brian Krebs)的安全博客網站遭遇 DDoS 攻擊,攻擊帶寬達 665Gbps,是目前在網絡犯罪領域已知的最大的拒絕服務攻擊。這種規模的攻擊,如果用防火牆來防,則需要部署大量的防火牆,成本會很高。例如,中高端一些的防火牆價格 10 萬元,每秒能抗住大約 25GB 流量,那麼應對這種攻擊就需要將近 30 臺防火牆,成本將近 300 萬元,這還不包括維護成本,而這些防火牆設備在沒有發生攻擊的時候又沒有什麼作用。也就是說,如果花費幾百萬元來買這麼一套設備,有可能幾年都發揮不了任何作用。

就算是公司對錢不在乎,一般也不會堆防火牆來防 DDoS 攻擊,因爲 DDoS 攻擊最大的影響是大量消耗機房的出口總帶寬。不管防火牆處理能力有多強,當出口帶寬被耗盡時,整個業務在用戶看來就是不可用的,因爲用戶的正常請求已經無法到達系統了。防火牆能夠保證內部系統不受衝擊,但用戶也是進不來的。對於用戶來說,業務都已經受到影響了,至於是因爲用戶自己進不去,還是因爲系統出故障,用戶其實根本不會關心。

基於上述原因,互聯網系統的架構安全目前並沒有太好的設計手段來實現,更多地是依靠運營商或者雲服務商強大的帶寬和流量清洗的能力,較少自己來設計和實現。

規模

很多企業級的系統,既沒有高性能要求,也沒有雙中心高可用要求,也不需要什麼擴展性,但往往我們一說到這樣的系統,很多人都會脫口而出:這個系統好複雜!爲什麼這樣說呢?關鍵就在於這樣的系統往往功能特別多,邏輯分支特別多。特別是有的系統,發展時間比較長,不斷地往上面疊加功能,後來的人由於不熟悉整個發展歷史,可能連很多功能的應用場景都不清楚,或者細節根本無法掌握,面對的就是一個黑盒系統,看不懂、改不動、不敢改、修不了,複雜度自然就感覺很高了。

規模帶來複雜度的主要原因就是“量變引起質變”,當數量超過一定的閾值後,複雜度會發生質的變化。常見的規模帶來的複雜度有:

1. 功能越來越多,導致系統複雜度指數級上升

例如,某個系統開始只有 3 大功能,後來不斷增加到 8 大功能,雖然還是同一個系統,但複雜度已經相差很大了,具體相差多大呢?

我以一個簡單的抽象模型來計算一下,假設系統間的功能都是兩兩相關的,系統的複雜度 = 功能數量 + 功能之間的連接數量,通過計算我們可以看出:

  • 3 個功能的系統複雜度 = 3 + 3 = 6

  • 8 個功能的系統複雜度 = 8 + 28 = 36

可以看出,具備 8 個功能的系統的複雜度不是比具備 3 個功能的系統的複雜度多 5,而是多了 30,基本是指數級增長的,主要原因在於隨着系統功能數量增多,功能之間的連接呈指數級增長。下圖形象地展示了功能數量的增多帶來了複雜度。

通過肉眼就可以很直觀地看出,具備 8 個功能的系統複雜度要高得多。

2. 數據越來越多,系統複雜度發生質變

與功能類似,系統數據越來越多時,也會由量變帶來質變,最近幾年火熱的“大數據”就是在這種背景下誕生的。大數據單獨成爲了一個熱門的技術領域,主要原因就是數據太多以後,傳統的數據收集、加工、存儲、分析的手段和工具已經無法適應,必須應用新的技術才能解決。目前的大數據理論基礎是 Google 發表的三篇大數據相關論文,其中 Google File System 是大數據文件存儲的技術理論,Google Bigtable 是列式數據存儲的技術理論,Google MapReduce 是大數據運算的技術理論,這三篇技術論文各自開創了一個新的技術領域。

即使我們的數據沒有達到大數據規模,數據的增長也可能給系統帶來複雜性。最典型的例子莫過於使用關係數據庫存儲數據,我以 MySQL 爲例,MySQL 單表的數據因不同的業務和應用場景會有不同的最優值,但不管怎樣都肯定是有一定的限度的,一般推薦在 5000 萬行左右。如果因爲業務的發展,單表數據達到了 10 億行,就會產生很多問題,例如:

  • 添加索引會很慢,可能需要幾個小時,這幾個小時內數據庫表是無法插入數據的,相當於業務停機了。

  • 修改表結構和添加索引存在類似的問題,耗時可能會很長。

  • 即使有索引,索引的性能也可能會很低,因爲數據量太大。

  • 數據庫備份耗時很長。

  • ……

因此,當 MySQL 單表數據量太大時,我們必須考慮將單表拆分爲多表,這個拆分過程也會引入更多複雜性,例如:

  • 拆表的規則是什麼?

以用戶表爲例:是按照用戶 id 拆分表,還是按照用戶註冊時間拆表?

  • 拆完表後查詢如何處理?

以用戶表爲例:假設按照用戶 id 拆表,當業務需要查詢學歷爲“本科”以上的用戶時,要去很多表查詢才能得到最終結果,怎麼保證性能?

還有很多類似的問題這裏不一一展開,後面的專欄還會討論。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章