面向服務的體系架構 SOA(三) --- Zookeeper API、zkClient API的使用

来源:https://www.cnblogs.com/bearduncle/archive/2018/03/23/8602554.html
-Advertisement-
Play Games

zookeeper簡單介紹及API使用 1.1 zookeeper簡介 zookeeper是一個針對大型分散式系統的可靠的協調系統,提供的功能包括配置維護、名字服務、分散式同步、組服務等。zookeeper可以集群複製,集群間通過zab協議來保持數據的一致性。該協議包括兩個階段:leader ele ...


zookeeper簡單介紹及API使用

1.1 zookeeper簡介

zookeeper是一個針對大型分散式系統的可靠的協調系統,提供的功能包括配置維護、名字服務、分散式同步、組服務等。zookeeper可以集群複製,集群間通過zab協議來保持數據的一致性。該協議包括兩個階段:leader election階段和Atomic broadcas階段。

leader election階段:集群間選舉出一個leader,其他的機器則稱為follower,所有的寫操作都被傳送給leader,並通過broadcas將所有的更新告訴follower,當leader崩潰或leader失去大多數的follower時,需要重新選舉出一個新的leader,讓所有的伺服器都恢復到一個正確的狀態。當leader被選舉出來且大多數伺服器完成了和leader的狀態同步後,leader election過程結束,進入Atomic broadcas階段。

Atomic broadcas階段:Atomic broadcas同步leader和follower之間的信息,保證二者具有相同的系統狀態。

zookeeper的協作過程簡化了鬆散耦合系統之間的交互,即使參與者彼此不知道對方的存在,也能夠相互發現並且完成交互。

1.2 zookeeper API簡單使用

可以認為zookeeper是一個小型的、精簡的文件系統,它的每個節點稱為znode,znode除了本身能夠包含一部分數據之外,還能擁有子節點,當節點或子節點數據發生變化時,基於watcher機制,會發出相應的通知給訂閱其狀態變化的客戶端。

1.2.1 zookeeper節點創建

maven項目中引入模塊:

<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.6</version>
</dependency>

創建zookeeper對象和節點:

 1     public static void main(String[] args) throws Exception {
 2         /*
 3          * 127.0.0.1:2181:伺服器地址
 4          * 10:超時時間
 5          * watcher:若包含boolean watch的讀方法中傳入true,則將預設watcher註冊為所關註事件的watcher
 6          * 若傳入false,則不註冊任何watcher。此處暫且定為空
 7          */
 8         ZooKeeper zookeeper = new ZooKeeper("127.0.0.1:2181", 10, null);
 9         /*
10          * 若創建的節點已經存在,則會拋出異常
11          * /root:節點路徑 ; root data:路徑包含的位元組數據
12          * Ids.OPEN_ACL_UNSAFE:訪問許可權
13          * CreateMode.PERSISTENT:節點類型
14          */
15         zookeeper.create("/root", "root data".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
16         /*
17          * 設置節點數據
18          * -1:版本號;若匹配不到響應的節點則會拋出異常
19          */
20         zookeeper.setData("/root", "hello".getBytes(), -1);
21         /*
22          * 讀取節點數據
23          * stat是節點狀態參數,讀取時會傳出該節點當前狀態信息
24          */
25         Stat stat = new Stat();
26         byte[] data = zookeeper.getData("/root", false, stat);
27         System.out.println(new String(data));
28         /*
29          * 添加子節點,若父節點不存在會拋出異常
30          */
31         zookeeper.create("/root/child", "child data".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
32         /*
33          * 判斷節點是否存在,不存在則返回的stat為null
34          */
35         Stat existsStat = zookeeper.exists("/root/child", false);
36         System.out.println(existsStat);
37         /*
38          * /root/child:刪除節點路徑
39          * -1:節點的版本號;若設置為-1,則匹配所有版本,zookeeper會比較刪除的版本和伺服器版本是否一致,不一致會拋出異常
40          */
41         zookeeper.delete("/root/child", -1);
42     }

 實際運行中最常出現這個錯誤:

Exception in thread "main" org.apache.zookeeper.KeeperException$ConnectionLossException: KeeperErrorCode = ConnectionLoss for /root
at org.apache.zookeeper.KeeperException.create(KeeperException.java:90)
at org.apache.zookeeper.KeeperException.create(KeeperException.java:42)
at org.apache.zookeeper.ZooKeeper.create(ZooKeeper.java:643)
at com.project.soa.zookeeper.ZookeeperDemo.main(ZookeeperDemo.java:12)

這是因為還未連接上zookeeper就開始添加、刪除節點等操作,為避免這種情況發生,可以在做操作時對連接狀態做判斷:

1 ZooKeeper zookeeper = new ZooKeeper("127.0.0.1:2181", 10, null);
2 if (zookeeper.getState() == States.CONNECTED) {
3 
4 }

 1.2.2 watcher的實現

節點的狀態發生變化,可以通過zookeeper的watcher機制讓客戶端取得通知。watcher的實現較為簡單,只需實現org.apache.ZooKeeper.Watcher介面即可,其中節點的狀態變化包含以下幾種狀態:

註意:watcher機制是一次性的,每次處理完狀態變化事件之後需重新註冊watcher。這也導致在處理事件和重新加上watcher這段時間發生的節點狀態無法被感知。

1.2.3 zkClient的使用

zkClient解決了watcher的一次性註冊問題,將znode的事件重新定義為子節點的變化、數據的變化、連接及狀態的變化三類,watcher執行後重新讀取數據的同時再註冊相同的watcher。在異常發生時zkClient會自動創建新的zookeeper實例進行重連,此時原來的watcher節點都將失效,可在zkClient定義的連接狀態變化的介面中進行相應處理。同時zkClient還提供了序列化和反序列化介面ZkSerializer,簡化了znode上對象的存儲。

maven中引入zkClient模塊:

<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>

簡單事例:
 1     public static void main(String[] args) {
 2         ZkClient zkClient = new ZkClient("192.168.146.132:2181");
 3         String path = "/root";
 4         zkClient.createPersistent(path);
 5         zkClient.create(path + "/child", "znode child", CreateMode.EPHEMERAL);
 6         List<String> children = zkClient.getChildren(path);
 7         System.out.println(children);
 8         int countChildren = zkClient.countChildren(path);
 9         System.out.println(countChildren);
10         System.out.println(zkClient.exists(path));
11         zkClient.writeData(path + "/child", "hello everyone");
12         Object data = zkClient.readData(path + "/child");
13         System.out.println(data);
14         zkClient.delete(path + "/child");
15         
16         //訂閱數據的變化
17         zkClient.subscribeDataChanges(path, new IZkDataListener() {
18             
19             public void handleDataDeleted(String arg0) throws Exception {
20                 
21             }
22             
23             public void handleDataChange(String arg0, Object arg1) throws Exception {
24                 
25             }
26         });
27 
28         //訂閱子節點的變化
29         zkClient.subscribeChildChanges(path, new IZkChildListener() {
30             
31             public void handleChildChange(String arg0, List<String> arg1) throws Exception {
32                 
33             }
34         });
35         
36         zkClient.subscribeStateChanges(new IZkStateListener() {
37             
38             public void handleStateChanged(KeeperState arg0) throws Exception {
39                 
40             }
41             
42             public void handleNewSession() throws Exception {
43                 // 在這裡可以進行異常發生時節點失效的容錯處理
44                 
45             }
46         });
47     }

 1.2.4 路由和負載均衡

當服務規模變大時,服務之間的依賴變得十分複雜,這時我們不僅需要瞭解服務提供方,還需要瞭解服務消費方以瞭解服務的調用情況,可以以此作為服務擴容或下線的依據。

服務消費者獲取服務提供者地址列表的部分代碼為:

 1     List<String> serverList;
 2 
 3     public List<String> getServerList() {
 4         serverList = new ArrayList<String>();
 5         String serviceName = "server - A";
 6         String serviceString = "127.0.0.1:2181";
 7         String path = "/config/" + serviceName;
 8         ZkClient zkClient = new ZkClient(serviceString);
 9         if (zkClient.exists(path)) {//服務存在則取地址列表
10             serverList = zkClient.getChildren(path);
11         } else {
12             throw new RuntimeException();
13         }
14         // 註冊監聽事件
15         zkClient.subscribeChildChanges(path, new IZkChildListener() {
16 
17             public void handleChildChange(String s, List<String> list) throws Exception {
18                 serverList = list;
19             }
20         });
21         return serverList;
22     }

先取得服務上所註冊的包含服務提供者地址的子節點,取得伺服器地址列表後便可根據負載均衡演算法選取調用伺服器,伺服器列表還存在本地以降低網路開銷。註冊監聽器來感知伺服器上線、下線和宕機事件,若發生節點改動,則將監聽方法中取得的最新子節點賦給當前的serverList。

服務提供者向zookeeper註冊服務:

 1         String path = "/config";
 2         String serverList = "127.0.0.1:2181";
 3         String serverName = "server";
 4         ZkClient zkClient = new ZkClient(serverList);
 5         if (!zkClient.exists(path)) {
 6             zkClient.createPersistent(path);//創建根節點
 7         }
 8         if (zkClient.exists(path + "/" + serverName)) {
 9             zkClient.createPersistent(path + "/" + serverName);//創建服務節點
10         }
11         //註冊當前伺服器
12         InetAddress addr = InetAddress.getLocalHost();
13         //取得本機ip
14         String ip = addr.getHostAddress().toString();
15         //創建當前伺服器節點
16         zkClient.createPersistent(path + "/" + serverName + "/" + ip);

這樣只有當配置信息更新時服務消費者才會去獲取最新的服務地址列表,其他時候使用本地緩存即可,這樣能大大降低配置中心的壓力。

1.3 HTTP服務網關

移動互聯網的崛起出現了多平臺的現狀,同樣的功能廠商需根據不同平臺開發不同的APP,使得開發成本增高。而由於客戶端APP、第三方ISV(獨立軟體開發商)應用都必須經過公共網路來發起客戶端請求,網關(gateway)作用得以凸顯。gateway接收外部各種APP的請求,經過一系列許可權與安全校驗等,根據服務名到對應配置中心選取伺服器列表,再由負載均衡演算法選取一臺伺服器進行調用,將結果返回給客戶端。

gateway可以攔截一系列惡意請求,而且能使不同的平臺共用重覆的邏輯,降低開發和運維成本。但由於gateway是整個網路的核心節點,一旦失效,依賴它的所有外部APP都將無法使用,因此在設計之初應該考慮到系統流量的監控和容量的規劃,以便在達到峰值時能夠快速進行系統擴容。

上圖是一種網關集群的架構方案,一組對等的伺服器組成網關集群接收外部HTTP請求,當流量達到警戒值,能方便地增加機器進行擴容。網關前有兩台負載均衡設備負責對網關集群進行負載均衡,設備間進行心跳檢測,一旦其中一臺宕機,另一臺則變更自己的地址接管宕機設備,平時這兩台機器均對外提供服務。


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

-Advertisement-
Play Games
更多相關文章
  • 1.1,JavaScript起源--Netscape和Sun公司 1.2,Dom,DHTML(Dynamic HTML)動態HTML 1.3,瀏覽器戰爭 1.4,最後都遵循W3C標準 1.5,WebKit(http://webkit.org)是Safari和Chrome採用的一個開源的Web瀏覽器引 ...
  • 1. 把你的代碼全部放在閉包裡面 這是我用的最多的一條。但是有時候在閉包外面的方法會不能調用。不過你的插件的代碼只為你自己的插件服務,所以不存在這個問題,你可以把所有的代碼都放在閉包裡面。而方法可能應該放在Prototype方法內部。 2. 提供插件的預設選項 你的插件應該會有一些選項是可以讓開發者 ...
  • 1. 陀螺儀deviceorientation的使用,參考《關於陀螺儀deviceorientation》https://segmentfault.com/a/1190000007183883 。 2. transform各屬性的具體使用,參考《深入理解CSS變形transform(3d)》http ...
  • 1、DOM事件綁定到父元素 2、DOM事件綁定到本身DOM上 總結: (1)事件內部的this就是綁定事件的那個DOM (2)事件處理程式內部,對象 this 始終等於 currentTarget 的值。 (3)事件處理程式內部,target 的值是實際觸發事件的真正DOM(如父節點綁定事件,其實子 ...
  • 上圖是代碼,註意,寬高只有在canvas標簽內部設置寬高,繪製的路徑顯示才是正常的;效果如下: ...
  • 設計模式(2) --簡單工廠模式 設計模式(3) --工廠方法模式 設計模式(4) --抽象工廠模式 設計模式之工廠模式 -- 簡單工廠、工廠、抽象工廠 ...
  • 1、創建mysql用戶賬號:groupadd mysqluseradd -d /sbin/nolog -g mysql -M mysql-s /sbin/nologin 表示禁止該用戶登錄,只需要角色存在即可,加強安全-g mysql 表示指定mysql用戶屬於mysql組-M 表示不創建用戶家目錄 ...
  • SpringBoot使用FastJson作為JSON格式轉換器的標準工具時,出現亂碼 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...