[原創]分散式系統之緩存的微觀應用經驗談(二) 【主從和主備高可用篇】

来源:https://www.cnblogs.com/bsfz/archive/2018/10/10/9769503.html
-Advertisement-
Play Games

第二篇這裡嘗試聊聊緩存的主從(Master-Slave),以及相關的高可用實現(High-Availability)(具體應用依然以Redis 舉例) 1.1 關於主從分離的取捨觀點 是否採用主從分離(這裡特指讀寫分離),個人目前的觀點是,它在很多場景里,並不是一個很好的方案。 我更想說的是,甚至任... ...


分散式系統之緩存的微觀應用經驗談(二) 【主從和主備高可用篇】

 

前言


  近幾個月一直在忙些瑣事,幾乎年後都沒怎麼閑過。忙忙碌碌中就進入了2018年的秋天了,不得不感嘆時間總是如白駒過隙,也不知道收穫了什麼和失去了什麼。最近稍微休息,買了兩本與技術無關的書,其一是 Yann Martel 寫的《The High Mountains of Portugal》(葡萄牙的高山),發現閱讀此書是需要一些耐心的,對人生暗喻很深,也有足夠的留白,有興趣的朋友可以細品下。好了,下麵回歸正題,嘗試寫寫工作中緩存技術相關的一些實戰經驗和思考。

 

正文


  在分散式Web程式設計中,解決高併發以及內部解耦的關鍵技術離不開緩存和隊列,而緩存角色類似電腦硬體中CPU的各級緩存。如今的業務規模稍大的互聯網項目,即使在最初beta版的開發上,都會進行預留設計。但是在諸多應用場景里,也帶來了某些高成本的技術問題,需要細緻權衡。本系列主要圍繞分散式系統中服務端緩存相關技術,也會結合朋友間的探討提及自己的思考細節。文中若有不妥之處,懇請指正。

  為了方便獨立成文,原諒在內容排版上的一點點個人強迫症。

 

  第二篇這裡嘗試聊聊緩存的主從(Master-Slave),以及相關的高可用實現(High-Availability)(具體應用依然以Redis 舉例)

  另見:分散式系統之緩存的微觀應用經驗談(一) 【基礎細節篇】(https://www.cnblogs.com/bsfz/p/9568591.html 


  一、先簡單談談主從分離(Master-Slave)

    (註:由於目前個人工作中大多數情況應用的是Redis 3.x,以下若有特性關聯,均是以此作為參照說明。)

 

    1.1 關於主從分離的取捨觀點

 

      是否採用主從分離(這裡特指讀寫分離),個人目前的觀點是,它在很多場景里,並不是一個很好的方案。

 

      我更想說的是,甚至任何涉及數據同步的環節,包括DB讀寫分離、緩存數據複製等等,如果沒有特殊場景強制要求,那麼儘量規避。

 

      雖然在互聯網的一些應用場景里,讀遠大於寫,也演變了一套看似完整的讀寫實踐方案,大體歸為“主寫從讀”、“一寫多讀”、“多讀多寫”。但本質上,在大多數環境下,均存在一定缺陷,無論是基於服務底層的數據同步延遲,還是開發中的邏輯切換,都帶來了一些可能本末倒置的隱患和生硬。同時,在集群模式下讀寫分離成本實在過高,不僅僅是一致性問題,必須慎重考慮和權衡。

 

      如果沒明白讀寫分離方案基於什麼本質什麼條件、包含哪些細節問題,那你的設計可能就很勉強,甚至出現某些關鍵問題時,反而很難去分析和解決。去年跟一前輩朋友取經,他們一個業務服務兜兜轉轉實際測出的結果是讀QPS約2000,寫QPS不到500,這些的分離哭笑不得,程式性能也沒得到優化,反而增加了完全浪費的技術成本,以及因為讀寫分離帶來的程式本不該處理的例外問題,也是折騰。

    1.2 主從分離的一些細節

      以 Redis為例,每個Redis實例(Instance)都是作為一個節點(node),並且預設主節點(master node),它們均可以手動轉換為從節點(slave node)。每個slave node只能隸屬於一個 master node, 而每個master node可以擁有n個slave node。任何主從同步都離不開複製的概念,在Redis中主要命令是 slaveof host port (指定一個master即可),這樣master node的數據將自動非同步的同步到各個slave中,這算是最基本的形態了。

      

      在進行相關軟性配置時,個人推薦最好保持配置文件(config-file)的一致,這裡指多個salve node。對於slave node的操作預設是只讀(read-only),也建議保持這個設置。如果更改為可寫許可權,那麼對slave node的修改是不會反向同步至master node中的,而且就算通過其他方式實現了反向同步,中間將大量存在類似傳統RDBMS里的幻讀問題,這裡併發不大但足夠繁瑣,追蹤到具體原因也是得不償失。(而對應程式開發中,往往寫操作也是都直接進master node執行。)

 

      另外順便提下,主從的硬體配置可以一致,但是我依然推薦slave node 可以稍微高一些。稍微註意,slave node的記憶體儘量不要小於 master node 的預算記憶體。

      對於node之間的數據延遲問題,外在因素一般都是網路I/O影響為主,CPU影響為次,換句話說,往往CPU的負載都足夠(詳見上一篇中提到的一些關聯處),而網路I/O則會比較明顯。在部署時候,沒有特殊場景,都是同機房內聯而對外隔離,但即使這樣,也需要額外註意延遲的接收程度,每次同步複製的TCP數據包,並非是真正的實時處理,這個類似於之前提到的 AOF 和 RDB 的設計思想,分為實時複製和間隔性複製,前者更及時但帶寬消耗大,而後者正好相反。在Redis中主要以 repl-disable-tcp-nodelay切換,預設使用前者,個人也較為推薦,但是在單次數據量較頻較大,業務場景的時效要求不高,完全可以設置為後者,從而節省不少性能,也連鎖提升了一定穩定性。

 

      對於拓撲結構的設計,應用最多的就是單層拓撲,針對大量類似 keys全表掃描的操作,slave node會做到分擔性能壓力的作用。如果還想極致一些,把整體阻塞降到最低,可以將拓撲結構轉換為樹狀,最簡單的做法,將某個slave node直接轉移到最底部,但會帶來更多時效上的犧牲,所以需要考慮場景的接受程度了。同時,這裡可能在具體架構落地的環節里,會比較分身乏術,需要開始考慮交由專業的運維來參與部署了,涉及上下節點間的通信、帶寬監控、級聯之間的複製問題,以及一些更獨立的高頻率統計和管理。ps下,這點一直作為備用,但在截止到目前的工作生涯里還沒有找到必要的機會去採用。

 

      對於複製/同步數據本身,無論是全量、還是增量,由於非同步性(個人認為不可能設計為同步)和一定的時效損耗,必定存在一個偏移值(offset)。以Redis舉例,master node和slave node中,各自對自己的當前複製時的offset做記錄,如果兩個角色的偏移值存在較大差異(可參考查詢對應repl_offset),那麼大概率存在頻繁的阻塞,包括網路和自身腳本命令的阻塞。一般內部網路都是專線環境,並且都是獨立部署,所以優先排查命令執行效率,和不必要的掃描問題(可參考上篇討論:https://www.cnblogs.com/bsfz/p/9568591.html)。但是無論如何,延遲或者說偏移過大的問題,總不可能完全規避,所以在開發里要麼利用專業的監控服務,要麼使用不同驅動庫定時判斷,這也無疑增加了編碼複雜度,哪怕一些開源庫已經儘力做了一些工作。

 

  二、嘗試談談相關的高可用(High-Availability)

 

    緩存既然作為一種通用的中間件(當然,某些場景里也可能是最後一層,見第一篇),決定了在諸多場景里其交互頻率(包括QPS)大多遠遠高於其他服務,這就需要其具備極高的穩定性、可用性。個人在前面闡述了一些關於主從分離的細節,下麵嘗試談談相關的HA方案和一些思考。

 

    2.1 關於高可用說明

      這裡聲明下,我認為主從分離和高可用本質上是沒有任何一絲關係的,只是有些剛剛好的作用使之結合形成了一些HA方案。

 

      前面提到過,單個相對可靠的緩存服務,除了本身所在伺服器自身的記憶體負載,設計時更需要充分考慮網路I/O、CPU的負載,以及某些場景下的磁碟I/O的代價。而這些條件全部都會擁有瓶頸,除此,你永遠無法避免的問題還有伺服器造成的直接宕機、服務自身的缺陷造成的某些時候的不可用(單點問題)等等。一套相對能夠落地的高可用緩存方案,必然還需要擁有足夠健壯的承載和相對完善的內部故障轉移機制,從而達到對外提供的是整套程式化的高可用的緩存服務。

 

    2.2 實現HA的原始步驟

      以Redis為例,其本身的設計已經足夠優秀和成熟,但在負載過大導致延遲過高、甚至崩潰的過程里,比較原始的方式是這樣去操作:將一個關聯的備用 slave node升級為 master node,可以一個 slaveof no one 基本處理。然後分析是否還做了業務層面上的主從分離,如果存在,那麼還需要手工修改其他slave node 里的舊 master node指向,映射為當前 master node。 最後,當master node 重新上線時,修改自身角色並重新加入集群。

    2.3 談談程式化HA方案的部分實踐

 

      上面提到的主幹思路看起來並不複雜,但實際以人工去操作每一個環節所需要解決的問題往往不止這些,比如對於node的不可用的判定、確認後的選舉邏輯、程式客戶端的事件通知處理、服務的同步處理細節等。在Redis中比較成熟的 HA方案,目前主要包括依賴獨立 node的 Sentinel 和自身基於 Gossip 傳播的 Cluster 方案。

    

      從巨集觀角度來談, Sentinel 和 Cluster 對於HA的設計均有互相借鑒,但後者 Cluster 更多是偏向提供一套可行性集群分片方案,與這裡主題關聯性不是很大(後續我會嘗試單獨寫一篇,這裡不延伸),圍繞 Sentinel 的HA實踐更直接。

      Sentinel 的本質邏輯就是對所有node作定期巡視,當發現存在共同投票認為不可達的 master node, 會對其做下線標識,同時進行必要的 master選舉升級,並將事件狀態返回給信號方及客戶端。Sentinel 的故障轉移是針對 master node的,通常是把 slave node作為master的一個熱備。

 

      這裡依然以Redis 3.x 為主,在 Redis Sentinel方案里,通常指 n個 Sentinel node來自動監聽Redis普通node。準確的說,每個Sentinel node 其實會監聽任何一個node,包括其他Sentinel node。

 

      對於選舉和審定的控制,可以調整配置 monitor的quorum 來確認嚴格性,比如, 在大多數場景里,設置為 (n / 2 + 1) 個,這樣代表過半的票數認同,即認為指定node當前宕機。同時,當需要選舉新的領導者master,這樣也至少是趨勢性客觀判斷。是否可以設置更小?當然可以,只是要註意的一個問題是,這樣對失敗的認定流程更短更快,但是誤差也相對越大了,需要看看場景是否適配。個人在權衡時會儘量優先設置為前者。

 

      對於內部故障轉移自然可以得到相應的事件通知,一般還可以寫入到對應執行腳本,理論上會適合自動化這塊,但個人目前尚未應用,這個偏向純運維了,個人這裡依然保持針對架構和開發來做一些討論。

 

      對於監聽通信,可以適度調整 failover-timeout等相關配置,這裡並沒有相應的計算方式,在大多數情況沒太多講究,但是也需要關註不能過度調整。個人目前採取的方式是,優先設置一個較大值,比如審定時間30秒,五個實例,那麼同步轉移超時時間則不低於150秒。

 

      對於選舉完成後,發起新的數據複製流程,由於master node會面向多個 slave node 進行瞬間同步, 預設併發複製,而很多時候伺服器環境有限,沒有很足夠的配置,甚至經常同一伺服器上存在幾個理想上本應該獨立的服務, 這裡則需要重點考慮下網路IO和磁碟IO的問題,根據實際情況臨時調整,除此之外,在高峰時這也起到了限流作用。

 

      額外再強調一下,基於主從的HA方案,依然存在 master node同步到 slave node 的延遲問題,這個基本是任何類似熱備方案均存在的問題,系統交互越是密集,或者 slave node 的不斷增加,都會明顯增大這個延遲,所以在權衡的時候,需要考慮業務的初衷,到底能夠接受到什麼程度。

 

      任何服務里的應用,都不是看起來越多越好。假如你打算手動實現一套自定義的HA方案,或者相關的熱備思路,你甚至可以考慮在業務程式里,具體點可以直接是在相關的驅動庫(比如JAVA的Jedis、和.Net的 StackExchange.Redis)修改,插入數據的同時,插入到另一個備用庫中。這在一些非緩存場景里,也有類似設計,並不是一定不被採用的,畢竟架構設計的初衷一定是考慮整體可行性和利弊權衡。

 


結語



  本篇先寫到這裡,下一篇會圍繞相關主題嘗試擴展闡述。
  PS:由於個人能力和經驗均有限,自己也在持續學習和實踐,文中若有不妥之處,懇請指正。


【預留占位:分散式系統之緩存的微觀應用經驗談(三)【集群場景篇】https://www.cnblogs.com/bsfz/

 

 



End.

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言:工作中由於公司的電腦(SSD+HDD)硬碟(HDD)突然壞了,只剩下一個系統盤(SSD)。然後就是有個比較緊急的需求正在做,申請換的新硬碟不能立刻換上,因為工作的機器不在公司,操作遠程機器工作,所以只能重新安裝部署工作環境。然後就是在安裝Git的時候出現了The drive or UNC sh ...
  • 註意:firewalld服務有兩份規則策略配置記錄,配置永久生效的策略記錄時,需要執行"reload"參數後才能立即生效: Permanent:永久生效的 RunTime:現在正在生效的 1.查看當前區域 2.查看防火牆狀態,需要註意的是,設置埠規則時防火牆必須是啟動狀態 3.配置需要開發的埠 ...
  • yum安裝jdk的好處就是不需要手動再配置環境變數,所有的變數都是自動生成 1.檢查系統是否存在jdk,存在刪除原版jdk 如果沒有信息輸出,則表示沒有安裝jdk 如果存在則執行命令刪除和卸載相關信息 2.執行命令檢索包含java的列表 3.以為我要安裝1.8版本jdk所以,我需要檢索java-1. ...
  • 伺服器端安裝 1、安裝倉庫 rpm -ivh http://repo.zabbix.com/zabbix/3.2/rhel/7/x86_64/zabbix-release-3.2-1.el7.noarch.rpm 2、安裝軟體包 yum install zabbix-server-mysql zab ...
  • 查看僵屍進程 lsof grep deleted; 用於查看已經停止但還在占用存儲的進程 ...
  • 有些用戶在把Win7/Win8.1升級到Win10正式版後,發現屏幕一直不停閃爍,以至於無法正常使用。出現這種情況的原因可能有很多,微軟社區的論壇審閱人Alex_Shen給出了一種解決方案:進入安全模式停止兩個服務。好系統官網將其提供的方法進行整理後供大家參考。 工具/原料 好系統重裝助手 具體操作 ...
  • 本文來自:https://www.breakyizhan.com/sql/5648.html1. 儲存與管理資料儲存與管理資料一直是資訊應用上最基本、也是最常見的技術。在還沒有使用電腦來管理你的資料時,你可能會使用這樣的方式來保存世界上所有的國家資料:這樣的作法在生活中是很常見的,例如親友的通訊錄,... ...
  • 看了網上好多種教程,自己嘗試失敗了好多次,最後總算弄好了,具體如下 zip下載地址:https://dev.mysql.com/downloads/mysql/ 之後點擊No thanks, just start my download. 下載之後解壓文件 然後配置環境變數,這樣可以直接在cmd中輸 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...