1. 程式人生 > >分布式系統學習筆記(一)

分布式系統學習筆記(一)

常見 算法 特征 最大 普通 部分 AR 復制 完美

1.分布式架構的發展歷史

  1.1 1946 年情人節(2.14) , 世界上第一臺電子數字計算機誕生在美國賓夕法尼亞大學大學,它的名字是:ENIAC; 這臺計算機占地 170 平米、重達 30 噸,每秒可進行 5000 次加法運算。第一臺電子計算機誕生以後,意味著一個日新月異的 IT 時代的到來。一方面單臺計算機的性能每年都在提升:從最早的8位 CPU 到現在的 64 位 CPU;從早期的 MB 級內存到現在的GB 級別內存;從慢速的機械存儲到現在的固態 SSD 硬盤存儲。

  1.2 ENIAC 之後,電子計算機便進入了 IBM 主導的大型機時代,IBM大型機之父吉恩.阿姆達爾被認為是有史以來最偉大的計算機設計師之一。1964 年 4 月 7 日,在阿姆達爾的帶領下,歷時三年,耗費50億美元,第一臺 IBM 大型機 SYSTEM/360 誕生。這使得 IBM在20 實際 50~60 年代統治整個大型計算機工業,奠定了IBM計算機帝國的江山。

  1.3 IBM大型機曾支撐美國航天登月計劃

  1.4 IBM 主機一直服務於金融等核心行業的關鍵領域

  1.5 由於高可靠性和超強的計算能力,即便在 X86 和雲計算飛速發展的情況下,IBM 的大型機依然牢牢占據著一定的高端市場份額20 世紀 80 年代,在大型機霸主的時代,計算機架構同時向兩個方向發展,以 CISC (微處理器執行的計算機語言指令集) CPU 為架構的價格便宜的面向個人的PC,以 RISC (精簡指令集計算機) CPU 為架構的價格昂貴的面向企業的小型UNIX 服務器

2.分布式架構發展的裏程碑

  2.1 大型主機的出現。憑借著大型機超強的計算和 I/O 處理能力、穩定性、安全性等,在很長一段時間內,大型機引領了計算機行業及商業計算領域的發展。而集中式的計算機系統架構也成為了主流。

  2.2 隨著計算機的發展,這種架構越來越難以適應人們的需求:

    1)由於大型主機的復雜性,導致培養一個能夠熟練運維大型主機的人的成本很高

    2)大型主機很貴,一般只有土豪(政府、金融、電信)才能用得起

    3)單點問題,一臺大型主機出現故障,那麽整個系統將處於不可用狀態。而對於大型機的使用群體來說,這種不可用導致的損失是非常大的

    4)科技在進步,技術在進步。PC 機性能不斷提升,很多企業放棄大型機改用小型機及普通 PC來搭建系統架構

3.阿裏巴巴在 2009 年發起了一項"IOE"運動

  3.1 IOE 指的是 IBM 小型機、Oracle 數據庫、EMC 的高端存儲2009 年“去 IOE”戰略透露,到 2013 年 5 月 17 日最後一臺 IBM小型機在支付寶下線。

  3.2 為什麽要去IOE?

    1)阿裏巴巴過去一直采用的是 Oracle 數據庫,並利用小型機和高端存儲設備提供高性能的數據處理和存儲服務。隨著業務的不斷發展,數據量和業務量呈爆發性增長,傳統的集中式Oracle數據庫架構在擴展性方面遭遇瓶頸。

    2)傳統的商業數據庫軟件(Oracle,DB2),多以集中式架構為主,這些傳統數據庫軟件的最大特點就是將所有的數據都集中在一個數據庫中,依靠大型高端設備來提供高處理能力和擴展性。集中式數據庫的擴展性主要采用向上擴展 (Scale up)的方式,通過增加 CPU,內存,磁盤等方式提高處理能力。這種集中式數據庫的架構,使得數據庫成為了整個系統的瓶頸,已經越來越不適應海量數據對計算能力的巨大需求。

  3.3 分布式系統的意義

    1)升級單機處理能力的性價比越來越低,單機的處理能力主要依靠 CPU、內存、磁盤。通過更換硬件做垂直擴展的方式來提升性能,成本會越來越高。

    2)單機處理能力存在瓶頸,CPU、內存都會有自己的性能瓶頸,也就是說就算你是土豪不惜成本去提升硬件,但是硬件的發展速度和性能是有限制的。

    3)穩定性和可用性這兩個指標很難達到單機系統存在可用性和穩定性的問題,這兩個指標又是我們必須要去解決的。

4.分布式架構的常見概念

  4.1 集群:單機處理到達瓶頸的時候,單機復制幾份,這樣就構成了一個“集群”。集群中每臺服務器就叫做這個集群的一個“節點”,所有節點構成了一個集群。每個節點都提供相同的服務,那麽這樣系統的處理能力就相當於提升了好幾倍(有幾個節點就相當於提升了這麽多倍)

  4.2 分布式

    1)分布式結構就是將一個完整的系統,按照業務功能,拆分成一個個獨立的子系統,在分布式結構中,每個子系統就被稱為“服務”。這些子系統能夠獨立運行在web容器中,它們之間通過RPC方式通信。

    2)系統之間的耦合度大大降低,可以獨立開發、獨立部署、獨立測試,系統與系統之間的邊界非常明確,排錯也變得相當容易,開發效率大大提升。

    3)我們可以針對性地擴展某些服務。假設這個商城要搞一次大促,下單量可能會大大提升,因此我們可以針對性地提升訂單系統、產品系統的節點數量,而對於後臺管理系統、數據分析系統而言,節點數量維持原有水平即可。

    4)服務的復用性更高。比如,當我們將用戶系統作為單獨的服務後,該公司所有的產品都可以使用該系統作為用戶系統,無需重復開發。

  4.3 節點:節點是指一個可以獨立按照分布式協議完成一組邏輯的程序個體。在具體的項目中,一個節點表示的是一個操作系統上的進程。

  4.4 副本機制:副本(replica/copy)指在分布式系統中為數據或服務提供的冗余。數據副本指在不同的節點上持久化同一份數據,當出現某一個節點的數據丟失時,可以從副本上讀取到數據。數據副本是分布式系統中解決數據丟失問題的唯一手段。服務副本表示多個節點提供相同的服務,通過主從關系來實現服務的高可用方案。

  4.5 中間件:中間件位於操作系統提供的服務之外,又不屬於應用,他是位於應用和系統層之間為開發者方便的處理通信、輸入輸出的一類軟件,能夠讓用戶關心自己應用的部分。

5.架構的發展過程

  5.1 一個成熟的大型網站系統架構並不是一開始就設計的非常完美,也不是一開始就具備高性能、高可用、安全性等特性,而是隨著用戶量的增加、業務功能的擴展逐步完善演變過來的。在這個過程中,開發模式、技術架構等都會發生非常大的變化。而針對不同業務特征的系統,會有各自的側重點,比如像淘寶這類的網站,要解決的是海量商品搜索、下單、支付等問題;

  5.2 架構的發展過程像騰訊,要解決的是數億級別用戶的實時消息傳輸;百度所要解決的是海量數據的搜索。每一個種類的業務都有自己不同的系統架構。

  5.3 我們簡單模擬一個架構演變過程。我們以 javaweb 為例,來搭建一個簡單的電商系統,從這個系統中來看系統的演變歷史;要註意的是,接下來的演示模型,關註的是數據量、訪問量提升,網站結構發生的變化。

  5.4 階段一:單應用架構,網站的初期也可以認為是互聯網發展的早起,我們經常會在單機上跑我們所有的程序和軟件。把所有軟件和應用都部署在一臺機器上,這樣就完成一個簡單系統的搭建,這個時候的講究的是效率。

技術分享圖片

  5.5 階段二:應用服務器和數據庫服務器分離,隨著網站的上線,訪問量逐步上升,服務器的負載慢慢提高,在服務器還沒有超載的時候,我們應該做好規劃,提升網站的負載能力。假如代碼層面的優化已經沒辦法繼續提高,在不提高單臺機器的性能,增加機器是一個比較好的方式,投入產出比非常高。這個階段增加機器的主要目的是講 web 服務器和數據庫服務器拆分,這樣不僅提高了單機的負載能力,也提高了容災能力。

技術分享圖片

  5.6 階段三:應用服務器集群-應用服務器負載告警,如何讓應用服務器走向集群隨著訪問量的繼續增加,單臺應用服務器已經無法滿足需求。在假設數據庫服務器還沒有遇到性能問題的時候,我們可以增加應用服務器,通過應用服務器集群將用戶請求分流到各個服務器中,從而繼續提升負載能力。此時多臺應用服務器之間沒有直接的交互,他們都是依賴數據庫各自對外提供服務,架構發展到這個階段,各種問題也會慢慢呈現

    1) 用戶請求由誰來轉發到具體的應用服務器

    2) 用戶如果每次訪問到的服務器不一樣,那麽如何維護session

技術分享圖片

  5.7 階段四:數據庫壓力變大,數據庫讀寫分離架構演變到這裏,並不是終點。上面我們把應用層的性能拉上來了,但是數據庫的負載也在慢慢增大,那麽怎麽去提高數據庫層面的負載呢?有了前面的思路以後,自然會想到增加服務器。但是假如我們單純的把數據庫一分為二,然後對於後續數據庫的請求,分別負載到兩臺數據庫服務器上,那麽一定會造成數據庫不統一的問題。所以我們一般先考慮讀寫分離的方式這個架構的變化會帶來幾個問題

    1)主從數據庫之間 的數據同步可以使用 mysql 自帶的master-slave 方式實現主從復制。

    2) 對應數據源的選擇采用第三方數據庫中間件,例如 mycat。

  技術分享圖片

  5.8 階段五:使用搜索引擎緩解讀庫的壓力數據庫做讀庫的話,嘗嘗對模糊查找效率不是特別好,像電商類的網站,搜索是非常核心的功能,即便是做了讀寫分離,這個問題也不能有效解決。那麽這個時候就需要引入搜索引擎了使用搜索引擎能夠大大提高我們的查詢速度,但是同時也會帶來一些附加的問題,比如維護索引的構建。

技術分享圖片

  5.9 階段六:引入緩存機制緩解數據庫的壓力隨著訪問量的持續增加,逐漸出現許多用戶訪問統一部分內容的情況,對於這些熱點數據,沒必要每次都從數據庫去讀取,我們可以使用緩存技術,比如 memcacheredis 來作為我們應用層的緩存;另外在某些場景下,比如我們對用戶的某些IP的訪問頻率做限制,那這個放內存中又不合適,放數據庫又太麻煩,這個時候可以使用Nosql 的方式比如 mongDB 來代替傳統的關系型數據庫。

技術分享圖片

  5.10 階段七:數據庫的水平/垂直拆分我們的網站演進的變化過程,交易、商品、用戶的數據都還在同一個數據庫中,盡管采取了增加緩存,讀寫分離的方式,但是隨著數據庫的壓力持續增加,數據庫的瓶頸仍然是個最大的問題。因此我們可以考慮對數據的垂直拆分和水平拆分垂直拆分:把數據庫中不同業務數據拆分到不同的數據庫。水平拆分:把同一個表中的數據拆分到兩個甚至跟多的數據庫中,水平拆分的原因是某些業務數據量已經達到了單個數據庫的瓶頸,這時可以采取講表拆分到多個數據庫中。

技術分享圖片

技術分享圖片

  5.11 階段八,應用的拆分隨著業務的發展,業務越來越多,應用的壓力越來越大。工程規模也越來越龐大。這個時候就可以考慮講應用拆分,按照領域模型講我們的用戶、商品、交易拆分成多個子系統。

技術分享圖片

這樣拆分以後,可能會有一些相同的代碼,比如用戶操作,在商品和交易都需要查詢,所以會導致每個系統都會有用戶查詢訪問相關操作。這些相同的操作一定是要抽象出來,否則就會是一個坑。所以通過走服務化路線的方式來解決。

技術分享圖片 

那麽服務拆分以後,各個服務之間如何進行遠程通信呢?通過 RPC 技術,比較典型的有:webservicehessianhttpRMI等等前期通過這些技術能夠很好的解決各個服務之間通信問題,but互聯網的發展是持續的,所以架構的演變和優化還在持續。

技術分享圖片

技術分享圖片

6.分布式架構演進的變化

  6.1 輸入設備的變化:在分布式系統架構中,輸入設備可以分兩類,第一類是互相連接的多個節點,在接收其他節點傳來的信息作為該節點的輸入;另一種就是傳統意義上的人機交互的輸入設備了。

  6.2 輸出設備的變化:輸出和輸入類似,也有兩種,一種是系統中的節點向其他節點傳輸信息時,該節點可以看作是輸出設備;另一種就是傳統意義上的人際交互的輸出設備,比如用戶的終端。

  6.3 控制器的變化:在單機中,控制器指的是 CPU 中的控制器,在分布式系統中,控制器主要的作用是協調或控制節點之間的動作和行為;比如硬件負載均衡器;LVS 軟負載;規則服務器等。

  6.4 運算器:在分布式系統中,運算器是由多個節點來組成的。運用多個節點的計算能力來協同完成整體的計算任務。

  6.5 存儲器:在分布式系統中,我們需要把承擔存儲功能的多個節點組織在一起,組成一個整體的存儲器;比如數據庫、rediskey-value 存儲)。

7.分布式系統的難點

  7.1 毫無疑問,分布式系統對於集中式系統而言,在實現上會更加復雜。分布式系統將會是更難理解、設計、構建和管理的,同時意味著應用程序的根源問題更難發現。

  7.2 三態:在集中式架構中,我們調用一個接口返回的結果只有兩種,成功或者失敗,但是在分布式領域中,會出現超時這個狀態。

  7.3 分布式事務:這是一個老生常談的問題,我們都知道事務就是一些列操作的原子性保證,在單機的情況下,我們能夠依靠本機的數據庫連接和組件輕易做到事務的控制,但是分布式情況下,業務原子性操作很可能是跨服務的,這樣就導致了分布式事務,例如 A B 操作分別是不同服務下的同一個事務操作內的操作,A 調 BA 如果可以清楚的知道 B 是否成功提交從而控制自身的提交還是回滾操作,但是在分布式系統中調用會出現一個新狀態就是超時,就是 A 無法知道 B 是成功還是失敗,這個時候 A是提交本地事務還是回滾呢?其實這是一個很難的問題,如果強行保證事務一致性,可以采取分布式鎖,但是那樣會增加系統復雜度而且會增大系統的開銷,而且事務跨越的服務越多,消耗的資源越大,性能越低,所以最好的解決方案就是避免分布式事務。還有一種解決方案就是重試機制,但是重試如果不是查詢接口,必然涉及到數據庫的變更,如果第一次調用成功但是沒返回成功結果,那調用方第二次調用對調用方來說依然是重試,但是對於被調用方來說是重復調用,例如 A B 轉賬,A-100,B +100,這樣會導致 A 扣了 100,而 B 增加 200。這樣的結果不是我們期望的,因此需在要寫入的接口做冪等設計。多次調用和單次調用是一樣的效果。通常可以設置一個唯一鍵,在寫入的時候查詢是否已經存在,避免重復寫入。但是冪等設計的一個前提就是服務是高可用,否則無論怎麽重試都不能調用返回一個明確的結果調用方會一直等待,雖然可以限制重試的次數,但是這已經進入了異常狀態了,甚至到了極端情況還是需要人肉補償處理。其實根據 CAP BASE 理論,不可能在高可用分布式情況下做到一致性,一般都是最終一致性保證。

  7.4 負載均衡:每個服務單獨部署,為了達到高可用,每個服務至少是兩臺機器,因為互聯網公司一般使用可靠性不是特別高的普通機器,長期運行宕機概率很高,所以兩臺機器能夠大大降低服務不可用的可能性,這正大型項目會采用十幾臺甚至上百臺來部署一個服務,這不僅是保證服務的高可用,更是提升服務的 QPS但是這樣又帶來一個問題,一個請求過來到底路由到哪臺機器?路由算法很多,有 DNS 路由,如果 session 在本機,還會根據用戶 id 或則 cookie 等信息路由到固定的機器,當然現在應用服務器為了擴展的方便都會設計為無狀態的,session 會保存到專有的 session 服務器,所以不會涉及到拿不到 session 題。那路由規則是隨機獲取麽?這是一個方法,但是據我所知,實際情況肯定比這個復雜,在一定範圍內隨機,但是在大的範圍也會分為很多個域,例如如果為了保證異地多活的多機房,誇機房調用的開銷太大,肯定會優先選擇同機房的服務,這個要參考具體的機器分布來考慮。

  7.5 一致性:數據被分散或者復制到不同的機器上,如何保證各臺主機之間的數據的一致性將成為一個難點。

  7.6 故障的獨立性:分布式系統由多個節點組成,整個分布式系統完全出問題的概率是存在的,但是在時間中出現更多的是某個節點出問題,其他節點都沒問題。這種情況下我們實現分布式系統時需要考慮得更加全面些。

分布式系統學習筆記(一)