1. 程式人生 > >python爬蟲進階(八):分散式系統的高可用與高併發處理

python爬蟲進階(八):分散式系統的高可用與高併發處理

一、應對高併發的基本思路

1、加快單機的速度,例如使用Redis,提高資料訪問頻率;增加CPU的核心數,增大記憶體;

2、增加伺服器的數量,利用叢集。

二、分散式系統的設計

1、無狀態

應用本身沒有狀態,狀態全部通過配置檔案或者叢集的服務端提供並與之同步。比如不同的機房需要讀取不同的資料來源,那麼他們直接通過配置檔案或者中心來指定。

進一步,在分散式叢集中,如果資料請求的節點可以做到沒有狀態,意味著任意節點都可以被請求,結合去中心化,就能有效避免單節點的訪問瓶頸。

2、拆分

系統設計初期,不要按功能模組來進行拆分,只需要儘快保證每個開發的單元能獨立執行,即按照多程序模式可以執行。例如搜尋引擎的業務會分為地理資訊、類別、文字等多個搜尋,在初期所有搜尋可以繼承開發在一個http請求的響應處理模組裡,初期就按照業務進行拆分,會帶來極大的工作量,各個模組能獨立並行執行即可。


系統拆分原則:

功能及業務:例如搜尋模組、地圖模組、使用者資訊模組

子功能拆分:例如搜尋模組裡,圖資料庫與文字搜尋可以分開

讀寫分離:根據讀寫的特性在進行拆分,例如淘寶的商品瀏覽與編輯,編輯是一個純寫的功能,流量是一個純讀的功能,因此可以對讀寫的實現進行拆分,一個叢集實現商品讀取的功能,而另一個規模小的多的叢集提供商品寫入的功能。

程式碼模組:一般情況,與上圖類似,一個系統可以按照Web、Service及DAO來劃分,有專門負責Web請求的,有提供進一步資料服務的模組,以及專門的資料庫HA管理模組。

3、負載均衡

如果單機不行,需要考慮使用叢集,使用叢集就意味著一個負載均衡服務提供在最前端。


負載均衡演算法:

(1)輪詢:以輪詢的方式把請求發到上游伺服器,配合weight配置實現基於權重的輪詢

(2)IP hash:根據客戶的IP做負載均衡,使得胸痛IP均衡到同一個upstream server。

(3)hash key:對客戶端的一個key進行hash,建議使用一致性Hash實現負載均衡。普通Hash演算法,當新增或刪除伺服器的時候,很多key都會被重新分配到不同的伺服器,使用一致性hash,使得只有極少數的key會被重新分配伺服器。

(4)least connection:把最新的請求負載均衡到活躍連線最少的伺服器,依然可以與權重相結合。

一致性hash:(如下左圖)

一致雜湊將每個物件對映到圓環邊上的一個點,系統再將可用的節點機器對映到圓環的不同位置。查詢某個物件對應的機器時,需要用一致雜湊演算法計算得到物件對應圓環邊上位置,沿著圓環邊上查詢直到遇到某個節點機器這臺機器即為物件應該儲存的位置。當刪除一臺節點機器時,這臺機器儲存的所有物件都要移動到下一臺機器。新增一臺機器到圓環邊上的某個點時,這個點的下一臺機器需要將這個節點前對應的物件移動到新機器上。更改物件在節點機器上的分佈可以通過調整節點機器的位置來實現。


一致性hash的平衡性:(如上右圖)

通過增加虛擬節點,使得節點的分佈及hash演算法能實現平衡。

4、服務化

當伺服器叢集設計為主從架構的時候,意味著需要有多個主伺服器提供備份和容災,這樣就要考慮使用服務的自動註冊和發現,比如使用ZooKeeper。


訊息佇列:

訊息佇列用來解耦一些不需要同步呼叫的服務或者訂閱一些通知以及系統的變化。使用訊息佇列可以實現服務解耦、非同步處理、流量緩衝等。案例:


5、databus架構

我們可以通過databus來實現MySQL資料與redis的更新操作,把MySQL的資料變化同步到redis。

6、資料異構

把一些聯合查詢的資料,直接組合成一張結果表,這樣在讀取的時候能更快速地取回結果。通常這樣的表會比較大,因此需要按照主鍵分庫分表來增加讀取的效能,帶來的問題:

(1)資料同步

(2)某一項服務的終止導致整體服務的終止

(3)聚合查詢

資料異構的實現:

(1)通過MQ機制接收資料變更,然後原子化儲存

(2)在任務佇列裡,聚合資料來源並更新

(3)聚合的資料,根據型別、例項進行分割,分割的資料還可以考慮分片


7、快取:

快取不僅僅存在於服務端,它可以被用在從最前端的任意節點,只要快取被命中,對應的資料查詢就可以得到量級的提升。

(1)客戶端快取:瀏覽器的cookie、storage,APP的本地資料儲存

(2)網路層:CDN、映象伺服器、P2P技術等

(3)服務前端:接入層的快取,應用層快取

(4)分散式快取:利用redis資料庫實現分散式的快取系統

(5)資料庫快取:當所有結果都沒命中的情況下,可以依賴資料庫的快取提高檢索排序效率

8、併發:


9、隔離:

1.保護資源,以防被其他資源拖垮

2.把不同的資料資源隔開

當海量請求傳送到前端的時候,單機的故障率會極大提高,此時一旦一臺伺服器出故障停止響應,前端反向代理會把請求傳送到叢集的其他節點,導致整體負載的進一步提升,使得所有的服務請求都被拖累,使得伺服器節點如雪崩一樣紛紛過載從而導致服務不夠用。

因此需要考慮從以下幾個維度對訪問進行隔離:

(1)資源的隔離:比如js、CSS這類訪問量極大的檔案放在CDN上

(2)熱點的隔離:一些高頻的請求和低頻的請求分開

(3)讀寫分離:分散式系統總必用的一點(保證系統高可用很重要的一點)

10、讀寫分離




MySQL中的儲存引擎InnoDB:行級鎖,事務(原子性),寫快

MySQL中的儲存引擎myisam:標記鎖,純讀效能高

11、分庫分表:

對於NoSQL的資料庫,往往天然支援分散式部署,例如HBASE、MongoDB,因此直接可以用叢集,通過分片及複製來提高響應能力

對於RDBMS,不能進行分片,所以當容量增長的時候,需要考慮分表,把舊的內容獨立出來,新建一張表儲存;當業務增長很快,可以進一步考慮把舊的歷史資料儲存到單獨的伺服器上的一個數據庫,由應用層根據請求來判斷到那個庫上讀取資料,這樣能使得熱點資料的總量以及總訪問量是一定的

分庫分表的策略:

(1)取模:按照主鍵取模後做分庫分表,缺點是按照非主鍵查詢的時候需要跨庫跨表的查詢,擴容需要建立新的叢集並進行資料遷移

(2)分割槽:例如2B的系統,每個大的客戶一張表,每個客戶下的分店可以考慮分表;根據時間或地區,進行表或資料庫的切割

12、限流:

HTTP的請求全部發送到任務佇列中,當佇列滿的時候,直接返回伺服器超時;佇列的大小按照併發處理能力來設定,使得進入佇列的請求都能在一定時間內響應


13、降級:

降級是指在服務併發突然增大的時候,啟動限制性措施,降低服務提供的能力從而保護系統性能。降級一般是在系統的介面之間,設定降級開關,在特定的時候啟用。例如前面講到為限流而做的任務緩衝佇列,可以通過降級來啟動或停用:平峰或低估期請求通過代理層直達後端;高峰期通過降級,請求都進入到佇列,由worker從佇列獲取資料來請求。

降級措施還包括針對服務級別的,例如在高峰情況下只讀快取,快取失效的情況下直接返回失敗,使得熱點的訪問能被響應,而非熱點資料請求被拒絕;微博打開個人主頁的時候,還回出現熱點推薦、廣告等,如果出現流量暴漲,可以關閉這些功能的服務介面。

降級的啟動方式:

(1)超時:資料庫、HTTP服務或者遠端呼叫超時後,可以自動觸發降級。例如淘寶的商品主頁會非同步載入價格、評論、推薦,而搶購活動時,評論和推薦都可以臨時不展示,通過超時來自動降級

(2)統計失敗次數:呼叫外部服務,例如資料來源於圖資料庫的情況,失敗次數達到一定次數的時候自動降級

(3)故障:遠端服務出錯,可以直接降級並報警

(4)限流:流量監控,超過峰值後自動開啟降級,把所有請求排隊

自動化限流降級: