1. 程式人生 > >PowerJob 的自實現高可用方案,妙妙妙!

PowerJob 的自實現高可用方案,妙妙妙!

> 本文適合有 Java 基礎知識的人群 ![](https://img2020.cnblogs.com/blog/759200/202008/759200-20200811174153483-2110529700.png) 作者:HelloGitHub-**Salieri** HelloGitHub 推出的[《講解開源專案》](https://github.com/HelloGitHub-Team/Article "《講解開源專案》")系列。 ## 碎碎念 高可用放到今天已經不是一個新穎的詞彙了,怎麼實現高可用大家也已經瞭然於心。多例項部署 + 服務註冊 + 服務發現這一套組合拳打下來,實現高可用那還不是分分鐘的事情。所以很多人看到 PowerJob 的介紹頁面中寫了**任意元件支援叢集部署以實現高可用**,想當然的以為也是走了上述的那套流程。然後看到系統依賴元件時,發現......emmm...... Zookeeper 呢?沒看著。那找找 Nacos ?emmm......也沒找著......不僅沒找著,還發現文件中明明白白的寫著,**最小依賴僅為關係型資料庫**。許多使用者看到這裡就有點百思不得其解了,正常來講都會有兩個疑惑。 ![](https://img2020.cnblogs.com/blog/759200/202008/759200-20200811174206230-461704799.png) 首先,為什麼不用註冊中心呢? 要做到分散式環境下的高可用,肯定是需要服務註冊、服務發現這樣的概念的。沒有外部註冊中心,說白了就是自己去實現了一套類似的機制。那為什麼要怎麼做呢? 其實答案很簡單——成本。這個成本指的是使用者的接入成本。對於一個需要部署的重型開源專案來說,每少一個外部依賴,就多一份潛在的使用者。額外的系統依賴代表著額外的技術棧和額外的維護成本,如果企業本身沒有這一套技術體系(比如沒用到 zookeeper),而 PowerJob 又強依賴 zookeeper,那大概率只能說再見嘍~ 第一個問題解決了,接下來進入第二個問題~ ![](https://img2020.cnblogs.com/blog/759200/202008/759200-20200811174212090-1262721412.png) ## 簡單高“可用” PowerJob 系統中的基礎元件為排程伺服器 server 和執行器 worker,server 負責排程定時任務,並派發到 worker 執行,是一個典型的 C/S 架構。 C/S 架構下,如果目標是 server 和 client 可以相互聯通的“高可用”,那麼實現起來其實非常容易。 首先,啟動多個 server 應用例項,叢集部署。然後將多個 server 的 IP 地址統統填入 worker 的配置檔案中,worker 啟動時,隨機找一個 IP 進行連線,失敗則重試。一旦成功連線到某一臺 server,就開始上報自己的地址資訊。server 通過持有這個資訊也可以和 worker 進行通訊。如此一來,一個最簡單版本的“高可用”叢集就搭建完成了。但是......它真的可用嗎? ![](https://img2020.cnblogs.com/blog/759200/202008/759200-20200811174218071-918137946.png) 答案顯然是否定的(否則也不會有這篇文章了是不是~)。以上方案主要存在兩個問題: 1. 任務排程需要保證唯一性,即某個任務在某一個時刻只能被一臺機器排程,否則就會導致重複執行。而前文提及的方案中,每一臺 server 都是完全等價的,因此只能依靠分散式鎖來保證唯一性,即搶到鎖的 server 執行排程,其他 server 只能充當戰地記者,默默地邊緣 OB。這種方案下,無論部署多少臺 server,系統整體的排程效能其實是固定的,多例項部署只能做到高可用,而不能做到高效能。 2. server 無法持有完整的 worker 叢集資訊。PowerJob 的定位是**任務排程中介軟體**,旨在為企業下各部門各業務線提供精準的排程和分散式計算能力。因此肯定會有叢集分組的概念,就像 RocketMQ 中存在 ProducerGroup 和 ConsumerGroup 一樣,PowerJob 有著 AppName 的概念。一個 AppName 邏輯上對應了某個應用下的一組任務,物理上對應了這個應用所部署的叢集。為了便於 server 統一管理以及一些額外功能的實現(分散式計算),server 持有某一個 AppName 下完整的叢集資訊是一個強訴求,而前文提及的“瞎貓撞上死耗子”式方案,顯然沒辦法做到這一點。 基於以上兩點,征途是星辰大海的 PowerJob 需要探索出一種更合理、更強大的高可用架構。 ## 分組隔離 其實根據前面遇到的問題,這一套機制的雛形也差不多出來了。 server 既然需要持有某一個分組下完整的叢集資訊,那麼可以順其自然的想到,能不能讓某一個分組的所有 worker 都連線到某一臺 server 呢?一旦某個分組下所有機器全部連線到了某一臺 server,那麼其實這就形成了一個小型的子系統。雖然整個 PowerJob 系統中存在著多臺 server 和多個 worker 叢集,但是對於這個分組的執行來說,只要有這個分組對應的 worker 叢集以及它們連線的那一臺 server 就夠了。那麼在這個小型“子系統”內部,只存在著一臺 server,也就不存在重複排程問題了(server 只調度連線到它的 AppName 下面的任務就能實現這一點)。 所以,經過一層層的剝絲抽繭,問題已經轉化為了:**如何讓某個分組下的所有機器都連線到同一臺 server 上去呢?** 看到這個問題的時候,相信很多人會有和我當時一樣的想法,那就是:就這? ![](https://img2020.cnblogs.com/blog/759200/202008/759200-20200811174228020-98463098.png) “讓所有機器都連線到同一臺 server 上去,那也太簡單了吧,你只配置一個 IP 不就行了嗎?” “配置一個 IP 怎麼做高可用,怎麼利用多臺 server 資源?” “