分散式系統–>(關於系統應用的基本概念)
最近想了一下,個人學習使用了很多很優秀的開源技術,然後也看了一些的書籍,感覺需要去整理一下,然後分享出來,一方面是一個知識總結,第二方面是有一個知識共享,期間會寫一些關於分散式系統的基礎知識,包括分散式系統會遇到的問題,然後是各種分散式應用, 會設計到訊息佇列,搜尋引擎,甚至是各種資料庫的相關實現內容,然後給自己定一個分享計劃是,週期為每週一篇,deadline為每週二(畢竟deadline是第一生產力)
關於系統應用的基本概念
在寫其他內容之前,我感覺應該先寫一些對於系統的基本知識,然後就是我們在設計或則應用維護一個好的系統需要有哪些好的指標。
可靠性
第一個的話是可靠性,可以簡單的理解就是所有的系統都流暢正常的工作,也有一些公司會制定一些指標去固化可靠性,如SLA。每個人在不同的環境下,應該都會有自己的理解,比如說是系統一直正常執行,然後系統可以忍受一部分誤操作,系統通過限流等方式正常的拒絕一些不正常的使用者請求,也可能是系統能夠一定程度的避免一些硬體故障,如有cpu故障,記憶體條故障,網路中斷,磁碟異常等。我們可以試想一下,如果一個分散式儲存節點有1000個disk節點,那麼故障可能就是是一種常態,因為基數太大,那麼造成故障的機率假設是1/1000,那麼每天就可能有一個磁碟故障,相信類似這樣的事情在大的雲資料中心肯定是經常發生,比如aws, google coud。
還可能對可靠性有影響的就是軟體自身的bug了,肯定的是所有的軟體都會有bugs,甚至強如linux核心, mysql這樣的被嚴格驗證的系統都會有bugs, 所以這是不能被避免的,只能說我們去減少這樣的bugs異常,優化流程,減少類似異常的發生,如用完善的監控和告警,完整的工作流測試,嚴格的系統程式隔離,允許進行異常檢測和重啟等一些流程增強系統可靠性。
最後的話可能是人為的處理異常,系統都需要人去維護,需要人去控制系統的正常執行,即便是像kubernetes優秀的工具也需要人維護。可以這麼說,即便是最優秀的工程師去維護的也一定會出錯,而且許可權約大越可能會有故障。我們只能儘可能的去減少。比如減少出現異常的概率,如設計的時候提供標準的rest api控制, admin dashboard控制介面許可權,最少也要有完善的文件,這塊是非常有用的,比如像rabbitmq 提供了admin 頁面去控制整個叢集,包括使用者許可權控制,佇列控制,vhost隔離,這都簡化使用者操作,一定程度上減少認為操作導致的系統異常。
然後的話可以進行定期的進行一個演練,這個演練可以是一種系統故障模擬,測試系統是否符合預期工作,也可以讓我們更熟悉我們的操作,在一個就是提供一些能夠簡化回滾的配置檔案,或則是更容易操作的回滾工具,比如像oracle 就會資料庫回閃,如果有異常操作也能進行一個資料庫回閃。
在這一塊,現在能看到越來越多的軟體在設計的時候在考慮了可靠性,就是大家都將”服務只要執行就一定有異常的情況”當做了一種共識,所有設計的時候就考慮了分散式的情況,提高容錯率,增強可靠性,像hdfs, zookeeper, kafka, es, mongdb 等等,都有各自的機制去保證可用性,最常見的就是master-salve, 也有叫primary-secondary。
可擴充套件性
這幾乎是所有系統都會遇到的問題,想象一下,當你網站的使用者隨著時間的增長越來越多,需要的流量和資料的儲存等各項資源都在增長,那麼你怎麼去保證你係統還能一直正常工作,還保證正常的負載和響應延時。
這個問題可以很簡單的問自己,如果使用者系統增加了2倍,系統能否正常執行?
要問答這個問題,需要清楚的知道當前系統的負載和當前系統的效能瓶頸在哪。負載的話可以被定義為為,遊戲裡邊的話就是線上人數,web相關的服務qps, 資料庫的tps, 快取的命中率等,機器資源的cpu/mem的使用率等。
還有一個資料就是效能,簡單理解就是在你負載增長的情況下,在保持系統資源都不變的情況下(如cpu/mem/io等等),對系統最大的影響是什麼。然後當你增加了一些負載,你需要怎麼增加資源才能保證效能不變。比如說訊息佇列會有一些吞吐量(throughtout)的概念,即為一分鐘能夠處理的訊息量是多少,又比如說響應時間(respone-time),就是能正常響應服務的時間,還比如gc垃圾回收的效率,堆疊的使用效率等等,你怎麼去保證他們保持原來的狀態。
整個的話就是想說我們的系統設計不可能一直是不變的,一直都會是變化的的,然後我們需要設計我們的系統在保證效能的同時具有可擴充套件性,滿足我們的擴充套件需求,比如就對儲存來說,目的是就是簡單的增加磁碟,增加主機,增加資源就可達到我們的目的,開源資料庫裡邊已經有很多在軟體設計就考慮到了這些問題,如果像mongdb,es,他們是一種可擴充套件的資料庫,他們有sharding,就是將資料分散到不同的計算節點上,然後有相關程式進行路由轉發和結果匯聚,還有像kafka訊息佇列,也有資料分割槽,不同topic進行Partition, 將不同資料分散,然後滿足擴充套件性。像mysql雖然官方沒有提供很好的擴充套件方案(NDK在國內用的比較少),不過社群也做了很多基於mysql的擴充套件,像讀寫分離中介軟體,分庫分表中介軟體,maxscale, mycat, sharding-sphere等等工具。所以可擴充套件性是應用程式設計也是必不可少的。
可維護性
然後最後的話就是可維護性,這塊大家都很容易被忽視,覺得只要能用就行,其實不是這樣,這塊對我們服務也是非常重要的。因為自己也在研究很多的應用服務軟體,然後也應用了很多在公司中,對我來說,可維護性是非常重要的指標,因為這會和我的工作直接相關,想象一下,如果說我去使用一個沒有文件,沒有測試報告,沒有管理工具的軟體,這會是多麼懊惱的一件事,你要去處理所有的坑,然後出了問題也沒有很好地方式去解決,維護可能帶來很大的成本,也很容易進行誤操作,對時間的把控,和軟體的把控都不能遊刃有餘,那對系統來說就是一個很大潛在的威脅。
所有說如果你是一個研發,當你設計的軟體需要進行交付的時候,你應該去多想想,是否設計的軟體方便維護,比如是否有完善的文件,完善的部署指令碼,回滾指令碼,升級工具,系統狀態監控,服務擴容,縮容的步驟等。這樣做下來會減少你排查問題,修復問題的時間,也會提高服務的SLA。
這裡的話,推薦一個最佳比較火的容器編排工具, kubernetes, 它和ansible ,salt-statck思路不一樣,它不僅僅是一個批量控制,管理主機的工具,它還能管理你的服務,監控,甚至是修復你的服務,當服務以docker的方式的時候,理想狀態是以後你就不需要去維護了,而且更讚的是如果你設計的軟體能能水平擴充套件,那麼就更好了,它能用hpa的方式,自動的進行擴容縮容,結合雲端計算平臺的話,甚至能彈性的擴充套件底層的計算儲存網路相關資源。我是較早一批吃螃蟹的人,感覺非常不錯。
簡單整理
以上幾個指標我覺得是軟體設計中的一些基本概念,我們設計的服務軟體應該儘可能的滿足上邊的目標,對系統而言會更有幫助。同時這些也是分散式系統設計一些基本概念,有了概念這些我們才能從更好的角度去看其他優秀的分散式系統的設計思路和方法。