從0開始學架構(五)

 

此係列文章爲極客時間0開始學架構學習後感悟總結,雖然隔了一段時間了,那麼就再看一遍而且進行感悟昇華,排版格式上有問題,後期再複習時也會進行更新前端

 

一. 架構師應該如何判斷技術演進的方向?程序員

互聯網的出現不但改變了普通人的生活方式,同時也促進了技術圈的快速發展和開放。在開源和分享兩股力量的推進下,最近 10 多年的技術發展能夠說是應接不暇,你方唱罷我登場,大的方面有大數據、雲計算、人工智能等,細分的領域有 NoSQL、Node.js、Docker 容器化等。各個大公司也樂於將本身的技術分享出來,以此來提高本身的技術影響力,打造圈內技術口碑,從而造成強大的人才吸引力,典型的有,Google 的大數據論文、淘寶的全鏈路壓測、微信的紅包高併發技術等。正則表達式

對於技術人員來講,技術的快速發展固然是一件大好事,畢竟這意味着技術百寶箱中又多了更多的可選工具,同時也能夠經過學習業界先進的技術來提高本身的技術實力。但對於架構師來講,除了這些好處,卻也多了「甜蜜的煩惱」:面對層出不窮的新技術,咱們應該採起什麼樣的策略?數據庫

架構師可能常常會面臨下面這些誘惑或者挑戰:後端

  1. 如今 Docker 虛擬化技術很流行,咱們要不要引進,引入 Docker 後能夠每一年節省幾十萬元的硬件成本呢?
  2. 競爭對手用了阿里的雲計算技術,據說由於上了雲,業務增加了好幾倍呢,咱們是否也應該儘快上雲啊?
  3. 咱們的技術和業界頂尖公司(例如,淘寶、微信)差距很大,應該投入人力和時間追上去,否則招聘的時候沒有技術影響力!
  4. 公司的技術發展示在已經比較成熟了,程序員都以爲在公司學不到東西,咱們能夠嘗試引入 Golang 來給你們一個學習新技術的機會。

相似的問題還有不少,本質上均可以概括總結爲一個問題:架構師應該如何判斷技術演進的方向?關於這個問題的答案,基本上能夠分爲幾個典型的派別:設計模式

1.潮流派瀏覽器

潮流派的典型特徵就是對於新技術特別熱衷,緊跟技術潮流,當有新的技術出現時,迫切想將新的技術應用到本身的產品中。緩存

2.保守派安全

保守派的典型特徵和潮流派正好相反,對於新技術抱有很強的戒備心,穩定壓倒一切,已經掌握了某種技術,就一直用這種技術打天下。就像有句俗語說的,「若是你手裏有一把錘子,那麼全部的問題都變成了釘子」,保守派就是拿着一把錘子解決全部的問題。服務器

3.跟風派

跟風派與潮流派不一樣,這裏的跟風派不是指跟着技術潮流,而是指跟着競爭對手的步子走。

下面咱們來看一下不一樣的派別可能存在的問題。

1.潮流派

首先,新技術須要時間成熟,若是剛出來就用,此時新技術還不怎麼成熟,實際應用中極可能遇到各類「坑」,本身成了實驗小白鼠。其次,新技術須要學習,須要花費必定的時間去掌握,這個也是較大的成本;若是等到掌握了技術後又發現不適用,則是一種較大的人力浪費。

2.保守派

保守派的主要問題是不能享受新技術帶來的收益,由於新技術不少都是爲了解決之前技術存在的固有缺陷。就像汽車取代馬車同樣,不是量變而是質變,帶來的收益不是線性變化的,而是爆發式變化的。若是無視技術的發展,形象一點說就是有了拖拉機,你還恰恰要用牛車。

3.跟風派

可能不少人都會認爲,跟風派與「潮流派」和「保守派」相比,是最有效的策略,既不會承擔「潮流派」的風險,也不會遭受「保守派」的損失,花費的資源也少,簡直就是一舉多得。看起來很美妙,但跟風派最大的問題在於若是沒有風可跟的時候怎麼辦。若是你是領頭羊怎麼辦,其餘人都準備跟你的風呢?另一種狀況就是競爭對手的這些信息並不那麼容易獲取,即便獲取到了一些信息,大部分也是不全面的,一不當心可能就變成邯鄲學步了。即便有風可跟,其實也存在問題。有時候適用於競爭對手的技術,並不必定適用於本身,盲目模仿可能帶來相反的效果。

 

既然潮流派、保守派、跟風派都存在這樣或者那樣的問題,那架構師究竟如何判斷技術演進的方向呢?

這個問題之因此讓人困惑,關鍵的緣由仍是在於無論是潮流派、保守派,仍是跟風派,都是站在技術自己的角度來考慮問題的,正所謂「不識廬山真面,只緣身在此山中」。所以,要想看到「廬山真面目」,只有跳出技術的範疇,從一個更廣更高的角度來考慮這個問題,這個角度就是企業的業務發展。

不管是表明新興技術的互聯網企業,仍是表明傳統技術的製造業;不管是通訊行業,仍是金融行業的發展,歸根到底就是業務的發展。而影響一個企業業務的發展主要有 3 個因素:市場、技術、管理,這三者構成支撐業務發展的鐵三角,任何一個因素的不足,均可能致使企業的業務停滯不前。

在這個鐵三角中,業務處於三角形的中心,絕不誇張地說,市場、技術、管理都是爲了支撐企業業務的發展。在專欄裏,我主要探討「技術」和「業務」之間的關係和互相如何影響。

咱們能夠簡單地將企業的業務分爲兩類:一類是產品類,一類是服務類。

產品類:360 的殺毒軟件、蘋果的 iPhone、UC 的瀏覽器等都屬於這個範疇,這些產品本質上和傳統的製造業產品相似,都是具有了某種「功能」,單個用戶經過購買或者無償使用這些產品來完成本身相關的某些任務,用戶對這些產品是獨佔的。

服務類:百度的搜索、淘寶的購物、新浪的微博、騰訊的 IM 等都屬於這個範疇,大量用戶使用這些服務來完成須要與其餘人交互的任務,單個用戶「使用」但不「獨佔」某個服務。事實上,服務的用戶越多,服務的價值就越大。服務類的業務符合互聯網的特徵和本質:「互聯」+「網」。

對於產品類業務,答案看起來很明顯:技術創新推進業務發展!

對於「服務」類的業務,答案和產品類業務正好相反:業務發展推進技術的發展!

爲何會出現截然相反的差異呢?主要緣由是用戶選擇服務的根本驅動力與選擇產品不一樣。用戶選擇一個產品的根本驅動力是其「功能」,而用戶選擇一個服務的根本驅動力不是功能,而是「規模」。

例如,選擇 UC 瀏覽器仍是選擇 QQ 瀏覽器,更多的人是根據我的喜愛和體驗來決定的;而選擇微信仍是 Whatsapp,就不是根據它們之間的功能差別來選擇的,而是根據其規模來選擇的,就像我更喜歡 Whatsapp 的簡潔,但個人朋友和周邊的人都用微信,那我也不得不用微信。

當「規模」成爲業務的決定因素後,服務模式的創新就成爲了業務發展的核心驅動力,而產品只是爲了完成服務而提供給用戶使用的一個載體。以淘寶爲例,淘寶提供的「網絡購物」是一種新的服務,這種業務與傳統的到實體店購物是徹底不一樣的,而爲了完成這種業務,須要「淘寶網」「支付寶」「一淘」和「菜鳥物流」等多個產品。隨便一個軟件公司,若是隻是模仿開發出相似的產品,只要願意投入,半年時間就能夠將這些產品所有開發出來。可是這樣作並無意義,由於用戶選擇的是淘寶的整套網絡購物服務,而且這個服務已經具有了必定的規模,其餘公司不具有這種同等規模服務的能力。即便開發出徹底同樣的產品,用戶也不會由於產品功能更增強大而選擇新的相似產品。

以微信爲例,一樣能夠得出相似結論。假如咱們進行技術創新,開發一個耗電量只有微信的 1/10,用戶體驗比微信好 10 倍的產品,你以爲如今的微信用戶都會拋棄微信,而轉投咱們的這個產品嗎?我相信絕大部分人都不會,由於微信不是一個互聯網產品,而是一個互聯網服務,你一我的換到其餘類微信類產品是沒有意義的。

所以,服務類的業務發展路徑是這樣的:提出一種創新的服務模式→吸引了一批用戶→業務開始發展→吸引了更多用戶→服務模式不斷完善和創新→吸引愈來愈多的用戶,如此循環往復。在這個發展路徑中,技術並無成爲業務發展的驅動力,反過來因爲用戶規模的不斷擴展,業務的不斷創新和改進,對技術會提出愈來愈高的要求,所以是業務驅動了技術發展。

其實回到產品類業務,若是咱們將觀察的時間拉長來看,即便是產品類業務,在技術創新開創了一個新的業務後,後續的業務發展也會反向推進技術的發展。例如,第一代 iPhone 缺乏對 3G 的支持,且只能經過 Web 發佈應用程序,第二代 iPhone 纔開始支持 3G,而且內置 GPS;UC 瀏覽器隨着功能愈來愈強大,原有的技術沒法知足業務發展的需求,瀏覽器的架構須要進行更新,前後通過 UC 瀏覽器 7.0 版本、8.0 版本、9.0 版本等幾個技術差別很大的版本。

綜合這些分析,除非是開創新的技術可以推進或者創造一種新的業務,其餘狀況下,都是業務的發展推進了技術的發展。

 

明確了技術發展主要的驅動力是業務發展後,咱們來看看業務發展到底是如何驅動技術發展的。

業務模式千差萬別,有互聯網的業務(淘寶、微信等),有金融的業務(中國平安、招商銀行等),有傳統企業的業務(各色 ERP 對應的業務)等,但不管什麼模式的業務,若是業務的發展須要技術同步發展進行支撐,無一例外是由於業務「複雜度」的上升,致使原有的技術沒法支撐。

按照前面所介紹的複雜度分類,複雜度要麼來源於功能不斷疊加,要麼來源於規模擴大,從而對性能和可用性有了更高的要求。既然如此,判斷究竟是什麼複雜度發生了變化就顯得相當重要了。是任什麼時候候都要同時考慮功能複雜度和規模複雜度嗎?仍是有時候考慮功能複雜度,有時候考慮規模複雜度?仍是隨機挑一個複雜度的問題解決就能夠了?

因此,對於架構師來講,判斷業務當前和接下來一段時間的主要複雜度是什麼就很是關鍵。判斷不許確就會致使投入大量的人力和時間作了對業務沒有做用的事情,判斷準確就可以作到技術推進業務更加快速發展。那架構師具體應該按照什麼標準來判斷呢?

答案就是基於業務發展階段進行判斷,這也是爲何架構師必須具有業務理解能力的緣由。不一樣的行業業務發展路徑、軌跡、模式不同,架構師必須可以基於行業發展和企業自身狀況作出準確判斷。

假設你是一個銀行 IT 系統的架構師:

90 年代主要的業務複雜度可能就是銀行業務範圍逐漸擴大,功能愈來愈複雜,致使內部系統數量愈來愈多,單個系統功能愈來愈複雜。

2004 年之後主要的複雜度就是銀行業務從櫃檯轉向網上銀行,網上銀行的穩定性、安全性、易用性是主要的複雜度,這些複雜度主要由銀行 IT 系統本身解決。

2009 年之後主要的複雜度又變化爲移動支付複雜度,尤爲是「雙 11」這種海量支付請求的狀況下,高性能、穩定性、安全性是主要的複雜度,而這些複雜度須要銀行和移動支付服務商(支付寶、微信)等一塊兒解決。

 

而若是你是淘寶這種互聯網業務的架構師,業務發展又會是另一種模式:

2003 年,業務剛剛創立,主要的複雜度體現爲如何才能快速開發各類需求,淘寶團隊採起的是買了一個 PHP 寫的系統來改。

2004 年,上線後業務發展迅速,用戶請求數量大大增長,主要的複雜度體現爲如何才能保證系統的性能,淘寶的團隊採起的是用 Oracle 取代 MySQL。

用戶數量再次增長,主要的複雜度仍是性能和穩定性,淘寶的團隊採起的是 Java 替換 PHP。

2008 年,淘寶的商品數量在 1 億以上,PV2.5 億以上,主要的複雜度又變成了系統內部耦合,交易和商品耦合在一塊兒,支付的時候又和支付寶強耦合,整個系統邏輯複雜,功能之間跳來跳去,用戶體驗也很差。淘寶的團隊採起的是系統解耦,將交易中心、類目管理、用戶中心從原來大一統的系統裏面拆分出來。

 

二. 互聯網技術演進的模式

互聯網業務千差萬別,但因爲它們具備「規模決定一切」的相同點,其發展路徑也基本上是一致的。互聯網業務發展通常分爲幾個時期:初創期、發展期、競爭期、成熟期。

不一樣時期的差異主要體如今兩個方面:複雜性、用戶規模

 

業務複雜性

互聯網業務發展第一個主要方向就是「業務愈來愈複雜」,咱們來看看不一樣時期業務的複雜性的表現。

1.初創期

互聯網業務剛開始通常都是一個創新的業務點,這個業務點的重點不在於「完善」,而在於「創新」,只有創新才能吸引用戶;並且由於其「新」的特色,其實一開始是不可能很完善的。只有隨着愈來愈多的用戶的使用,經過快速迭代試錯、用戶的反饋等手段,不斷地在實踐中去完善,才能繼續創新。

初創期的業務對技術就一個要求:「快」,但這個時候卻又是創業團隊最弱小的時期,可能就幾個技術人員,因此這個時候十八般武藝都須要用上:能買就買,有開源的就用開源的。

初版的淘寶

 

 

初版的 QQ

 

 

能夠看到最開始的淘寶和 QQ 與如今相比,幾乎看不出是同一個業務了。

2.發展期

當業務推出後通過市場驗證若是是可行的,則吸引的用戶就會愈來愈多,此時原來不完善的業務就進入了一個快速發展的時期。業務快速發展時期的主要目的是將原來不完善的業務逐漸完善,所以會有愈來愈多的新功能不斷地加入到系統中。對於絕大部分技術團隊來講,這個階段技術的核心工做是快速地實現各類需求,只有這樣才能知足業務發展的須要。如何作到「快」,通常會經歷下面幾個階段。

  1. 堆功能期
  2. 優化期
  3. 架構期

3.競爭期

當業務繼續發展,已經造成必定規模後,必定會有競爭對手開始加入行業來競爭,畢竟誰都想分一塊蛋糕,甚至有可能一不當心還會成爲下一個 BAT。當競爭對手加入後,你們互相學習和模仿,業務更加完善,也不斷有新的業務創新出來,並且因爲競爭的壓力,對技術的要求是更上一層樓了。

新業務的創新給技術帶來的典型壓力就是新的系統會更多,同時,原有的系統也會拆得愈來愈多。二者協力的一個典型後果就是系統數量在原來的基礎上又增長了不少。架構拆分後帶來的美好時光又開始慢慢消逝,技術工做又開始進入了「慢」的狀態,這又是怎麼回事呢?

         原來系統數量愈來愈多,到了一個臨界點後就產生了質變,即系統數量的量變帶來了技術工做的質變。主要體如今下面幾個方面:

  1. 重複造輪子:系統愈來愈多,各系統類似的工做愈來愈多。例如,每一個系統都有存儲,都要用緩存,都要用數據庫。新建一個系統,這些工做又要都作一遍,即便其餘系統已經作過了一遍,這樣怎麼能快得起來?

         2.系統交互一團亂麻:系統愈來愈多,各系統的交互關係變成了網狀。系統間的交互數量和系統的數量成平方比的關係。例如,4 個系統的交互路徑是 6 個,10 個系統的交互路徑是 45 個。每實現一個業務需求,都須要幾個甚至十幾個系統一塊兒改,而後互相調用來調用去,聯調成了研發人員的災難、聯測成了測試人員的災難、部署成了運維的災難。

         針對這個時期業務變化帶來的問題,技術工做主要的解決手段有:

  1.平臺化:目的在於解決「重複造輪子」的問題。

  2.服務化:目的在於解決「系統交互」的問題,常見的作法是經過消息隊列來完成系統間的異步通知,經過服務框架來完成系統間的同步調用。

4.成熟期

當企業熬過競爭期,成爲了行業的領頭羊,或者整個行業總體上已經處於比較成熟的階段,市場地位已經比較牢固後,業務創新的機會已經不大,競爭壓力也沒有那麼激烈,此時求快求新已經沒有很大空間,業務上開始轉向爲「求精」:咱們的響應時間是否比競爭對手快?咱們的用戶體驗是否比競爭對手好?咱們的成本是否比競爭對手低……

此時技術上其實也基本進入了成熟期,該拆的也拆了,該平臺化的也平臺化了,技術上能作的大動做其實也很少了,更多的是進行優化。但有時候也會爲了知足某個優化,系統作很大的改變。例如,爲了將用戶響應時間從 200ms 下降到 50ms,可能就須要從不少方面進行優化:CDN、數據庫、網絡等。這個時候的技術優化沒有固定的套路,只能按照競爭的要求,找出本身的弱項,而後逐項優化。在逐項優化時,能夠採起以前各個時期採用的手段。

 

用戶規模

互聯網業務的發展第二個主要方向就是「用戶量愈來愈大」。互聯網業務的發展會經歷「初創期、發展期、競爭期、成熟期」幾個階段,不一樣階段典型的差異就是用戶量的差異,用戶量隨着業務的發展而愈來愈大。

用戶量增大對技術的影響主要體如今兩個方面:性能要求愈來愈高、可用性要求愈來愈高。

1.性能

用戶量增大給技術帶來的第一個挑戰就是性能要求愈來愈高。以互聯網企業最經常使用的 MySQL 爲例,再簡單的查詢,再高的硬件配置,單臺 MySQL 機器支撐的 TPS 和 QPS 最高也就是萬級,低的多是幾千,高的也不過幾萬。當用戶量增加後,必然要考慮使用多臺 MySQL,從一臺 MySQL 到多臺 MySQL 不是簡單的數量的增長,而是本質上的改變,即原來集中式的存儲變爲了分佈式的存儲。

稍微有經驗的工程師都會知道,分佈式將會帶來複雜度的大幅度上升。以 MySQL 爲例,分佈式 MySQL 要考慮分庫分表、讀寫分離、複製、同步等不少問題。

2.可用性

用戶量增大對技術帶來的第二個挑戰就是可用性要求愈來愈高。當你有 1 萬個用戶的時候,宕機 1 小時可能也沒有很大的影響;但當你有了 100 萬用戶的時候,宕機 10 分鐘,投訴電話估計就被打爆了,這些用戶再到朋友圈抱怨一下你的系統有多爛,極可能你就不會再有機會發展下一個 100 萬用戶了。

除了口碑的影響,可用性對收入的影響也會隨着用戶量增大而增大。1 萬用戶宕機 1 小時,你可能才損失了幾千元;100 萬用戶宕機 10 分鐘,損失可能就是幾十萬元了。

 

量變到質變

 

應對業務質變帶來的技術壓力,不一樣時期有不一樣的處理方式,但無論什麼樣的方式,其核心目標都是爲了知足業務「快」的要求,當發現你的業務快不起來的時候,其實就是技術的水平已經跟不上業務發展的須要了,技術變革和發展的時候就到了。更好的作法是在問題尚未真正暴露出來就可以根據趨勢預測下一個轉折點,提早作好技術上的準備,這對技術人員的要求是很是高的。

 

三. 互聯網架構模板:「存儲層」技術

不少人對於 BAT 的技術有一種莫名的崇拜感,以爲只有天才才能作出這樣的系統,但通過前面對架構的本質、架構的設計原則、架構的設計模式、架構演進等多方位的探討和闡述,你能夠看到,其實並無什麼神祕的力量和魔力融合在技術裏面,而是業務的不斷髮展推進了技術的發展,這樣一步一個腳印,持續幾年甚至十幾年的發展,才能達到當前技術複雜度和先進性。

拋開 BAT 各自差別很大的業務,站在技術的角度來看,其實 BAT 的技術架構基本是同樣的。再將視角放大,你會發現整個互聯網行業的技術發展,最後都是異曲同工。

若是你正處於一個創業公司,或者正在爲成爲另外一個 BAT 拼搏,那麼深刻理解這種技術模式(或者叫技術結構、技術架構),對於本身和公司的發展都大有裨益。

互聯網的標準技術架構以下圖所示,這張圖基本上涵蓋了互聯網技術公司的大部分技術點,不一樣的公司只是在具體的技術實現上稍有差別,但不會跳出這個框架的範疇。

咱們首先來聊聊互聯網架構模板的「存儲層」技術

SQL

SQL 即咱們一般所說的關係數據。前幾年 NoSQL 火了一陣子,不少人都理解爲 NoSQL 是徹底拋棄關係數據,所有采用非關係型數據。但通過幾年的試驗後,你們發現關係數據不可能徹底被拋棄,NoSQL 不是 No SQL,而是 Not Only SQL,即 NoSQL 是 SQL 的補充。

因此互聯網行業也必須依賴關係數據,考慮到 Oracle 太貴,還須要專人維護,通常狀況下互聯網行業都是用 MySQL、PostgreSQL 這類開源數據庫。這類數據庫的特色是開源免費,拿來就用;但缺點是性能相比商業數據庫要差一些。隨着互聯網業務的發展,性能要求愈來愈高,必然要面對一個問題:將數據拆分到多個數據庫實例才能知足業務的性能需求(其實 Oracle 也同樣,只是時間遲早的問題)。

數據庫拆分知足了性能的要求,但帶來了複雜度的問題:數據如何拆分、數據如何組合?這個複雜度的問題解決起來並不容易,若是每一個業務都去實現一遍,重複造輪子將致使投入浪費、效率下降,業務開發想快都快不起來。

因此互聯網公司流行的作法是業務發展到必定階段後,就會將這部分功能獨立成中間件,例如百度的 DBProxy、淘寶的 TDDL。不過這部分的技術要求很高,將分庫分表作到自動化和平臺化,不是一件容易的事情,因此通常是規模很大的公司纔會本身作。中小公司建議使用開源方案,例如 MySQL 官方推薦的 MySQL Router、360 開源的數據庫中間件 Atlas。

假如公司業務繼續發展,規模繼續擴大,SQL 服務器愈來愈多,若是每一個業務都基於統一的數據庫中間件獨立部署本身的 SQL 集羣,就會致使新的複雜度問題,具體表如今:

  1. 數據庫資源使用率不高,比較浪費。
  2. 各 SQL 集羣分開維護,投入的維護成本愈來愈高。

所以,實力雄厚的大公司此時通常都會在 SQL 集羣上構建 SQL 存儲平臺,以對業務透明的形式提供資源分配、數據備份、遷移、容災、讀寫分離、分庫分表等一系列服務,例如淘寶的 UMP(Unified MySQL Platform)系統。

 

NOSQL

首先 NoSQL 在數據結構上與傳統的 SQL 的不一樣,例如典型的 Memcache 的 key-value 結構、Redis 的複雜數據結構、MongoDB 的文檔數據結構;其次,NoSQL 無一例外地都會將性能做爲本身的一大賣點。NoSQL 的這兩個特色很好地彌補了關係數據庫的不足,所以在互聯網行業 NoSQL 的應用基本上是基礎要求。

因爲 NoSQL 方案通常本身自己就提供集羣的功能,例如 Memcache 的一致性 Hash 集羣、Redis 3.0 的集羣,所以 NoSQL 在剛開始應用時很方便,不像 SQL 分庫分表那麼複雜。通常公司也不會在開始時就考慮將 NoSQL 包裝成存儲平臺,但若是公司發展很快,例如 Memcache 的節點有上千甚至幾千時,NoSQL 存儲平臺就頗有意義了。首先是存儲平臺經過集中管理可以大大提高運維效率;其次是存儲平臺能夠大大提高資源利用效率,2000 臺機器,若是利用率能提高 10%,就能夠減小 200 臺機器,一年幾十萬元就節省出來了。

因此,NoSQL 發展到必定規模後,一般都會在 NoSQL 集羣的基礎之上再實現統一存儲平臺,統一存儲平臺主要實現這幾個功能:

  1. 資源動態按需動態分配:例如同一臺 Memcache 服務器,能夠根據內存利用率,分配給多個業務使用。
  2. 資源自動化管理:例如新業務只須要申請多少 Memcache 緩存空間就能夠了,無需關注具體是哪些 Memcache 服務器在爲本身提供服務。
  3. 故障自動化處理:例如某臺 Memcache 服務器掛掉後,有另一臺備份 Memcache 服務器能馬上接管緩存請求,不會致使丟失不少緩存數據。

固然要發展到這個階段,通常也是大公司纔會這麼作,簡單來講就是若是隻有幾十臺 NoSQL 服務器,作存儲平臺收益不大;但若是有幾千臺 NoSQL 服務器,NoSQL 存儲平臺就可以產生很大的收益。

 

小文件存儲

除了關係型的業務數據,互聯網行業還有不少用於展現的數據。例如,淘寶的商品圖片、商品描述;Facebook 的用戶圖片;新浪微博的一條微博內容等。這些數據具備三個典型特徵:一是數據小,通常在 1MB 如下;二是數量巨大,Facebook 在 2013 年天天上傳的照片就達到了 3.5 億張;三是訪問量巨大,Facebook 天天的訪問量超過 10 億。

因爲互聯網行業基本上每一個業務都會有大量的小數據,若是每一個業務都本身去考慮如何設計海量存儲和海量訪問,效率天然會低,重複造輪子也會投入浪費,因此天然而然就要將小文件存儲作成統一的和業務無關的平臺。

和 SQL 和 NoSQL 不一樣的是,小文件存儲不必定須要公司或者業務規模很大,基本上認爲業務在起步階段就能夠考慮作小文件統一存儲。得益於開源運動的發展和最近幾年大數據的火爆,在開源方案的基礎上封裝一個小文件存儲平臺並非太難的事情。例如,HBase、Hadoop、Hypertable、FastDFS 等均可以做爲小文件存儲的底層平臺,只須要將這些開源方案再包裝一下基本上就能夠用了。

典型的小文件存儲有:淘寶的 TFS、京東 JFS、Facebook 的 Haystack。

 

大文件存儲

互聯網行業的大文件主要分爲兩類:一類是業務上的大數據,例如 Youtube 的視頻、電影網站的電影;另外一類是海量的日誌數據,例如各類訪問日誌、操做日誌、用戶軌跡日誌等。和小文件的特色正好相反,大文件的數量沒有小文件那麼多,但每一個文件都很大,幾百 MB、幾個 GB 都是常見的,幾十 GB、幾 TB 也是有可能的,所以在存儲上和小文件有較大差異,不能直接將小文件存儲系統拿來存儲大文件。

說到大文件,特別要提到 Google 和 Yahoo,Google 的 3 篇大數據論文(Bigtable/Map- Reduce/GFS)開啓了一個大數據的時代,而 Yahoo 開源的 Hadoop 系列(HDFS、HBase 等),基本上壟斷了開源界的大數據處理。固然,江山代有才人出,長江後浪推前浪,Hadoop 後又有更多優秀的開源方案被貢獻出來,如今隨便走到大街上拉住一個程序員,若是他不知道大數據,那基本上能夠肯定是「火星程序員」。

對照 Google 的論文構建一套完整的大數據處理方案的難度和成本實在過高,並且開源方案如今也很成熟了,因此大數據存儲和處理這塊反而是最簡單的,由於你沒有太多選擇,只能用這幾個流行的開源方案,例如,Hadoop、HBase、Storm、Hive 等。實力雄厚一些的大公司會基於這些開源方案,結合本身的業務特色,封裝成大數據平臺,例如淘寶的雲梯系統、騰訊的 TDW 系統。

 

四. 互聯網架構模板:「開發層」和「服務層」技術

開發層技術

1.框架

若是每一個小組用不一樣的開發框架和技術,則會帶來不少問題,典型的問題有:

  a)         技術人員之間沒有共同的技術語言,交流合做少。

  b)         每類技術都須要投入大量的人力和資源並熟練精通。

  c)         不一樣團隊之間人員沒法快速流動,人力資源不能高效的利用。

因此,互聯網公司都會指定一個大的技術方向,而後使用統一的開發框架。例如,Java 相關的開發框架 SSH、SpringMVC、Play,Ruby 的 Ruby on Rails,PHP 的 ThinkPHP,Python 的 Django 等。使用統一的開發框架可以解決上面提到的各類問題,大大提高組織和團隊的開發效率。

對於框架的選擇,有一個總的原則:優選成熟的框架,避免盲目追逐新技術!

首先,成熟的框架資料文檔齊備,各類坑基本上都有人踩過了,遇到問題很容易經過搜索來解決。

其次,成熟的框架受衆更廣,招聘時更加容易招到合適的人才。

第三,成熟的框架更加穩定,不會出現大的變更,適合長期發展。

2.Web服務器

開發框架只是負責完成業務功能的開發,真正可以運行起來給用戶提供服務,還須要服務器配合。

獨立開發一個成熟的 Web 服務器,成本很是高,何況業界又有那麼多成熟的開源 Web 服務器,因此互聯網行業基本上都是「拿來主義」,挑選一個流行的開源服務器便可。大一點的公司,可能會在開源服務器的基礎上,結合本身的業務特色作二次開發,例如淘寶的 Tengine,但通常公司基本上只須要將開源服務器摸透,優化一下參數,調整一下配置就差很少了。

選擇一個服務器主要和開發語言相關,例如,Java 的有 Tomcat、JBoss、Resin 等,PHP/Python 的用 Nginx,固然最保險的就是用 Apache 了,什麼語言都支持。

你可能會擔憂 Apache 的性能之類的問題,其實不用過早擔憂這個,等到業務真的發展到 Apache 撐不住的時候再考慮切換也不遲,那時候你有的是錢,有的是人,有的是時間。

3.容器

容器是最近幾年纔開始火起來的,其中以 Docker 爲表明,在 BAT 級別的公司已經有較多的應用。

傳統的虛擬化技術是虛擬機,解決了跨平臺的問題,但因爲虛擬機太龐大,啓動又慢,運行時太佔資源,在互聯網行業並無大規模應用;而 Docker 的容器技術,雖然沒有跨平臺,但啓動快,幾乎不佔資源,推出後馬上就火起來了,預計 Docker 類的容器技術將是技術發展的主流方向。

千萬不要覺得 Docker 只是一個虛擬化或者容器技術,它將在很大程度上改變目前的技術形勢:

  1. 運維方式會發生革命性的變化:Docker 啓動快,幾乎不佔資源,隨時啓動和中止,基於 Docker 打造自動化運維、智能化運維將成爲主流方式。
  2. 設計模式會發生本質上的變化:啓動一個新的容器實例代價如此低,將鼓勵設計思路朝「微服務」的方向發展。

例如,一個傳統的網站包括登陸註冊、頁面訪問、搜索等功能,沒有用容器的狀況下,除非有特別大的訪問量,不然這些功能開始時都是集成在一個系統裏面的;有了容器技術後,一開始就能夠將這些功能按照服務的方式設計,避免後續訪問量增大時又要重構系統。

 

服務層技術

互聯網業務的不斷髮展帶來了複雜度的不斷提高,業務系統也愈來愈多,系統間相互依賴程度加深。好比說爲了完成 A 業務系統,可能須要 B、C、D、E 等十幾個其餘系統進行合做。從數學的角度進行評估,能夠發現系統間的依賴是呈指數級增加的:3 個系統相互關聯的路徑爲 3 條,6 個系統相互關聯的路徑爲 15 條。

服務層的主要目標其實就是爲了下降系統間相互關聯的複雜度。

1.配置中心

故名思議,配置中心就是集中管理各個系統的配置。

當系統數量很少的時候,通常是各系統本身管理本身的配置,但系統數量多了之後,這樣的處理方式會有問題:

  a)       某個功能上線時,須要多個系統配合一塊兒上線,分散配置時,配置檢查、溝通協調須要耗費較多時間。

  b)       處理線上問題時,須要多個系統配合查詢相關信息,分散配置時,操做效率很低,溝通協調也須要耗費較多時間。

  c)       各系統本身管理配置時,通常是經過文本編輯的方式修改的,沒有自動的校驗機制,容易配置錯誤,並且很難發現。

例如,我曾經遇到將 IP 地址的數字 0 誤敲成了鍵盤的字母 O,肉眼很是難發現,但程序檢查其實就很容易。

實現配置中心主要就是爲了解決上面這些問題,將配置中心作成通用的系統的好處有:

  a)       集中配置多個系統,操做效率高。

  b)       全部配置都在一個集中的地方,檢查方便,協做效率高。

  c)       配置中心能夠實現程序化的規則檢查,避免常見的錯誤。好比說檢查最小值、最大值、是否 IP 地址、是否 URL 地址,均可以用正則表達式完成。

  d)       配置中心至關於備份了系統的配置,當某些狀況下須要搭建新的環境時,可以快速搭建環境和恢復業務。

整機磁盤壞掉、機器主板壞掉……遇到這些不可恢復的故障時,基本上只能從新搭建新的環境。程序包確定是已經有的,加上配置中心的配置,可以很快搭建新的運行環境,恢復業務。不然幾十個配置文件從新一個個去 Vim 中修改,耗時很長,還很容易出錯。

下面是配置中心簡單的設計,其中經過「系統標識 + host + port」來標識惟一一個系統運行實例是常見的設計方法。

 

2.服務中心

當系統數量很少的時候,系統間的調用通常都是直接經過配置文件記錄在各系統內部的,但當系統數量多了之後,這種方式就存在問題了。

好比說總共有 10 個系統依賴 A 系統的 X 接口,A 系統實現了一個新接口 Y,可以更好地提供原有 X 接口的功能,若是要讓已有的 10 個系統都切換到 Y 接口,則這 10 個系統的幾十上百臺機器的配置都要修改,而後重啓,可想而知這個效率是很低的。

除此之外,若是 A 系統總共有 20 臺機器,如今其中 5 臺出故障了,其餘系統若是是經過域名訪問 A 系統,則域名緩存失效前,仍是可能訪問到這 5 臺故障機器的;若是其餘系統經過 IP 訪問 A 系統,那麼 A 系統每次增長或者刪除機器,其餘全部 10 個系統的幾十上百臺機器都要同步修改,這樣的協調工做量也是很是大的。

服務中心就是爲了解決上面提到的跨系統依賴的「配置」和「調度」問題。

服務中心的實現通常來講有兩種方式:服務名字系統和服務總線系統。

服務名字系統(Service Name System)

看到這個翻譯,相信你會馬上聯想到 DNS,即 Domain Name System。沒錯,二者的性質是基本相似的。

DNS 的做用將域名解析爲 IP 地址,主要緣由是咱們記不住太多的數字 IP,域名就容易記住。服務名字系統是爲了將 Service 名稱解析爲「host + port + 接口名稱」,可是和 DNS 同樣,真正發起請求的仍是請求方。

 

 

服務總線系統(Service Bus System)

看到這個翻譯,相信你可能馬上聯想到計算機的總線。沒錯,二者的本質也是基本相似的。

相比服務名字系統,服務總線系統更進一步了:由總線系統完成調用,服務請求方都不須要直接和服務提供方交互了。

 

 

「服務名字系統」和「服務總線系統」簡單對好比下表所示。

 

 

3.消息隊列

互聯網業務的一個特色是「快」,這就要求不少業務處理採用異步的方式。例如,大 V 發佈一條微博後,系統須要發消息給關注的用戶,咱們不可能等到全部消息都發送給關注用戶後再告訴大 V 說微博發佈成功了,只能先讓大 V 發佈微博,而後再發消息給關注用戶。

傳統的異步通知方式是由消息生產者直接調用消息消費者提供的接口進行通知的,但當業務變得龐大,子系統數量增多時,這樣作會致使系統間交互很是複雜和難以管理,由於系統間互相依賴和調用,整個系統的結構就像一張蜘蛛網,以下圖所示。

        

 

         消息隊列就是爲了實現這種跨系統異步通知的中間件系統。消息隊列既能夠「一對一」通知,也能夠「一對多」廣播。以微博爲例,能夠清晰地看到異步通知的實現和做用,以下圖所示。

        

 

         對比前面的蜘蛛網架構,能夠清晰地看出引入消息隊列系統後的效果:

  a)       總體結構從網狀結構變爲線性結構,結構清晰。

  b)       消息生產和消息消費解耦,實現簡單。

  c)       增長新的消息消費者,消息生產者徹底不須要任何改動,擴展方便。

  d)       消息隊列系統能夠作高可用、高性能,避免各業務子系統各自獨立作一套,減輕工做量。

  e)       業務子系統只須要聚焦業務便可,實現簡單。

消息隊列系統基本功能的實現比較簡單,但要作到高性能、高可用、消息時序性、消息事務性則比較難。業界已經有不少成熟的開源實現方案,若是要求不高,基本上拿來用便可,例如,RocketMQ、Kafka、ActiveMQ 等。但若是業務對消息的可靠性、時序、事務性要求較高時,則要深刻研究這些開源方案,不然很容易踩坑。

開源的用起來方便,但要改就很麻煩了。因爲其相對比較簡單,不少公司也會花費人力和時間重複造一個輪子,這樣也有好處,由於能夠根據本身的業務特色作快速的適配開發。

 

五. 互聯網架構模板:「網絡層」技術

 

負載均衡

顧名思議,負載均衡就是將請求均衡地分配到多個系統上。使用負載均衡的緣由也很簡單:每一個系統的處理能力是有限的,爲了應對大容量的訪問,必須使用多個系統。例如,一臺 32 核 64GB 內存的機器,性能測試數據顯示每秒處理 Hello World 的 HTTP 請求不超過 2 萬,實際業務機器處理 HTTP 請求每秒可能才幾百 QPS,而互聯網業務併發超過 1 萬是比較常見的,遇到雙11、過年發紅包這些極端場景,每秒能夠達到幾十萬的請求。

1.DNS

DNS 是最簡單也是最多見的負載均衡方式,通常用來實現地理級別的均衡。例如,北方的用戶訪問北京的機房,南方的用戶訪問廣州的機房。通常不會使用 DNS 來作機器級別的負載均衡,由於太耗費 IP 資源了。例如,百度搜索可能要 10000 臺以上機器,不可能將這麼多機器所有配置公網 IP,而後用 DNS 來作負載均衡。有興趣的讀者能夠在 Linux 用「digbaidu.com」命令看看實際上用了幾個 IP 地址。

DNS 負載均衡的優勢是通用(全球通用)、成本低(申請域名,註冊 DNS 便可),但缺點也比較明顯,主要體如今:

a)       DNS 緩存的時間比較長,即便將某臺業務機器從 DNS 服務器上刪除,因爲緩存的緣由,仍是有不少用戶會繼續訪問已經被刪除的機器。

b)       DNS 不夠靈活。DNS 不能感知後端服務器的狀態,只能根據配置策略進行負載均衡,沒法作到更加靈活的負載均衡策略。好比說某臺機器的配置比其餘機器要好不少,理論上來講應該多分配一些請求給它,但 DNS 沒法作到這一點。

因此對於時延和故障敏感的業務,有實力的公司可能會嘗試實現HTTP-DNS的功能,即便用 HTTP 協議實現一個私有的 DNS 系統。HTTP-DNS 主要應用在經過 App 提供服務的業務上,由於在 App 端能夠實現靈活的服務器訪問策略,若是是 Web 業務,實現起來就比較麻煩一些,由於 URL 的解析是由瀏覽器來完成的,只有 Javascript 的訪問能夠像 App 那樣實現比較靈活的控制。

HTTP-DNS 的優缺點有:

a)       靈活:HTTP-DNS 能夠根據業務需求靈活的設置各類策略。

b)       可控:HTTP-DNS 是本身開發的系統,IP 更新、策略更新等無需依賴外部服務商。

c)       及時:HTTP-DNS 不受傳統 DNS 緩存的影響,能夠很是快地更新數據、隔離故障。

d)       開發成本高:沒有通用的解決方案,須要本身開發。

e)       侵入性:須要 App 基於 HTTP-DNS 進行改造。

2.Nginx 、LVS 、F5

DNS 用於實現地理級別的負載均衡,而 Nginx、LVS、F5 用於同一地點內機器級別的負載均衡。其中 Nginx 是軟件的 7 層負載均衡,LVS 是內核的 4 層負載均衡,F5 是硬件的 4 層負載均衡。

軟件和硬件的區別就在於性能,硬件遠遠高於軟件,Ngxin 的性能是萬級,通常的 Linux 服務器上裝個 Nginx 大概能到 5 萬 / 秒;LVS 的性能是十萬級,沒有具體測試過,聽說可達到 80 萬 / 秒;F5 性能是百萬級,從 200 萬 / 秒到 800 萬 / 秒都有。硬件雖然性能高,可是單臺硬件的成本也很高,一臺最便宜的 F5 都是幾十萬,可是若是按照同等請求量級來計算成本的話,實際上硬件負載均衡設備可能會更便宜,例如假設每秒處理 100 萬請求,用一臺 F5 就夠了,但用 Nginx,可能要 20 臺,這樣折算下來用 F5 的成本反而低。所以一般狀況下,若是性能要求不高,能夠用軟件負載均衡;若是性能要求很高,推薦用硬件負載均衡。

4 層和 7 層的區別就在於協議和靈活性。Nginx 支持 HTTP、E-mail 協議,而 LVS 和 F5 是 4 層負載均衡,和協議無關,幾乎全部應用均可以作,例如聊天、數據庫等。

目前不少雲服務商都已經提供了負載均衡的產品,例如阿里雲的 SLB、UCloud 的 ULB 等,中小公司直接購買便可。

 

CDN

CDN 是爲了解決用戶網絡訪問時的「最後一千米」效應,本質上是一種「以空間換時間」的加速策略,即將內容緩存在離用戶最近的地方,用戶訪問的是緩存的內容,而不是站點實時的內容。

 

 

CDN 通過多年的發展,已經變成了一個很龐大的體系:分佈式存儲、全局負載均衡、網絡重定向、流量控制等都屬於 CDN 的範疇,尤爲是在視頻、直播等領域,若是沒有 CDN,用戶是不可能實現流暢觀看內容的。

幸運的是,大部分程序員和架構師都不太須要深刻理解 CDN 的細節,由於 CDN 做爲網絡的基礎服務,獨立搭建的成本巨大,不多有公司本身設計和搭建 CDN 系統,從 CDN 服務商購買 CDN 服務便可,目前有專門的 CDN 服務商,例如網宿和藍汛;也有云計算廠家提供 CDN 服務,例如阿里雲和騰訊雲都提供 CDN 的服務。

 

多機房

從架構上來講,單機房就是一個全局的網絡單點,在發生比較大的故障或者災害時,單機房難以保證業務的高可用。例如,停電、機房網絡中斷、地震、水災等都有可能致使一個機房徹底癱瘓。

多機房設計最核心的因素就是如何處理時延帶來的影響,常見的策略有:

1.同城多機房

同一個城市多個機房,距離不會太遠,能夠投入重金,搭建私有的高速網絡,基本上可以作到和同機房同樣的效果。

這種方式對業務影響很小,但投入較大,若是不是大公司,通常是承受不起的;並且遇到極端的地震、水災等天然災害,同城多機房也是有很大風險的。

2.跨城多機房

在不一樣的城市搭建多個機房,機房間經過網絡進行數據複製(例如,MySQL 主備複製),但因爲跨城網絡時延的問題,業務上須要作必定的妥協和兼容,好比不須要數據的實時強一致性,只是保證最終一致性。

3.跨國多機房

和跨城多機房相似,只是地理上分佈更遠,時延更大。因爲時延太大和用戶跨國訪問實在太慢,跨國多機房通常僅用於備份和服務本國用戶。

 

多中心

多中心必須以多機房爲前提,但從設計的角度來看,多中心相比多機房是本質上的飛越,難度也高出一個等級。

簡單來講,多機房的主要目標是災備,當機房故障時,能夠比較快速地將業務切換到另一個機房,這種切換操做容許必定時間的中斷(例如,10 分鐘、1 個小時),並且業務也可能有損失(例如,某些未同步的數據不能立刻恢復,或者要等幾天才恢復,甚至永遠都不能恢復了)。所以相比多機房來講,多中心的要求就高多了,要求每一箇中心都同時對外提供服務,且業務可以自動在多中心之間切換,故障後不需人工干預或者不多的人工干預就能自動恢復。

多中心設計的關鍵就在於「數據一致性」和「數據事務性」如何保證,這兩個難點都和業務緊密相關,目前沒有很成熟的且通用的解決方案,須要基於業務的特性進行詳細的分析和設計。以淘寶爲例,淘寶對外宣稱本身是多中心的,可是在實際設計過程當中,商品瀏覽的多中心方案、訂單的多中心方案、支付的多中心方案都須要獨立設計和實現。

正由於多中心設計的複雜性,不必定全部業務都能實現多中心,目前國內的銀行、支付寶這類系統就沒有徹底實現多中心,否則也不會出現挖掘機一鏟子下去,支付寶中斷 4 小時的故障。

 

六. 互聯網架構模板:「用戶層」和「業務層」技術

用戶層技術

1.用戶管理

互聯網業務的一個典型特徵就是經過互聯網將衆多分散的用戶鏈接起來,所以用戶管理是互聯網業務必不可少的一部分。

稍微大一點的互聯網業務,確定會涉及多個子系統,這些子系統不可能每一個都管理這麼龐大的用戶,由此引伸出用戶管理的第一個目標:單點登陸(SSO),又叫統一登陸。單點登陸的技術實現手段較多,例如 cookie、JSONP、token 等,目前最成熟的開源單點登陸方案當屬 CAS,其架構以下

 

 

除此以外,當業務作大成爲了平臺後,開放成爲了促進業務進一步發展的手段,須要容許第三方應用接入,由此引伸出用戶管理的第二個目標:受權登陸。如今最流行的受權登陸就是 OAuth 2.0 協議,基本上已經成爲了事實上的標準,若是要作開放平臺,則最好用這個協議,私有協議漏洞多,第三方接入也麻煩。

用戶管理系統面臨的主要問題是用戶數巨大,通常至少千萬級,QQ、微信、支付寶這種巨無霸應用都是億級用戶。不過也不要被這個數據給嚇倒了,用戶管理雖然數據量巨大,但實現起來並不難,緣由是什麼呢? 由於用戶數據量雖然大,可是不一樣用戶之間沒有太強的業務關聯,A 用戶登陸和 B 用戶登陸基本沒有關係。所以雖然數據量巨大,但咱們用一個簡單的負載均衡架構就能輕鬆應對。

 

 

 

 

 

2.消息推送

消息推送根據不一樣的途徑,分爲短信、郵件、站內信、App 推送。除了 App,不一樣的途徑基本上調用不一樣的 API 便可完成,技術上沒有什麼難度。例如,短信須要依賴運營商的短信接口,郵件須要依賴郵件服務商的郵件接口,站內信是系統提供的消息通知功能。

App 目前主要分爲 iOS 和 Android 推送,iOS 系統比較規範和封閉,基本上只能使用蘋果的 APNS;但 Android 就不同了,在國外,用 GCM 和 APNS 差異不大;可是在國內,狀況就複雜多了:首先是 GCM 不能用;其次是各個手機廠商都有本身的定製的 Android,消息推送實現也不徹底同樣。所以 Android 的消息推送就五花八門了,大部分有實力的大廠,都會本身實現一套消息推送機制,例如阿里雲移動推送、騰訊信鴿推送、百度雲推送;也有第三方公司提供商業推送服務,例如友盟推送、極光推送等。

一般狀況下,對於中小公司,若是不涉及敏感數據,Android 系統上推薦使用第三方推送服務,由於畢竟是專業作推送服務的,消息到達率是有必定保證的。

若是涉及敏感數據,須要本身實現消息推送,這時就有必定的技術挑戰了。消息推送主要包含 3 個功能:設備管理(惟一標識、註冊、註銷)、鏈接管理和消息管理,技術上面臨的主要挑戰有:

a)   海量設備和用戶管理:消息推送的設備數量衆多,存儲和管理這些設備是比較複雜的;同時,爲了針對不一樣用戶進行不一樣的業務推廣,還須要收集用戶的一些信息,簡單來講就是將用戶和設備關聯起來,須要提取用戶特徵對用戶進行分類或者打標籤等。

b)         鏈接保活:要想推送消息必須有鏈接通道,可是應用又不可能一直在前臺運行,大部分設備爲了省電省流量等緣由都會限制應用後臺運行,限制應用後臺運行後鏈接通道可能就被中斷了,致使消息沒法及時的送達。鏈接保活是整個消息推送設計中細節和黑科技最多的地方,例如應用互相拉起、找手機廠商開白名單等。

c)         消息管理:實際業務運營過程當中,並非每一個消息都須要發送給每一個用戶,而是可能根據用戶的特徵,選擇一些用戶進行消息推送。因爲用戶特徵變化很大,各類排列組合都有可能,將消息推送給哪些用戶這部分的邏輯要設計得很是靈活,才能支撐花樣繁多的業務需求,具體的設計方案能夠採起規則引擎之類的微內核架構技術。

3.存儲雲、圖片雲

互聯網業務場景中,用戶會上傳多種類型的文件數據,例如微信用戶發朋友圈時上傳圖片,微博用戶發微博時上傳圖片、視頻,優酷用戶上傳視頻,淘寶賣家上傳商品圖片等,這些文件具有幾個典型特色:

a)         數據量大:用戶基數大,用戶上傳行爲頻繁,例如 2016 年的時候微信朋友圈天天上傳圖片就達到了 10 億張

b)         文件體積小:大部分圖片是幾百 KB 到幾 MB,短視頻播放時間也是在幾分鐘內。

c)         訪問有時效性:大部分文件是剛上傳的時候訪問最多,隨着時間的推移訪問量愈來愈小。

爲了知足用戶的文件上傳和存儲需求,須要對用戶提供文件存儲和訪問功能,這裏就須要用到前面我在介紹「存儲層」技術時提到的「小文件存儲」技術。簡單來講,存儲雲和圖片雲一般的實現都是「CDN + 小文件存儲」,如今有了「雲」以後,除非 BAT 級別,通常不建議本身再重複造輪子了,直接買雲服務多是最快也是最經濟的方式。

既然存儲雲和圖片雲都是基於「CDN + 小文件存儲」的技術,爲什麼不統一一套系統,而將其拆分爲兩個系統呢?這是由於「圖片」業務的複雜性致使的,普通的文件基本上提供存儲和訪問就夠了,而圖片涉及的業務會更多,包括裁剪、壓縮、美化、審覈、水印等處理,所以一般狀況下圖片雲會拆分爲獨立的系統對用戶提供服務。

 

業務層技術

互聯網的業務千差萬別,不一樣的業務分解下來有不一樣的系統,因此業務層沒有辦法提煉一些公共的系統或者組件。拋開業務上的差別,各個互聯網業務發展最終面臨的問題都是相似的:業務複雜度愈來愈高。也就是說,業務層面對的主要技術挑戰是「複雜度」。

複雜度愈來愈高的一個主要緣由就是系統愈來愈龐大,業務愈來愈多。幸運的是,面對業務層的技術挑戰,咱們有一把「屠龍寶刀」,無論什麼業務難題,用上「屠龍寶刀」問題都能迎刃而解。這把「屠龍寶刀」就是「拆」,化整爲零、分而治之,將總體複雜性分散到多個子業務或者子系統裏面去。具體拆的方式你能夠查看專欄前面可擴展架構模式部分的分層架構、微服務、微內核等。

我以一個簡單的電商系統爲例,以下圖所示。

 

 

我這個模擬的電商系統經歷了 3 個發展階段:

第一階段:全部功能都在 1 個系統裏面。

第二階段:將商品和訂單拆分到 2 個子系統裏面。

第三階段:商品子系統和訂單子系統分別拆分紅了更小的 6 個子系統。

上面只是個樣例,實際上隨着業務的發展,子系統會愈來愈多,聽說淘寶內部大大小小的已經有成百上千的子系統了。

隨着子系統數量愈來愈多,若是達到幾百上千,另一個複雜度問題又會凸顯出來:子系統數量太多,已經沒有人可以說清楚業務的調用流程了,出了問題排查也會特別複雜。此時應該怎麼處理呢,總不可能又將子系統合成大系統吧?最終答案仍是「合」,正所謂「合久必分、分久必合」,但合的方式不同,此時採起的「合」的方式是按照「高內聚、低耦合」的原則,將職責關聯比較強的子系統合成一個虛擬業務域,而後經過網關對外統一呈現,相似於設計模式中的 Facade 模式。一樣以電商爲樣例,採用虛擬業務域後,其架構以下:

 

 

 

七. 互聯網架構模板:「平臺」技術

運維平臺

運維平臺核心的職責分爲四大塊:配置、部署、監控、應急,每一個職責對應系統生命週期的一個階段,以下圖所示。

  1. 配置:主要負責資源的管理。例如,機器管理、IP 地址管理、虛擬機管理等。
  2. 部署:主要負責將系統發佈到線上。例如,包管理、灰度發佈管理、回滾等。
  3. 監控:主要負責收集系統上線運行後的相關數據並進行監控,以便及時發現問題。
  4. 應急:主要負責系統出故障後的處理。例如,中止程序、下線故障機器、切換 IP 等。

運維平臺的核心設計要素是「四化」:標準化、平臺化、自動化、可視化。

1.標準化

須要制定運維標準,規範配置管理、部署流程、監控指標、應急能力等,各系統按照運維標準來實現,避免不一樣的系統不一樣的處理方式。標準化是運維平臺的基礎,沒有標準化就沒有運維平臺

若是某個系統就是沒法改造本身來知足運維標準,那該怎麼辦呢?常見的作法是不改造系統,由中間方來完成規範適配。例如,某個系統對外提供了 RESTful 接口的方式來查詢當前的性能指標,而運維標準是性能數據經過日誌定時上報,那麼就能夠寫一個定時程序訪問 RESTful 接口獲取性能數據,而後轉換爲日誌上報到運維平臺。

2.平臺化

傳統的手工運維方式須要投入大量人力,效率低,容易出錯,所以須要在運維標準化的基礎上,將運維的相關操做都集成到運維平臺中,經過運維平臺來完成運維工做。

運維平臺的好處有:

a)       能夠將運維標準固化到平臺中,無須運維人員死記硬背運維標準。

b)       運維平臺提供簡單方便的操做,相比之下人工操做低效且容易出錯。

c)       運維平臺是可複用的,一套運維平臺能夠支撐幾百上千個業務系統。

3.自動化

傳統手工運維方式效率低下的一個主要緣由就是要執行大量重複的操做,運維平臺能夠將這些重複操做固化下來,由系統自動完成。

4.可視化

運維平臺有很是多的數據,若是所有經過人工去查詢數據再來判斷,則效率很低。尤爲是在故障應急時,時間就是生命,處理問題都是爭分奪秒,能減小 1 分鐘的時間就可能挽回幾十萬元的損失,可視化的主要目的就是爲了提高數據查看效率。

 

測試平臺

測試平臺核心的職責固然就是測試了,包括單元測試、集成測試、接口測試、性能測試等,均可以在測試平臺來完成。

測試平臺的核心目的是提高測試效率,從而提高產品質量,其設計關鍵就是自動化。傳統的測試方式是測試人員手工執行測試用例,測試效率低,重複的工做多。經過測試平臺提供的自動化能力,測試用例可以重複執行,無須人工參與,大大提高了測試效率。

爲了達到「自動化」的目標,測試平臺的基本架構以下圖所示。

 

 

1.用例管理

測試自動化的主要手段就是經過腳本或者代碼來進行測試,例如單元測試用例是代碼、接口測試用例能夠用 Python 來寫、可靠性測試用例能夠用 Shell 來寫。爲了可以重複執行這些測試用例,測試平臺須要將用例管理起來,管理的維度包括業務、系統、測試類型、用例代碼。例如,網購業務的訂單系統的接口測試用例。

2.資源管理

測試用例要放到具體的運行環境中才能真正執行,運行環境包括硬件(服務器、手機、平板電腦等)、軟件(操做系統、數據庫、Java 虛擬機等)、業務系統(被測試的系統)。

除了性能測試,通常的自動化測試對性能要求不高,因此爲了提高資源利用率,大部分的測試平臺都會使用虛擬技術來充分利用硬件資源,如虛擬機、Docker 等技術。

3.任務管理

任務管理的主要職責是將測試用例分配到具體的資源上執行,跟蹤任務的執行狀況。任務管理是測試平臺設計的核心,它將測試平臺的各個部分串聯起來從而完成自動化測試。

4.數據管理

測試任務執行完成後,須要記錄各類相關的數據(例如,執行時間、執行結果、用例執行期間的 CPU、內存佔用狀況等),這些數據具有下面這些做用:

a)       展示當前用例的執行狀況。

b)       做爲歷史數據,方便後續的測試與歷史數據進行對比,從而發現明顯的變化趨勢。例如,某個版本後單元測試覆蓋率從 90% 降低到 70%。

c)       做爲大數據的一部分,能夠基於測試的任務數據進行一些數據挖掘。例如,某個業務一年執行了 10000 個用例測試,另一個業務只執行了 1000 個用例測試,兩個業務規模和複雜度差很少,爲什麼差別這麼大?

 

數據平臺

數據平臺的核心職責主要包括三部分:數據管理、數據分析和數據應用。每一部分又包含更多的細分領域,詳細的數據平臺架構以下圖所示。

 

1.數據管理

數據管理包含數據採集、數據存儲、數據訪問和數據安全四個核心職責,是數據平臺的基礎功能。

a)       數據採集:從業務系統蒐集各種數據。例如,日誌、用戶行爲、業務數據等,將這些數據傳送到數據平臺。

b)       數據存儲:將從業務系統採集的數據存儲到數據平臺,用於後續數據分析。

c)       數據訪問:負責對外提供各類協議用於讀寫數據。例如,SQL、Hive、Key-Value 等讀寫協議。

d)       數據安全:一般狀況下數據平臺都是多個業務共享的,部分業務敏感數據須要加以保護,防止被其餘業務讀取甚至修改,所以須要設計數據安全策略來保護數據。

2.數據分析

數據分析包括數據統計、數據挖掘、機器學習、深度學習等幾個細分領域。

a)  數據統計:根據原始數據統計出相關的總覽數據。例如,PV、UV、交易額等。

b)  數據挖掘:數據挖掘這個概念自己含義能夠很廣,爲了與機器學習和深度學習區分開,這裏的數據挖掘主要是指傳統的數據挖掘方式。例如,有經驗的數據分析人員基於數據倉庫構建一系列規則來對數據進行分析從而發現一些隱含的規律、現象、問題等,經典的數據挖掘案例就是沃爾瑪的啤酒與尿布的關聯關係的發現。

c)  機器學習、深度學習:機器學習和深度學習屬於數據挖掘的一種具體實現方式,因爲其實現方式與傳統的數據挖掘方式差別較大,所以數據平臺在實現機器學習和深度學習時,須要針對機器學習和深度學習獨立進行設計。

3.數據應用

數據應用很普遍,既包括在線業務,也包括離線業務。例如,推薦、廣告等屬於在線應用,報表、欺詐檢測、異常檢測等屬於離線應用。

數據應用可以發揮價值的前提是須要有「大數據」,只有當數據的規模達到必定程度,基於數據的分析、挖掘才能發現有價值的規律、現象、問題等。若是數據沒有達到必定規模,一般狀況下作好數據統計就足夠了,尤爲是不少初創企業,無須一開始就參考 BAT 來構建本身的數據平臺。

 

管理平臺

管理平臺的核心職責就是權限管理,不管是業務系統(例如,淘寶網)、中間件系統(例如,消息隊列 Kafka),仍是平臺系統(例如,運維平臺),都須要進行管理。若是每一個系統都本身來實現權限管理,效率過低,重複工做不少,所以須要統一的管理平臺來管理全部的系統的權限。

權限管理主要分爲兩部分:身份認證、權限控制,其基本架構以下圖所示。

1.身份認證

肯定當前的操做人員身份,防止非法人員進入系統。例如,不容許匿名用戶進入系統。爲了不每一個系統都本身來管理用戶,一般狀況下都會使用企業帳號來作統一認證和登陸。

2.權限控制

根據操做人員的身份肯定操做權限,防止未經受權的人員進行操做。例如,不容許研發人員進入財務系統查看別人的工資。

 

八. 架構重構內功心法第一式:有的放矢

「架構設計三原則」中的演化原則部分,我提到了系統的架構是不斷演化的,少部分架構演化可能須要推倒重來進行重寫,但絕大部分的架構演化都是經過架構重構來實現的。相比全新的架構設計來講,架構重構對架構師的要求更高,主要體如今:

1.業務已經上線,不能停下來

架構重構時,業務已經上線運行了,重構既須要儘可能保證業務繼續往前發展,又要完成架構調整,這就比如「給飛行中的波音 747 換引擎」;而若是是新設計架構,業務尚未上線,則即便作砸了對業務也不會有太大影響。

2.關聯方衆多,牽一髮動全身

架構重構涉及的業務關聯方不少,不一樣關聯方的資源投入程度、業務發展速度、對架構痛點的敏感度等有很大差別,如何儘可能減小對關聯方的影響,或者協調關聯方統一行動,是一項很大的挑戰;而若是是新設計架構,則在新架構上線前,對關聯方沒有影響。

3.舊架構的約束

架構重構須要在舊的架構基礎上進行,這是一個很強的約束,會限制架構師的技術選擇範圍;而若是是新設計架構,則架構師的技術選擇餘地大得多。

即便是咱們決定推倒到重來,徹底拋棄舊的架構而去設計新的架構,新架構也會受到舊架構的約束和影響,由於業務在舊架構上產生的數據是不能推倒重來的,新架構必須考慮如何將舊架構產生的數據轉換過來。

 

所以,架構重構對架構師的綜合能力要求很是高,業務上要求架構師可以說服產品經理暫緩甚至暫停業務來進行架構重構;團隊上須要架構師可以與其餘團隊達成一致的架構重構計劃和步驟;技術上須要架構師給出讓技術團隊承認的架構重構方案。

總之,架構重構須要架構師既要說得動老闆,也要鎮得住同事;既要技術攻關,又要協調資源;既要保證業務正常發展,又要在指定時間內完成目標……總之就是十八般武藝要樣樣精通。

 

說了那麼多架構重構的難度,千萬不要被困難所嚇倒,架構師正是須要在原來一團亂麻中找到線索,而後從新穿針引線,幫助業務進一步騰飛發展。接下來我將分 3 期傳授個人架構重構內功心法,今天先來看第一式:有的放矢

一般狀況下,當系統架構不知足業務的發展時,其表現形式是系統不斷出現各類問題,輕微一點的如系統響應慢、數據錯誤、某些用戶訪問失敗等,嚴重的多是宕機、數據庫癱瘓、數據丟失等,或者系統的開發效率很低。開始的時候,技術團隊可能只針對具體的問題去解決,解決一個算一個,但若是持續時間較長,例如持續了半年甚至一年狀況都不見好轉,此時可能有人想到了系統的架構是否存在問題,討論是不是由於架構緣由致使了各類問題。一旦肯定須要進行架構重構,就會由架構師牽頭來進行架構重構的分析。

當架構師真正開始進行架構重構分析時,就會發現本身好像進了一個迷霧森林,處處都是問題,每一個問題都須要解決,不知道出路在哪裏,感受若是要解決全部這些問題,架構重構其實也無能爲力。有的架構師一上來蒐集了系統當前存在的問題,而後彙總成一個 100 行的 Excel 表格,看到這樣一個表格就懵了:這麼多問題,要到猴年馬月才能所有解決完啊?

指望經過架構重構來解決全部問題固然是不現實的,因此架構師的首要任務是從一大堆紛繁複雜的問題中識別出真正要經過架構重構來解決的問題,集中力量快速解決,而不是想着經過架構重構來解決全部的問題。不然就會陷入人少事多頭緒亂的處境,團隊累死累活弄個大半年,最後發現好像什麼都作了,但每一個問題都依然存在。尤爲是對於剛接手一個新系統的架構師或者技術主管來講,必定要控制住「新官上任三把火」的衝動,避免攤大餅式或者運動式的重構和優化。

咱們來看幾個具體的重構案例。

1.後臺系統重構:解決不合理的耦合

M 系統是一個後臺管理系統,負責管理全部遊戲相關的數據,重構的主要緣由是由於系統耦合了 P 業務獨有的數據和全部業務公用的數據,致使可擴展性比較差。其大概架構以下圖所示。

 

舉一個簡單的例子:數據庫中的某張表,一部分字段是全部業務公用的「遊戲數據」,一部分字段是 P 業務系統「獨有的數據」,開發時若是要改這張表,代碼和邏輯都很複雜,改起來效率很低。

針對 M 系統存在的問題,重構目標就是將遊戲數據和業務數據拆分,解開二者的耦合,使得兩個系統都可以獨立快速發展。重構的方案以下圖所示。

重構後的效果很是明顯,重構後的 M 系統和 P 業務後臺系統每個月上線版本數是重構前的 4 倍!

2.遊戲接入系統重構:解決全局單點的可用性問題

S 系統是遊戲接入的核心繫統,一旦 S 系統故障,大量遊戲玩家就不能登陸游戲。而 S 系統並不具有多中心的能力,一旦主機房宕機,整個 S 系統業務就不可用了。其大概架構以下圖所示,能夠看出數據庫主庫是全局單點,一旦數據庫主庫不可用,兩個集羣的寫業務都不可用了。

針對 S 系統存在的問題,重構目標就是實現雙中心,使得任意一個機房都可以提供完整的服務,在某個機房故障時,另一個機房可以所有接管全部業務。重構方案以下圖所示。

 

重構後系統的可用性從 3 個 9 提高到 4 個 9,重構前最誇張的一個月有 4 次較大的線上故障,重構後雖然也經歷了機房交換機宕機、運營商線路故障、機櫃斷電等問題,但對業務都沒有什麼大的影響。

3.X 系統:解決大系統帶來的開發效率問題

X 系統是創新業務的主系統,以前在業務快速嘗試和快速發展期間,怎麼方便怎麼操做,怎麼快速怎麼作,系統設計並未投入太多精力和時間,不少東西都「塞」到同一個系統中,致使到了如今已經改不動了。作一個新功能或者新業務,須要花費大量的時間來討論和梳理各類業務邏輯,一不當心就踩個大坑。X 系統的架構以下圖所示。

X 系統的問題看起來和 M 系統比較相似,都是可擴展性存在問題,但其實根本緣由不同:M 系統是由於耦合了不一樣業務的數據致使系統可擴展性不足,而 X 系統是由於將業務相關的全部功能都放在同一個系統中,致使系統可擴展性不足;同時,全部功能都在一個系統中,也可能致使一個功能出問題,整站不可用。好比說某個功能把數據庫拖慢了,整站全部業務跟着都慢了。

針對 X 系統存在的問題,重構目標是將各個功能拆分到不一樣的子系統中,下降單個系統的複雜度。重構後的架構以下圖所示(僅僅是示例,實際架構遠比下圖複雜)。

重構後各個系統之間經過接口交互,雖然看似增長了接口的工做量,但總體來講,各系統的發展和開發速度比原來快了不少,系統也相對更加簡單,也不會出現某個子系統有問題,全部業務都有問題。

這三個系統重構的方案,如今回過頭來看,感受是理所固然的,但實際上當時作分析和決策時,遠遠沒有這麼簡單。以 M 系統爲例,當時咱們接手後遇到的問題有不少,例如:

  1. 數據常常出錯。
  2. M 系統是單機,單機宕機後全部後臺操做就不能進行了。
  3. 性能比較差,有的操做耗時很久。
  4. 界面比較醜,操做不人性化。
  5. 歷史上通過幾手轉接,代碼比較混亂。
  6. 業務數據和遊戲數據耦合,開發效率很低。

從這麼多問題中識別出重構的目標,並非一目瞭然的;而若是想一下所有解決全部這些問題,人力和時間又不夠!因此架構師須要透過問題表象看到問題本質,找出真正須要經過架構重構解決的核心問題,從而作到有的放矢,既不會耗費大量的人力和時間投入,又可以解決核心問題。這對架構師的分析和判斷能力要求很是高,既不能看到問題就想到要架構重構,也不能只是針對問題進行系統優化,判斷究竟是採起架構重構仍是採起系統優化,可能不一樣的架構師和團隊都有不一樣的見解。這裏分享一個簡單的作法:假設咱們如今須要從 0 開始設計當前系統,新架構和老架構是否相似?若是差別不大,說明採起系統優化便可;若是差別很大,那可能就要進行系統重構了。

那原來發現的那些非架構重構問題怎麼辦呢?固然不能聽任無論。以 M 系統爲例,咱們在重構完成後,又啓動了多個優化的項目去優化這些問題,但此時的優化主要由團隊內部完成便可,和其餘團隊沒有太多關聯,優化的速度是很快的。若是沒有重構就進行優化,則每次優化都要拉一大堆關聯業務的團隊來討論方案,效率很是低下!

 

九. 架構重構內功心法第二式:合縱連橫

合縱            

架構重構是大動做,持續時間比較長,並且會佔用必定的研發資源,包括開發和測試,所以不可避免地會影響業務功能的開發。所以,要想真正推進一個架構重構項目啓動,須要花費大量的精力進行遊說和溝通。注意這裏不是指辦公室政治,而是指要和利益相關方溝通好,讓你們對於重構可以達成一致共識,避免重構過程當中沒必要要的反覆和爭執。

通常的技術人員談到架構重構時,就會搬出一大堆技術術語:可擴展性、可用性、性能、耦合、代碼很亂……但從過往的實際經驗來看,若是和非技術人員這樣溝通,效果如同雞同鴨講,沒有技術背景的人員很難理解,甚至有可能擔憂咱們是在忽悠人。

技術人員說:咱們系統如今的可擴展性太差了,改都改不動!

產品人員想:咦,可擴展性,和擴胸運動有關嗎?擴展什麼呢?怎麼會改不動呢?不就是找個地方寫代碼嘛……

技術人員說:咱們的可用性太差,如今才 3 個 9,業界都是 4 個 9!

項目經理想:什麼是 3 個 9,三九感冒靈?4 個 9 和 3 個 9 不就是差個 9 嘛,和可用有什麼關係……

技術人員說:咱們系統設計不合理,A 業務和 B 業務耦合!

運營人員想:咦,耦合,蓮藕仍是藕斷絲連?A 業務和 B 業務原本就是互相依賴的呀,耦合爲何不合理呢?

因此在溝通協調時,將技術語言轉換爲通俗語言,以事實說話,以數聽說話,是溝通的關鍵!

以以前的 M 系統爲例,咱們把「可擴展性」轉換爲「版本開發速度很慢,每次設計都要考慮是否對門戶有影響,是否要考慮對其餘業務有影響」,而後咱們還收集了 1 個月裏的版本狀況,發現有幾個版本設計階段討論 1 周甚至 2 周時間,但開發只有 2 天時間;並且一個月才作了 4 個版本,最極端的一個版本討論 2 周,開發 2 天,而後等了 1 個月才和門戶系統一塊兒上線,項目經理和產品經理一聽都被嚇到了。

已以前的 S 系統爲例,咱們並無直接說可用性是幾個 9,而是整理線上故障的次數、每次影響的時長,影響的用戶,客服的反饋意見等,而後再拿其餘系統的數據進行對比,不管是產品人員、項目人員,仍是運營人員,明顯就看出系統的可用性有問題了。

 

連橫

除了上面討論的和上下游溝通協調,有的重構還須要和其餘相關或者配合的系統的溝通協調。因爲你們都是作技術的,有比較多的共同語言,因此這部分的溝通協調其實相對來講要容易一些,但也不是說想推進就能推進的,主要的阻力來自「這對我有什麼好處」和「這部分我這邊如今不急」。

對於「這對我有什麼好處」問題,有的人會簡單理解爲這是自私的表現,認爲對方不顧大局,因而溝通的時候將問題人爲拔高。例如「你應該站在部門的角度來考慮這個問題」「這對公司總體利益有幫助」等。這種溝通效果其實不好,首先是這種拔高通常都比較虛,沒法明確,不一樣的人理解也不同,沒法達成共識;其次是若是對公司和部門有利,但對某個小組沒用甚至不利,那麼多是由於目前的方案不夠好,還能夠考慮另外的方案。

那如何纔能有效地推進呢?有效的策略是「換位思考、合做共贏、關注長期」。簡單來講就是站在對方的角度思考,重構對他有什麼好處,可以幫他解決什麼問題,帶來什麼收益。

再以 M 系統爲例,當時有另一個 C 系統和 M 系統經過數據庫直連共用數據庫,咱們的重構方案是要去掉兩個系統同時在底層操做數據庫,改成 C 系統經過調用 M 系統接口來寫入數據庫。這個方案對 C 系統來講,很明顯的一點就是 C 系統短時間的改動比較大,要將十幾個功能都從直接讀寫數據庫改成跨系統接口調用。剛開始 C 系統也是以爲重構對他們沒有什麼做用,後來咱們通過分析和溝通,瞭解到 C 系統其實也深受目前這種架構之苦,主要體如今「數據常常出錯要排查」(由於 C 系統和 M 系統都在寫同一個數據庫,邏輯很難保證徹底一致)、「要跟着 M 系統同步開發」(由於 M 系統增長表或者字段,C 系統要從數據庫本身讀取出來,還要理解邏輯)、「C 系統要連兩個數據庫,出問題很差查」(由於 C 系統本身還有數據庫)……這些問題其實在 M 系統重構後均可以解決,雖然短時間內 C 系統有必定的開發工做量,但從中長期來看,C 系統確定能夠省不少事情。例如,數據問題排查主要是 M 系統的事情了,經過 M 系統的接口獲取數據,無須關注數據相關的業務邏輯等。經過這種方式溝通協調,C 系統很樂意跟咱們一塊兒作重構,並且事實也證實重構後對 C 系統和 M 系統都有很大好處。

         固然若是真的出現了對公司或者部門有利,對某個小組不利的狀況,那可能須要協調更高層級的管理者纔可以推進,平級推進是比較難的。

         對於「這部分咱們如今不急」問題,有的人可能會認爲這是在找藉口,我也不排除這種可能性。但就算真的是找藉口,那也是由於你們沒有達成一致意見,可能對方很差意思直接拒絕。因此這種狀況就能夠參考上面「這對我有什麼好處」問題的處理方法來處理。

         若是對方真的是由於有其餘更重要的業務,此時勉爲其難也很差,仍是那句話:換位思考!由於大部分重構的系統並非到了迫不及待很是緊急的時候纔開始啓動的,而是有必定前瞻性的規劃,若是對方真的有其餘更加劇要的事情,採起等待的策略也何嘗不可,但要明確正式啓動的時間。例如,3 個月後開始、6 月份開始,千萬不能說「之後」「等不忙的時候」這種沒法明確的時間點。

         除了計劃上靈活一點,方案上也能夠靈活一點:咱們能夠先不作這個系統相關的重構,先把其餘須要重構的作完。由於大部分須要重構的系統,須要作的事情不少,分階段處理,在風險規避、計劃安排等方面更加靈活可控。

 

十. 架構重構內功心法第三式:指揮若定

在以前我提到架構師須要從一大堆問題中識別關鍵的複雜度問題,而後有的放矢地經過架構重構來解決。可是一般狀況下,須要架構重構的系統,基本上都是由於各類歷史緣由和歷史問題沒有及時處理,遺留下來逐漸積累,而後到了一個臨界點,各類問題開始互相做用,集中爆發!到了真正要開始重構的時候,架構師識別出系統關鍵的複雜度問題後,若是隻針對這個複雜度問題進行架構重構,可能會發現仍是沒法落地,由於不少條件不具有或者有的問題沒解決的狀況下就是不能作架構重構。所以,架構師在識別系統關鍵的複雜度問題後,還須要識別爲了解決這個問題,須要作哪些準備事項,或者還要先解決哪些問題。這就須要我今天要和你分享的架構重構內功心法第三式:指揮若定。

         通過分析和思考,咱們可能從最初的 100 個問題列表,挑選出其中 50 個是須要在架構重構中解決的,其中一些是基礎能力建設或者準備工做,而另一些就是架構重構的核心工做。有了這樣一個表格後,那咱們應該怎麼去把這 50 個問題最終解決呢?

         最簡單的作法是每次從中挑一個解決,最終總會把全部的問題都解決。這種作法操做起來比較簡單,但效果會不好,爲何呢?

  1. 沒有區分問題的優先級,全部問題都一視同仁,沒有集中有限資源去解決最重要或者最關鍵的問題,致使最後作了大半年,回頭一看好像作了不少事情,但沒取得什麼階段性的成果。
  2. 沒有將問題分類,致使類似問題沒有統籌考慮,方案可能出現反覆,效率不高。
  3. 迫於業務版本的壓力,專門挑容易作的實施,到了稍微難一點的問題的時候,就由於複雜度和投入等緣由被擱置,達不到重構的真正目的。

 

以 X 系統爲例,在我加入前,其實也整理了系統目前存在的問題,大的項包括可用性、性能、安全、用戶體驗等,每一個大項又包括十幾二十個子項。可是實施時基本上就是挑軟柿子捏,以爲哪一個好落地、佔用資源不太多,就挑來作,結果作了半年,好像作了不少功能,但總體卻沒什麼進展。

後來咱們成立了一個「X 項目」,在原來整理的問題基礎上,識別出架構的核心複雜度體如今龐大的系統集成了太多功能,可擴展性不足;但目前系統的可用性也不高,常常出線上問題,耗費大量的人力去處理。所以咱們又識別出若是要作架構重構,就須要系統處於一個比較穩定的狀態,不要常常出線上問題。而目前系統的可用性性不高,有的是由於硬件資源不夠用了,或者某些系統組件使用不合理,有的是由於架構上存在問題。

基於這些分析,咱們制定了整體的策略,以下圖所示。

能夠看到,真正的架構重構在第三階段,第一階段和第二階段都是爲了第三階段作準備而已,但若是沒有第一階段和第二階段的鋪墊,直接開始第三階段的架構重構工做,架構重構方案須要糅合第一階段和第二階段的一些事項(例如,業務降級、接入服務中心等),會致使架構重構方案不聚焦,並且異常複雜。

爲何最終採用這樣一個策略呢?主要仍是爲了集中有限的資源,某個階段集中解決某一類問題。這樣作首先是效率高,由於階段目標比較明確,作決策和方案的時候無須進行太多選擇;其次是每一個階段都能看到明顯的成果,給團隊很大的信心。好比說第一階段的「救火」,作完以後,系統不多有由於機器過載、緩存響應慢、虛擬機掛死等問題致使的故障了;完成第二階段的事項後,由於組件、外部系統故障致使系統故障的問題也不多了。完成前兩個階段後,咱們就能夠安心地作第三階段的「服務化」工做了。

S 系統的重構作法也是相似,但 S 系統當時面臨的主要問題就是可用性不高,並無系統耦合的問題,因此咱們當時的策略是「先救火、後優化、再重構」。「救火」階段作了擴容(防止資源不足致使系統被壓死)和 Nginx 一鍵切換功能(故障時快速切換);優化階段將一些明顯的可用性問題解決(包括性能問題等);重構階段將原來的單點數據庫改成多中心。

總結一下重構的作法,其實就是「分段實施」,將要解決的問題根據優先級、重要性、實施難度等劃分爲不一樣的階段,每一個階段聚焦於一個總體的目標,集中精力和資源解決一類問題。這樣作有幾個好處:

  1. 每一個階段都有明確目標,作完以後效果明顯,團隊信心足,後續推動更加容易。
  2. 每一個階段的工做量不會太大,能夠和業務並行。
  3. 每一個階段的改動不會太大,下降了整體風險。

具體如何制定「分段實施」的策略呢?分享一下個人經驗。

1.優先級排序

將明顯且又比較緊急的事項優先落地,解決目前遇到的主要問題。例如,擴容在 S 系統和 X 系統中都是最優先實施的,由於若是不擴容,系統隔三差五一會出現響應超時報警,一會來個過載報警,一會來個大面積不可用……這些問題耗費大量的人力和精力,也就無法作其餘事情了。

2.問題分類

將問題按照性質分類,每一個階段集中解決一類問題。例如,X 系統的第二階段,咱們將多個底層系統切換到公司統一的公共組件,提高總體可用性。

3.先易後難

這點與不少人的直覺不太同樣,有的人認爲應該先攻克最難的問題,所謂「擒賊先擒王」,解決最難的問題後其餘問題就不在話下。這樣看起來很美好,但實際上不可行。

首先,一開始就作最難的部分,會發現想要解決這個最難的問題,要先解決其餘容易的問題。

其次,最難的問題解決起來耗時都比較長,佔用資源比較多,若是一開始作最難的,可能作了一兩個月尚未什麼進展和成果,會影響相關人員對項目的評價和見解,也可能影響團隊士氣。

第三,剛開始的分析並不必定全面,因此一開始對最難的或者最關鍵的事項的判斷可能會出錯。

採起「先易後難」的策略,可以很大程度上避免「先難後易」策略的問題。

首先,隨着項目的推動,一些相對簡單的問題逐漸解決,會發現原來看起來很難的問題已經不那麼難了,甚至有的問題可能都消失了。

其次,先易後難可以比較快地看到成果,雖然成果可能不大,但至少能看到一些成效了,對後續的項目推動和提高團隊士氣有很大好處。

第三,隨着項目的進行,原來遺漏的一些點,或者分析和判斷錯誤的點,會逐漸顯示出來,及時根據實際狀況進行調整,可以有效地保證整個重構的效果。

4. 按部就班

         按照前 3 個步驟劃分了架構重構的實施階段後,就須要評估每一個階段所須要耗費的時間,極可能會出現有的階段耗時可能只要 1 個月,而有的卻須要 6 個月,雖然這可能確實是客觀事實,但一般狀況下,按照固定的步驟和節奏,更有利於項目推動。個人經驗是每一個階段最少 1 個月,最長不要超過 3 個月,若是評估超過 3 個月的,那就再拆分爲更多階段。就像 X 項目,咱們先劃分了階段,每一個階段又分了任務子集,當任務子集比較小的時候,多個任務子集能夠並行;當任務子集比較大的時候,就當成一個獨立的里程碑推動。

 

十一. 再談開源項目:如何選擇、使用以及二次開發?

軟件開發領域有一個流行的原則:DRY,Don’t repeat yourself。翻譯過來更通俗易懂:不要重複造輪子。開源項目的主要目的是共享,其實就是爲了讓你們不要重複造輪子,尤爲是在

互聯網這樣一個快速發展的領域,速度就是生命,引入開源項目能夠節省大量的人力和時間,大大加快業務的發展速度,何樂而不爲呢?

然而現實每每沒有那麼美好,開源項目雖然節省了大量的人力和時間,但帶來的問題也很多,相信絕大部分技術人員都踩過開源軟件的坑,小的影響多是宕機半小時,大的問題多是丟失幾十萬條數據,甚至災難性的事故是所有數據都丟失。

除此之外,雖然 DRY 原則擺在那裏,但實際上開源項目反而是最不遵照 DRY 原則的,重複的輪子好多,你有 MySQL,我有 PostgreSQL;你有 MongoDB,我有 Cassandra;你有 Memcached,我有 Redis;你有 Gson,我有 Jackson;你有 Angular,我有 React……總之放眼望去,其實類似的輪子不少!類似輪子太多,如何選擇就成了讓人頭疼的問題了。

怎麼辦?徹底不用開源項目幾乎是不可能的,架構師須要更加聰明地選擇和使用開源項目。形象點說:不要重複發明輪子,但要找到合適的輪子!但別忘了,若是你開的是保時捷,可別找個拖拉機的輪子。

 

選:如何選擇一個開源項目

1.聚焦是否知足業務

架構師在選擇開源項目時,一個頭疼的問題就是類似的開源項目較多,並且後面的老是要宣稱比前面的更加優秀。有的架構師在選擇時有點無所適從,老是會擔憂選擇了 A 項目而錯過了 B 項目。這個問題的解決方式是聚焦因而否知足業務,而不須要過於關注開源項目是否優秀。

2.聚焦是否成熟

不少新的開源項目每每都會聲稱本身比之前的項目更加優秀:性能更高、功能更強、引入更多新概念……看起來都很誘人,但實際上都有意無心地隱藏了一個負面的問題:更加不成熟!無論多優秀的程序員寫出來的項目都會有 bug,千萬不要覺得做者歷害就沒有 bug,Windows、Linux、MySQL 的開發者都是頂級的開發者,系統同樣有不少 bug。

不成熟的開源項目應用到生產環境,風險極大:輕則宕機,重則宕機後重啓都恢復不了,更嚴重的是數據丟失都找不回來。

3.聚焦運維能力

大部分架構師在選擇開源項目時,基本上都是聚焦於技術指標,例如性能、可用性、功能這些評估點,而幾乎不會去關注運維方面的能力。但若是要將項目應用到線上生產環境,則運維能力是必不可少的一環,不然一旦出問題,運維、研發、測試都只能乾瞪眼,求菩薩保佑了!

 

用:如何使用開源項目

1.深刻研究,仔細測試

不少人用開源項目,實際上是完徹底全的「拿來主義」,看了幾個 Demo,把程序跑起來就開始部署到線上應用了。這就好像看了一下開車指南,知道了方向盤是轉向、油門是加速、剎車是減速,而後就開車上路了,實際上是很是危險的。

2.當心應用,灰度發佈

假如咱們作了上面的「深刻研究、仔細測試」,發現沒什麼問題,是否就能夠放心大膽地應用到線上了呢?別高興太早,即便你的研究再深刻,測試再仔細,仍是要當心爲妙,由於再怎麼深刻地研究,再怎麼仔細地測試,都只能下降風險,但不可能徹底覆蓋全部線上場景。

3.作好應急,以防萬一

即便咱們前面的工做作得很是完善和充分,也不能認爲萬事大吉,尤爲是剛開始使用一個開源項目,運氣很差可能遇到一個以前全世界的使用者歷來沒遇到的 bug,致使業務都沒法恢復,尤爲是存儲方面,一旦出現問題沒法恢復,可能就是致命的打擊。

 

改:如何基於開源項目作二次開發

1.保持純潔,加以包裝

當咱們發現開源項目有的地方不知足咱們的需求時,天然會有一種去改改的衝動,可是怎麼改是個大學問。一種方式是投入幾我的從內到外所有改一遍,將其改形成徹底符合咱們業務需求。但這樣作有幾個比較嚴重的問題:

a)       投入太大,通常來講,Redis 這種級別的開源項目,真要本身改,至少要投入 2 我的,搞 1 個月以上。

b)       失去了跟隨原項目演進的能力:改的太多,即便原有開源項目繼續演進,也沒法合併了,由於差別太大。

因此個人建議是不要改動原系統,而是要開發輔助系統:監控、報警、負載均衡、管理等。以 Redis 爲例,若是咱們想增長集羣功能,則不要去改動 Redis 自己的實現,而是增長一個 proxy 層來實現。Twitter 的 Twemproxy 就是這樣作的,而 Redis 到了 3.0 後自己提供了集羣功能,原有的方案簡單切換到 Redis 3.0 便可。

若是實在想改到原有系統,怎麼辦呢?咱們的建議是直接給開源項目提需求或者 bug,但弊端就是響應比較緩慢,這個就要看業務緊急程度了,若是實在太急那就只能本身改了;若是不是太急,建議作好備份或者應急手段便可。

2.發明你要的輪子

這一點估計讓你大跌眼鏡,怎麼講了半天,最後又回到了「重複發明你要的輪子」呢?其實選與不選開源項目,核心仍是一個成本和收益的問題,並非說選擇開源項目就必定是最優的項目,最主要的問題是:沒有徹底適合你的輪子!

軟件領域和硬件領域最大的不一樣就是軟件領域沒有絕對的工業標準,你們都很盡興,想怎麼玩就怎麼玩。不像硬件領域,你造一個尺寸不同凡響的輪子,其餘車都用不上,你的輪子工藝再高,質量再好也是白費;軟件領域能夠造不少類似的輪子,基本上能處處用。例如,把緩存從 Memcached 換成 Redis,不會有太大的問題。

除此之外,開源項目爲了可以大規模應用,考慮的是通用的處理方案,而不一樣的業務其實差別較大,通用方案並不必定完美適合具體的某個業務。好比說 Memcached,經過一致性 Hash 提供集羣功能,可是咱們的一些業務,緩存若是有一臺宕機,整個業務可能就被拖慢了,這就要求咱們提供緩存備份的功能。但 Memcached 又沒有,而 Redis 當時又沒有集羣功能,因而咱們投入 2~4 我的花了大約 2 個月時間基於 LevelDB 的原理,本身作了一套緩存框架支持存儲、備份、集羣的功能,後來又在這個框架的基礎上增長了跨機房同步的功能,很大程度上提高了業務的可用性水平。若是徹底採用開源項目,等開源項目來實現,是不可能這麼快速的,甚至開源項目徹底就不支持咱們的需求。

因此,若是你有錢有人有時間,投入人力去重複發明完美符合本身業務特色的輪子也是很好的選擇!畢竟,不少財大氣粗的公司(BAT 等)都是這樣作的,不然咱們也就沒有那麼多好用的開源項目了。

 

十二. 談談App架構的演進

 

以前的內容主要都是講後端系統的架構設計,例如存儲高可用、微服務、異地多活等,都是後端系統纔會涉及。事實上確實也是如此,一般狀況下咱們講架構設計,主要聚焦在後端系統,但這並不意味着 App、前端就沒有架構設計了,專欄所講述的整套架構設計理念,雖然是來源於個人後端設計經驗,但一旦造成完善的技術理論後,一樣適應於 App 和前端。

首先,先來複習一下個人專欄所講述的架構設計理念,能夠提煉爲下面幾個關鍵點:

  1. 架構是系統的頂層結構。
  2. 架構設計的主要目的是爲了解決軟件系統複雜度帶來的問題。
  3. 架構設計須要遵循三個主要原則:合適原則、簡單原則、演化原則。
  4. 架構設計首先要掌握業界已經成熟的各類架構模式,而後再進行優化、調整、創新。

 

Web App

最先的 App 有不少採用這種架構,大多數嘗試性的業務,一開始也是這樣的架構。Web App 架構又叫包殼架構,簡單來講就是在 Web 的業務上包裝一個 App 的殼,業務邏輯徹底仍是 Web 實現,App 殼完成安裝的功能,讓用戶看起來像是在使用 App,實際上和用瀏覽器訪問 PC 網站沒有太大差異。

爲什麼早期的 App 或者嘗試新的業務採用這種架構比較多呢?簡單來講,就是當時業務面臨的複雜度決定的。咱們以早期的 App 爲例,大約在 2010 年先後,移動互聯網雖然發展很迅速,但受限於用戶的設備、移動網絡的速度等約束,PC 互聯網仍是主流,移動互聯網仍是一個新鮮事物,將來的發展前景和發展趨勢,其實當年你們也不必定能徹底看得清楚。例如淘寶也是在 2013 年纔開始決定「All in 無線」的,在這樣的業務背景下,當時的業務重心仍是在 PC 互聯網上,移動互聯網更可能是嘗試性的。既然是嘗試,那就要求快速和低成本,雖然當時的 Android 和 iOS 已經都有了開發 App 的功能,但原生的開發成本過高,所以天然而然,Web App 這種包殼架構就被你們做爲首選嘗試架構了,其主要解決「快速開發」和「低成本」兩個複雜度問題,架構設計遵循「合適原則」和「簡單原則」。

 

原生App

Web App 雖然解決了「快速開發」和「低成本」兩個複雜度問題,但隨着業務的發展,Web App 的劣勢逐漸成爲了主要的複雜度問題,主要體如今:

  1. 移動設備的發展速度遠遠超過 Web 技術的發展速度,所以 Web App 的體驗相比原生 App 的體驗,差距愈來愈明顯。
  2. 移動互聯網飛速發展,趨勢愈來愈明顯,App 承載的業務邏輯也愈來愈複雜,進一步加重了 Web App 的體驗問題。
  3. 移動設備在用戶體驗方面有不少優化和改進,而 Web App 沒法利用這些技術優點,只有原生 App 纔可以利用這些技術優點。

所以,隨着業務發展和技術演進,移動開發的複雜度從「快速開發」和「低成本」轉向了「用戶體驗」,而要保證用戶體驗,採用原生 App 的架構是最合適的,這裏的架構設計遵循「演化原則」。

原生 App 解決了用戶體驗問題,沒記錯的話大約在 2013 年先後開始快速發展,那個時候的 Android 工程師和 iOS 工程師就像如今的人工智能工程師同樣很是搶手,不少同窗也是那時候從後端轉行到 App 開發的。

 

Hybrid App

原生 App 很好的解決了用戶體驗問題,但業務和技術也在發展,移動互聯網此時已經成爲明確的大趨勢,團隊須要考慮的不是要不要轉移動互聯網的問題,而是要考慮如何在移動互聯網更具競爭力的問題,所以各類基於移動互聯網特色的功能和體驗方式不斷被創造出來,你們拼的競爭方式就是看誰更快抓住用戶需求和痛點。所以,移動開發的複雜度又回到了「快速開發」,這時就發現了原生 App 開發的痛點:因爲 Android、iOS、Windows Phone(你沒看錯,當年確實是這三個主流平臺)的原生開發徹底不能兼容,一樣的功能須要三個平臺重複開發,每一個平臺還有一些差別,所以天然快不起來。

爲了解決「快速開發」的複雜度問題,你們天然又想到了 Web 的方式,但 Web 的體驗仍是遠遠不如原生,怎麼解決這個問題呢?其實沒有辦法完美解決,但能夠根據不一樣的業務要求選取不一樣的方案,例如對體驗要求高的業務採用原生 App 實現,對體驗要求不高的能夠採用 Web 的方式實現,這就是 Hybrid App 架構的核心設計思想,主要遵循架構設計的「合適原則」。

 

組件化 & 容器化

Hybrid App 可以較好的平衡「用戶體驗」和「快速開發」兩個複雜度問題(注意是「平衡」,不是「同時解決」),但對於一些超級 App 來講,隨着業務規模愈來愈大、業務愈來愈複雜,雖然在用戶看來多是一個 App,但事實上承載了幾十上百個業務。

以手機淘寶爲例,阿里確認「All in 無線」戰略後,手機淘寶定位爲阿里集團移動端的「航空母艦」,上面承載了很是多的子業務,下圖是淘寶的首頁第一屏,相關的子業務初步估計就有 10 個以上。

相關文章
相關標籤/搜索