本文轉自:
https://blog.csdn.net/xorxos/article/details/51008080前端
架構以及我理解中架構的本質算法
在開始談我對架構本質的理解以前,先談談對今天技術沙龍主題的我的看法,千萬級規模的網站感受數量級是很是大的,對這個數量級咱們戰略上要重視它,戰術上又要藐視它。數據庫
先舉個例子感覺一下千萬級究竟是什麼數量級?如今很流行的優步(Uber),從媒體公佈的信息看,它天天接單量平均在百萬左右, 假如天天有10個小時的服務時間,平均QPS只有30左右。對於一個後臺服務器,單機的平均QPS能夠到達800-1000,單獨看寫的業務量很簡單 。
後端
爲何咱們又不能說輕視它?第一,咱們看它的數據存儲,天天一百萬的話,一年數據量的規模是多少?其次,剛纔說的訂單量,每個訂單要推送給附近的司機、司機要併發搶單,後面業務場景的訪問量每每是前者的上百倍,輕鬆就超過上億級別了。瀏覽器
今天我想從架構的本質談起以後,但願你們理解在作一些建構設計的時候,它的出發點以及它解決的問題是什麼。緩存
架構,剛開始的解釋是我從知乎上看到的。什麼是架構?有人講, 說架構並非一 個很懸乎的東西,實際上就是一個架子,放一些業務和算法,跟咱們的生活中的晾衣架很像。更抽象一點,說架構實際上是對咱們重複性業務的抽象和咱們將來業務拓展的前瞻,強調過去的經驗和你對整個行業的預見。安全
咱們要想作一個架構的話須要哪些能力?我以爲最重要的是架構師一個最重要的能力就是你要有 戰 略分解能力。這個怎麼來看呢:服務器
第一,你必需要有抽象的能力,抽象的能力最基本就是去重,去重在整個架構中體如今方方面面,從定義一個函數,到定義一個類,到提供的一個服務,以及模板,背後都是要去重提升可複用率。微信
第二, 分類能力。作軟件須要作對象的解耦,要定義對象的屬性和方法,作分佈式系統的時候要作服務的拆分和模塊化,要定義服務的接口和規範。網絡
第三, 算法(性能),它的價值體如今提高系統的性能,全部性能的提高,最終都會落到CPU,內存,IO和網絡這4大塊上。
這一頁PPT舉了一些例子來更深刻的理解常見技術背後的架構理念。
第一個例子,在分佈式系統咱們會作 MySQL分 庫 分表,咱們要從不一樣的庫和表中讀取數據,這樣的抽象最直觀就是使用模板,由於絕大多數SQL語義是相同的,除了路由到哪一個庫哪一個表,若是不使用Proxy中間件,模板就是性價比最高的方法。
第二看一下加速網絡的CDN,它是作速度方面的性能提高,剛纔咱們也提到從CPU、內存、IO、網絡四個方面來考慮,CDN本質上一個是作網絡智能調度優化,另外一個是多級緩存優化。
第三個看一下服務化,剛纔已經提到了,各個大網站轉型過程當中必定會作服務化,其實它就是作抽象和作服務的拆分。第四個看一下消息隊列,本質上仍是作分類,只不過不是兩個邊際清晰的類,而是把兩個邊際不清晰的子系統經過隊列解構而且異步化。
新浪微博總體架構是什麼樣的
接下咱們看一下微博總體架構,到必定量級的系統整個架構都會變成三層,客戶端包括WEB、安卓和IOS,這裏就不說了。
接着還都會有一個接口層, 有三個主要做用:
第一個做用,要作 安全隔離,由於前端節點都是直接和用戶交互,須要防範各類惡意攻擊;
第二個還充當着一個 流量控制的做用,你們知道,在2014年春節的時候,微信紅包,每分鐘8億屢次的請求,其實真正到它後臺的請求量,只有十萬左右的數量級(這裏的數據可能不許),剩餘的流量在接口層就被擋住了;
第三,咱們看對 PC 端和移 動 端的需求不同的,因此咱們能夠進行拆分。接口層以後是後臺,能夠看到微博後臺有三大塊:
一個是 平臺服 務,
第二, 搜索,
第三, 大數據。
到了後臺的各類服務其實都是處理的數據。 像平臺的業務部門,作的就是 數據存儲和讀 取,對搜索來講作的是 數據的 檢 索,對大數據來講是作的數據的 挖掘。微博其實和淘寶是很相似
微博其實和淘寶是很相似的。通常來講,第一代架構,基本上能支撐到用戶到 百萬 級別,到第二代架構基本能支撐到 千萬 級別都沒什麼問題,當業務規模到 億級別時,須要第三代的架構。
從 LAMP 的架構到面向服 務 的架構,有幾個地方是很是難的,首先不可能在第一代基礎上經過簡單的修修補補知足用戶量快速增加的,同時線上業務又不能停, 這是咱們常說的 在 飛 機上 換 引擎的 問題。前兩天我有一個朋友問我,說他在內部推行服務化的時候,把一個模塊服務化作完了,其餘部門就是不接。我建議在作服務化的時候,首先更可能是偏向業務的梳理,同時要找準一個很好的切入點,既有架構和服務化上的提高,業務方也要有收益,好比提高性能或者下降維護成本同時升級過程要平滑,建議開始從原子化服務切入,好比基礎的用戶服務, 基礎的短消息服務,基礎的推送服務。 第二,就是可 以作無狀 態 服 務,後面會詳細講,還有數據量大了後須要作數據Sharding,後面會將。 第三代 架構 要解決的 問題,就是用戶量和業務趨於穩步增長(相對爆發期的指數級增加),更多考慮技術框架的穩定性, 提高系統總體的性能,下降成本,還有對整個系統監控的完善和升級。
大型網站的系統架構是如何演變的
咱們經過經過數據看一下它的挑戰,PV是在10億級別,QPS在百萬,數據量在千億級別。咱們可用性,就是SLA要求4個9,接口響應最多不能超過150毫秒,線上全部的故障必須得在5分鐘內解決完。若是說5分鐘沒處理呢?那會影響你年終的績效考覈。2015年微博DAU已通過億。咱們系統有上百個微服務,每週會有兩次的常規上線和不限次數的緊急上線。咱們的挑戰都同樣,就是數據量,bigger and bigger,用戶體驗是faster and faster,業務是more and more。互聯網業務更可能是產品體驗驅動, 技 術 在 產 品 體驗上最有效的貢獻 , 就是你的性能 愈來愈好 。 每次下降加載一個頁面的時間,均可以間接的下降這個頁面上用戶的流失率。
微博的技術挑戰和正交分解法解析架構
下面看一下 第三代的 架構 圖 以及 我 們 怎麼用正交分解法 闡 述。 咱們能夠看到咱們從兩個維度,橫軸和縱軸能夠看到。 一個 維 度 是 水平的 分層 拆分,第二從垂直的維度會作拆分。水平的維度從接口層、到服務層到數據存儲層。垂直怎麼拆分,會用業務架構、技術架構、監控平臺、服務治理等等來處理。我相信到第二代的時候不少架構已
經有了業務架構和技術架構的拆分。
咱們看一下, 接口層有feed、用戶關係、通信接口;服務層,SOA裏有基層服務、原子服務和組合服務,在微博咱們只有原子服務和組合服務。原子服務不依賴於任何其餘服務,組合服務由幾個原子服務和本身的業務邏輯構建而成 ,資源層負責海量數據的存儲(後面例子會詳細講)。技 術框架解決 獨立於 業務 的海量高併發場景下的技術難題,由衆多的技術組件共同構建而成 。在接口層,微博使用JERSY框架,幫助你作參數的解析,參數的驗證,序列化和反序列化;資源層,主要是緩存、DB相關的各種組件,好比Cache組件和對象庫組件。監 控平臺和服 務 治理 , 完成系統服務的像素級監控,對分佈式系統作提早診斷、預警以及治理。包含了SLA規則的制定、服務監控、服務調用鏈監控、流量監控、錯誤異常監控、線上灰度發佈上線系統、線上擴容縮容調度系統等。
下面咱們講一下常見的設計原則。
第一個,首先是系統架構三個利器:
一個, 我 們 RPC 服 務組 件 (這裏不講了),
第二個,咱們 消息中 間 件 。消息中間件起的做用:能夠把兩個模塊之間的交互異步化,其次能夠把不均勻請求流量輸出爲勻速的輸出流量,因此說消息中間件 異步化 解耦 和流量削峯的利器。
第三個是配置管理,它是 代碼級灰度發佈以及 保障系統降級的利器
第二個 , 無狀態 , 接口 層 最重要的就是無狀 態。咱們在電商網站購物,在這個過程當中不少狀況下是有狀態的,好比我瀏覽了哪些商品,爲何你們又常說接口層是無狀態的,其實咱們把狀態從接口層剝離到了數據層。像用戶在電商網站購物,選了幾件商品,到了哪一步,接口無狀態後,狀態要麼放在緩存中,要麼放在數據庫中, 其 實 它並非沒有狀 態 , 只是在 這 個 過 程中我 們 要把一些有狀 態 的 東 西抽離出來 到了數據層。
第三個, 數據 層 比服 務層 更須要 設計,這是一條很是重要的經驗。對於服務層來講,能夠拿PHP寫,明天你能夠拿JAVA來寫,可是若是你的數據結構開始設計不合理,未來數據結構的改變會花費你數倍的代價,老的數據格式向新的數據格式遷移會讓你痛不欲生,既有工做量上的,又有數據遷移跨越的時間週期,有一些甚至須要半年以上。
第四,物理結構與邏輯結構的映射,上一張圖看到兩個維度切成十二個區間,每一個區間表明一個技術領域,這個能夠看作咱們的邏輯結構。另外,不論後臺仍是應用層的開發團隊,通常都會分幾個垂直的業務組加上一個基礎技術架構組,這就是從物理組織架構到邏輯的技術架構的完美的映射,精細化團隊分工,有利於提升溝通協做的效率 。
第五, www .sanhao.com 的訪問過程,咱們這個架構圖裏沒有涉及到的,舉個例子,好比當你在瀏覽器輸入www.sanhao網址的時候,這個請求在接口層以前發生了什麼?首先會查看你本機DNS以及DNS服務,查找域名對應的IP地址,而後發送HTTP請求過去。這個請求首先會到前端的VIP地址(公網服務IP地址),VIP以後還要通過負載均衡器(Nginx服務器),以後纔到你的應用接口層。在接口層以前發生了這麼多事,可能有用戶報一個問題的時候,你經過在接口層查日誌根本發現不了問題,緣由就是問題可能發生在到達接口層以前了。
第六,咱們說分佈式系統,它最終的瓶頸會落在哪裏呢?前端時間有一個網友跟我討論的時候,說他們的系統遇到了一個瓶頸, 查遍了CPU,內存,網絡,存儲,都沒有問題。我說你再查一遍,由於最終你不論用上千臺服務器仍是上萬臺服務器,最終系統出瓶頸的必定會落在某一臺機(多是葉子節點也多是核心的節點),必定落在CPU、內存、存儲和網絡上,最後查出來問題出在一臺服務器的網卡帶寬上。
微博多級雙機房緩存架構
接下來咱們看一下微博的Feed多級緩存。咱們作業務的時候,常常不多作業務分析,技術大會上的分享又都偏向技術架構。其實你們更多的平常工做是須要花費更多時間在業務優化上。這張圖是統計微博的信息流前幾頁的訪問比例,像前三頁佔了97%,在作緩存設計的時候,咱們最多隻存最近的M條數據。 這裏強調的就是作系統設計 要基於用 戶 的 場 景 , 越細緻越好 。舉了一個例子,你們都會用電商,電商在雙十一會作全國範圍內的活動,他們作設計的時候也會考慮場景的,一個就是購物車,我曾經跟相關開發討論過,購物車是在雙十一以前用戶的訪問量很是大,就是不停地往裏加商品。在真正到雙十一那天他不會往購物車加東西了,可是他會頻繁的瀏覽購物車。針對這個場景,活動以前重點設計優化購物車的寫場景, 活動開始後優化購物車的讀場景。
你看到的微博是由哪些部分聚合而成的呢?最右邊的是Feed,就是微博全部關注的人,他們的微博所組成的。微博咱們會按照時間順序把全部關注人的順序作一個排序。隨着業務的發展,除了跟時間序相關的微博還有非時間序的微博,就是會有廣告的要求,增長一些廣告,還有粉絲頭條,就是拿錢買的,熱門微博,都會插在其中。分發控制,就是說和一些推薦相關的,我推薦一些相關的好友的微博,我推薦一些你可能沒有讀過的微博,我推薦一些其餘類型的微博。 固然對非時序的微博和分發控制微博,實際會起多個並行的程序來讀取,最後同步作統一的聚合。這裏稍微分享一下, 從SNS社交領域來看,國內如今作的比較好的三個信息流:
微博 是 基於弱關係的媒體信息流 ;
朋友圈是基於 強 關係的信息流 ;
另一個作的比 較 好的就是今日 頭 條 , 它並非基於關係來構建信息流 , 而是基於 興趣和相關性的個性化推薦 信息流 。
信息流的聚合,體如今不少不少的產品之中,除了SNS,電商裏也有信息流的聚合的影子。好比搜索一個商品後出來的列表頁,它的信息流基本由幾部分組成:
第一,打廣告的;第二個,作一些推薦,熱門的商品,其次,纔是關鍵字相關的搜索結果。 信息流 開始的時候 很 簡單 , 可是到後期會 發現 , 你的 這個流 如何作控制分發 , 很是複雜, 微博在最近一兩年一直在作 這樣 的工做。
剛纔咱們是從業務上分析,那麼技術上怎麼解決高併發,高性能的問題?微博訪問量很大的時候,底層存儲是用MySQL數據庫,固然也會有其餘的。對於查詢請求量大的時候,你們知道必定有緩存,能夠複用可重用的計算結果。能夠看到,發一條微博,我有不少粉絲,他們都會來看我發的內容,因此 微博是最適合使用 緩 存 的系統,微博的讀寫比例基本在幾十比一。
微博使用了 雙 層緩 存,上面是L1,每一個L1上都是一組(包含4-6臺機器),左邊的框至關於一個機房,右邊又是一個機房。在這個系統中L1緩存所起的做用是什麼? 首先,L1 緩 存增長整個系 統 的 QPS, 其次 以低成本靈活擴容的方式 增長 系統 的 帶寬 。想象一個極端場景,只有一篇博文,可是它的訪問量無限增加,其實咱們不須要影響L2緩存,由於它的內容存儲的量小,但它就是訪問量大。這種場景下,你就須要使用L1來擴容提高QPS和帶寬瓶頸。
另一個場景,就是L2級緩存發生做用,好比我有一千萬個用戶,去訪問的是一百萬個用戶的微博 ,這個時候,他不僅是說你的吞吐量和訪問帶寬,就是你要緩存的博文的內容也不少了,這個時候你要考慮緩存的容量, 第二 級緩 存更多的是從容量上來 規劃,保證請求以較小的比例 穿透到 後端的 數據 庫 中 ,根據你的用戶模型你能夠估出來,到底有百分之多少的請求不能穿透到DB, 評估這個容量以後,才能更好的評估DB須要多少庫,須要承擔多大的訪問的壓力。另外,咱們看雙機房的話,左邊一個,右邊一個。 兩個機房是互 爲 主 備 , 或者互 爲熱備 。若是兩個用戶在不一樣地域,他們訪問兩個不一樣機房的時候,假設用戶從IDC1過來,由於就近原理,他會訪問L1,沒有的話纔會跑到Master,當在IDC1沒找到的時候纔會跑到IDC2來找。同時有用戶從IDC2訪問,也會有請求從L1和Master返回或者到IDC1去查找。 IDC1 和 IDC2 ,兩個機房都有全量的用戶數據,同時在線提供服務,可是緩存查詢又遵循最近訪問原理。
還有哪些多級緩存的例子呢?CDN是典型的多級緩存。CDN在國內各個地區作了不少節點,好比在杭州市部署一個節點時,在機房裏確定不止一臺機器,那麼對於一個地區來講,只有幾臺服務器到源站回源,其餘節點都到這幾臺服務器回源便可,這麼看CDN至少也有兩級。Local Cache+ 分佈式 緩 存,這也是常見的一種策略。有一種場景,分佈式緩存並不適用, 好比 單 點 資 源 的爆發性峯值流量,這個時候使用Local Cache + 分佈式緩存,Local Cache 在 應用 服 務 器 上用很小的 內存資源 擋住少許的 極端峯值流量,長尾的流量仍然訪問分佈式緩存,這樣的Hybrid緩存架構經過複用衆多的應用服務器節點,下降了系統的總體成本。
咱們來看一下 Feed 的存 儲 架構,微博的博文主要存在MySQL中。首先來看內容表,這個比較簡單,每條內容一個索引,天天建一張表,其次看索引表,一共建了兩級索引。
首先想象一下用戶場景,大部分用戶刷微博的時候,看的是他關注全部人的微博,而後按時間來排序。仔細分析發如今這個場景下, 跟一個用戶的本身的相關性很小了。因此在一級索引的時候會先根據關注的用戶,取他們的前條微博ID,而後聚合排序。咱們在作哈希(分庫分表)的時候,同時考慮了按照UID哈希和按照時間維度。很業務和時間相關性很高的,今天的熱點新聞,明天就沒熱度了,數據的冷熱很是明顯,這種場景就須要按照時間維度作分表,首先冷熱數據作了分離(能夠對冷熱數據採用不一樣的存儲方案來下降成本),其次, 很容止控制我數據庫表的爆炸。像微博若是隻按照用戶維度區分,那麼這個用戶全部數據都在一張表裏,這張表就是無限增加的,時間長了查詢會愈來愈慢。二級索引,是咱們裏面一個比較特殊的場景,就是我要快速找到這我的所要發佈的某一時段的微博時,經過二級索引快速定位。
分佈式服務追蹤系統
分佈式追蹤服務系統,當系統到千萬級之後的時候,愈來愈龐雜,所解決的問題更偏向穩定性,性能和監控。剛纔說用戶只要有一個請求過來,你能夠依賴你的服務RPC一、RPC2,你會發現RPC2又依賴RPC三、RPC4。分佈式服務的時候一個痛點,就是說一個請求從用戶過來以後,在後臺不一樣的機器之間不停的調用並返回。
當你發現一個問題的時候,這些日誌落在不一樣的機器上,你也不知道問題到底出在哪兒,各個服務之間互相隔離,互相之間沒有創建關聯。因此致使排查問題基本沒有任何手段,就是出了問題無法兒解決。
咱們要解決的問題,咱們剛纔說日誌互相隔離,咱們就要把它創建聯繫。創建聯繫咱們就有一個請求ID,而後結合RPC框架, 服務治理功能。假設請求從客戶端過來,其中包含一個ID 101,到服務A時仍然帶有ID 101,而後調用RPC1的時候也會標識這是101 ,因此須要 一個惟一的 請求 ID 標識 遞歸迭代的傳遞到每個 相關 節點。
第二個,你作的時候,你不能說每一個地方都加,對業務系統來講須要一個框架來完成這個工做, 這 個框架要 對業務 系 統 是最低侵入原 則 , 用 JAVA 的 話 就能夠用 AOP,要作到零侵入的原則,就是對全部相關的中間件打點,從接口層組件(HTTP Client、HTTP Server)至到服務層組件(RPC Client、RPC Server),還有數據訪問中間件的,這樣業務系統只須要少許的配置信息就能夠實現全鏈路監控 。爲何要用日誌?服務化之後,每一個服務能夠用不一樣的開發語言, 考慮多種開發語言的兼容性 , 內部定 義標 準化的日誌 是惟一且有效的辦法。
最後,如何構建基於GPS導航的路況監控?咱們剛纔講分佈式服務追蹤。分佈式服務追蹤能解決的問題, 若是 單一用 戶發現問題 後 , 能夠通 過請 求 ID 快速找到 發 生 問
題 的 節 點在什麼,可是並無解決如何發現問題。咱們看現實中比較容易理解的道路監控,每輛車有GPS定位,我想看北京哪兒擁堵的時候,怎麼作? 第一個 , 你確定要知
道每一個 車 在什麼位置,它走到哪兒了。其實能夠說每一個車上只要有一個標識,加上每一次流動的信息,就能夠看到每一個車流的位置和方向。 其次如何作 監 控和 報 警,咱們怎麼能瞭解道路的流量情況和負載,並及時報警。咱們要定義這條街道多寬多高,單位時間能夠通行多少輛車,這就是道路的容量。有了道路容量,再有道路的實時流量,咱們就能夠基於實習路況作預警?
對應於 分佈式系 統 的話如何構建? 第一 , 你要 定義 每一個服 務節 點它的 SLA A 是多少 ?SLA能夠從系統的CPU佔用率、內存佔用率、磁盤佔用率、QPS請求數等來定義,至關於定義系統的容量。 第二個 , 統計 線 上 動態 的流量,你要知道服務的平均QPS、最低QPS和最大QPS,有了流量和容量,就能夠對系統作全面的監控和報警。
剛纔講的是理論,實際狀況確定比這個複雜。微博在春節的時候作許多活動,必須保障系統穩定,理論上你只要定義容量和流量就能夠。但實際遠遠不行,爲何?有技術的因素,有人爲的因素,由於不一樣的開發定義的流量和容量指標有主觀性,很難全局量化標準,因此真正流量來了之後,你預先評估的系統瓶頸每每不正確。實際中咱們在春節前主要採起了三個措施:第一,最簡單的就是有降 級 的 預 案,流量超過系統容量後,先把哪些功能砍掉,須要有明確的優先級 。第二個, 線上全鏈路壓測,就是把如今的流量放大到咱們日常流量的五倍甚至十倍(好比下線一半的服務器,縮容而不是擴容),看看系統瓶頸最早發生在哪裏。咱們以前有一些例子,推測系統數據庫會先出現瓶頸,可是實測發現是前端的程序先遇到瓶頸。第三,搭建在線 Docker 集羣 , 全部業務共享備用的 Docker集羣資源,這樣能夠極大的避免每一個業務都預留資源,可是實際上流量沒有增加形成的浪費。
總結
接下來講的是如何不停的學習和提高,這裏以Java語言爲例,首先, 必定要 理解 JAVA;第二步,JAVA完了之後,必定要 理 解 JVM;其次,還要 理解 操做系統;再次仍是要了解一下 Design Pattern,這將告訴你怎麼把過去的經驗抽象沉澱供未來借鑑;還要學習 TCP/IP、 分佈式系 統、數據結構和算法。