コンピュータ システムのパフォーマンスが継続的に向上し、ハードウェア コストが継続的に削減されているため、現代のコンピューティングの分野では分散システムの重要性がますます高まっています。これに伴い、分散コンピューティングの需要は拡大し続けており、分散システムの調整および管理ソリューションの重要性が増しています。
分散調整を実現するソリューションは数多くありますが、ZooKeeper は人気のあるソリューションの 1 つです。 ZooKeeper は Apache Hadoop プロジェクトのサブプロジェクトの 1 つで、信頼性の高い分散調整サービスを提供し、アプリケーション開発者が分散システムを実装しやすくします。
Java API 開発における分散調整に ZooKeeper を使用することが話題になっています。この記事では、ZooKeeper の基本概念をいくつか説明し、Java での分散調整に ZooKeeper を使用する方法を説明する実践的な例を示します。
ZooKeeper の概要
ZooKeeper は、分散アプリケーションを調整するために設計された分散サービスです。 ZooKeeper の主な目的は、開発者がアプリケーションの作成に集中できるように、比較的シンプルな調整サービスを提供することです。
ZooKeeper には次の特徴があります。
ZooKeeper の基本操作
ZooKeeper を分散調整に使用する場合、最も一般的に使用される操作は、ノードの作成、ノードの読み取り、およびノードのステータスの監視です。
ノードの作成
ノードを作成するには、ノード パスとノード データを指定する必要があります。ノードは ZooKeeper サービスにサブディレクトリとして追加されます。作成されたノードが一時ノードの場合、そのノードを作成したクライアントと ZooKeeper サービスの間の接続が有効である限り、そのノードにアクセスできます。
以下は、ZooKeeper API を使用してノードを作成するためのサンプル コードです:
ZooKeeper zk = new ZooKeeper("localhost:2181", 3000, null); String nodePath = "/testNode"; byte[] data = "nodeData".getBytes(); CreateMode createMode = CreateMode.EPHEMERAL; zk.create(nodePath, data, ZooDefs.Ids.OPEN_ACL_UNSAFE, createMode);
ノードの読み取り
ZooKeeper を使用してノードの内容を読み取り、取得できます。 API。以下は、Java API を使用してノードを読み取るためのサンプル コードです。
ZooKeeper zk = new ZooKeeper("localhost:2181", 3000, null); String nodePath = "/testNode"; byte[] data = zk.getData(nodePath, false, null);
ノードの監視
ノードを監視すると、クライアントにノードの変更が通知されるため、ノードのステータスを更新できます。以下は、ZooKeeper API を使用してノードを監視するためのサンプル コードです。
ZooKeeper zk = new ZooKeeper("localhost:2181", 3000, null); String nodePath = "/testNode"; Watcher watcher = new Watcher() { public void process(WatchedEvent event) { // do something } }; byte[] data = zk.getData(nodePath, watcher, null);
分散調整に ZooKeeper を使用する例
次の例では、ZooKeeper API を使用して単純な分散アプリケーションを実装します。 、アプリケーションは、複数のプロセスがリーダーになるために競合する単純なリーダー選出プロトコルを実装します。この場合、ZooKeeper のエフェメラル ノードを使用してリーダー選出機能を実装します。
以下はサンプル コードです:
import java.util.List; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.ZooDefs; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.KeeperException.NodeExistsException; import org.apache.zookeeper.data.Stat; public class LeaderElection implements Watcher { String znode = "/leader_election"; ZooKeeper zk; String serverId = Integer.toHexString((int)(Math.random() * 1000000)); boolean isLeader = false; public void start() throws Exception{ String serverPath = znode + "/" + serverId; zk = new ZooKeeper("localhost:2181", 3000, this); while(zk.getState() == ZooKeeper.States.CONNECTING){ Thread.sleep(500); } while(true){ try{ // create the node with EPHEMERAL and SEQUENTIAL flags zk.create(serverPath, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL); isLeader = true; doLeaderAction(); break; } catch (NodeExistsException e){ isLeader = false; break; } catch (InterruptedException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } } public void stop() throws Exception{ zk.close(); } void doLeaderAction() throws Exception { System.out.println("Becoming leader: " + serverId); try { Thread.sleep(6000); } catch (InterruptedException e) { System.err.println("Interrupted while " + "sleeping during leadership."); Thread.currentThread().interrupt(); } finally { try { System.out.println("Ending leader: " + serverId); } catch (Exception e) { System.err.println("Error ending leadership."); } } } public void process(WatchedEvent e){ System.out.println(e.toString() + ", " + serverId); try { electLeader(); } catch (Exception ex) { ex.printStackTrace(); } } void electLeader() throws Exception { Stat predecessorStat = null; String predecessor = null; List<String> children = zk.getChildren(znode, false); //(watcher not needed for this operation) int currentId = Integer.parseInt(serverId, 16); for(String child : children){ int childId = Integer.parseInt(child, 16); if(childId < currentId) { if(predecessorStat == null){ predecessor = child; predecessorStat = zk.exists(znode + "/" + child, true); } else { Stat stat = zk.exists(znode + "/" + child, true); if(stat.getMzxid() < predecessorStat.getMzxid()){ predecessor = child; predecessorStat = stat; } } } } if(predecessor == null){ System.out.println("No active group members, " + serverId + " as leader."); //...provisional leader code here } else{ // watch the predecessor node waiting for it to go // ...down or to receive a message that it is was elected leader too. System.out.println("Watching group member with higher ID: " + predecessor); } } public static void main(String[] args) throws Exception { LeaderElection election = new LeaderElection(); election.start(); } }
上記のサンプル コードでは、まず、リーダー選挙に参加するすべてのプロセスの参加ステータスを維持するために使用される znode サブディレクトリを作成します。次に、特定のアクターを表す一時的に順序付けされた ZooKeeper ノードを作成します。前に述べたように、ZooKeeper はクライアントと Zk 値の間に 1 回限りの接続を確立します。この一時ノードを作成した後、クライアント接続が失われると、ノードは削除されます。したがって、プロセスがノードの確立時に同じノード名のノードがすでに存在していることが判明した場合、そのプロセスはリーダーにはなりません。
クライアントが一時ノードの作成に成功すると、クライアントがリーダーになります。ここで、リーダーが実行するアクションを表す doLeaderAction() メソッドを呼び出すことができます。この例では、リーダーは 6 秒間の単純な操作を実行します。
クライアント接続が失われた場合、またはエラーが発生した場合、プロセスは既存のディレクトリの下のノードを検証し、どのノードが新しいリーダーになるかを決定します。
結論
分散調整と管理は、現代のコンピューティングの分野で最も重要な問題の 1 つであり、分散システムのアプリケーションはますます普及しています。 ZooKeeper は、開発者が分散システムを簡単に実装できるようにする人気のソリューションです。 Java API 開発では、分散調整に ZooKeeper を使用する主な操作には、ノードの作成、ノードの読み取り、ノードのステータスの監視が含まれます。この記事のサンプル コードを通じて、ZooKeeper を使用してリーダー選出プロトコルとその他の分散調整スキームを Java で実装する方法を確認できます。
以上がJava API 開発における分散調整のための ZooKeeper の使用の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。