1. ZooKeeperソース構造のマクロ分析
以下に示すように、ZooKeeperマクロ分析のソースコード:
ソースコードを分析するには、まずZooKeeper構造マクロ全体を分析する必要がありますZooKeeperは、サーバークラスターとクライアントの2つの部分に分かれていることを知っている必要があります。
サーバー:
- 各ZooKeeperサーバーには、初期化、実行、およびシャットダウンの3つの状態があります。したがって、サーバーがすべて実行してzookeeperクラスターを形成している場合、外部サービスを提供できます(単一のマシンも実行できます)。
- サーバーはサービスを開始した後、初期化して使用可能なクラスターを形成します。
クライアントの場合:
- クライアントはAPI操作レイヤーをカプセル化するため、すべてのアクセスは同じAPIに基づいています。
- クライアントのAPIは、メッセージプロトコルをカプセル化するために特定のプロトコルに従う必要があります。
- ネットワーク通信は、シリアライズ、デシリアライズ、接続確立を実現する必要があります。
もちろん、クライアントによって提供されるプロトコルのカプセル化、シリアライゼーション/デシリアライゼーション、および接続確立のこの部分も、サーバーによって提供される必要があります。表示する疑似サーバーを作成することにより、リクエストを傍受できます。コードは次のとおりです。
パブリック クラスSoecktLister { public static void main(String [] args)throws Exception { ServerSocket serverSocket = new ServerSocket(2181 ); ソケットの受け入れ = serverSocket.accept(); バイト []結果= 新しい バイト [2048 ]; accept.getInputStream()。read(result); ByteBuffer bb = ByteBuffer.wrap(result); ByteBufferInputStream bbis = new ByteBufferInputStream(bb); BinaryInputArchive bia =BinaryInputArchive.getArchive(bbis); RequestHeader header2 = new RequestHeader(); header2.deserialize(bia、 "header" ); System.out.println(header2); bbis.close(); } }
次に、クライアントを介してアクセスします。
パブリック クラスZooKeeperTest { プライベートZooKeeper zooKeeper; public ZooKeeperTest(){ try { zooKeeper = new ZooKeeper( "localhost:2181" 、 5000 、 null、false ); } catch (IOException e){ e.printStackTrace(); } } public void add(String path、String data){ try { String newPath =zooKeeper.create(path、data.getBytes()、ZooDefs.Ids.OPEN_ACL_UNSAFE、CreateMode.PERSISTENT); } catch (KeeperException e){ e.printStackTrace(); } catch (InterruptedException e){ e.printStackTrace(); } } public static void main(String [] args){ ZooKeeperTest zooKeeperTest = new ZooKeeperTest(); zooKeeperTest.add( "/ monkey2"、 "2019" ); } }
したがって、サーバーはリクエストを受信できます。
RequestHeader {protocolVersion = 45、lastZxidSeen = 0、timeOut = 0、sessionId = 21474836480000、passwd = []}
実際、これらのコンテンツは、単純な要求メッセージのプロトコルパッケージです。
第二に、サーバーのソースコード分析
1.サーバーの初期化
ZooKeeper起動スクリプト./zkServer.sh start -server ip:portに従って、スクリプトを開いてサーバー起動エントリを確認します:org.apache.zookeeper.server.quorum.QuorumPeerMain。
注:サーバーのデータストレージ構造は、org.apache.zookeeper.server.DataTreeです。dataTreeはZKDataBasseに配置されます。
サーバーが起動すると、構成ファイルzoo.cfg、データの読み込み、通信の確立、リーダーの選出が順番に読み込まれます。コードは次のとおりです。
@Override public synchronized void start(){ if(!GetView()。ContainsKey(myid)){ throw new RuntimeException( "My id" + myid + "not in the peer list" ); } loadDataBase(); // ロードデータznodeデータの読み込み:(データディレクトリの下の)ハードディスクスナップショットファイルを読み取り ますstartServerCnxnFactory(); // ネットワーク通信の確立を 試行{ adminServer.start(); } catch (AdminServerException e){ LOG.warn( "Problem starting AdminServer" 、e ); System.out.println(e); } startLeaderElection(); // Election startJvmPauseMonitor(); super .start(); //スレッド実行メソッドを今すぐ呼び出す }
注:コードなど、これを呼び出す前に構成がロードされています。
public void runFromConfig(QuorumPeerConfig config)はIOException、AdminServerExceptionをスローします{ try { ManagedUtil.registerLog4jMBeans(); } catch (JMException e){ LOG.warn( "Unable to register log4j JMX control" 、e); } LOG.info( "開始クォーラムピア" ); MetricsProvider metricsProvider; { metricsProvider = MetricsProviderBootstrap.startMetricsProvider(config.getMetricsProviderClassName( )、config.getMetricsProviderConfiguration ());を試してください。 }catch (MetricsProviderLifeCycleException error){ throw new IOException( "Cannot boot MetricsProvider" + config.getMetricsProviderClassName ()、error); } { ServerMetrics.metricsProviderInitialized(metricsProvider);を試してください。 ServerCnxnFactory cnxnFactory = null ; ServerCnxnFactory secureCnxnFactory = null ; if( config.getClientPortAddress()!= null ){ cnxnFactory = ServerCnxnFactory.createFactory(); cnxnFactory.configure(config.getClientPortAddress()、config.getMaxClientCnxns()、config.getClientPortListenBacklog()、false ); } if( config.getSecureClientPortAddress()!= null ){ secureCnxnFactory = ServerCnxnFactory.createFactory(); secureCnxnFactory.configure(config.getSecureClientPortAddress()、config.getMaxClientCnxns()、config.getClientPortListenBacklog()、true ); } quorumPeer = getQuorumPeer(); quorumPeer.setTxnFactory(new FileTxnSnapLog(config.getDataLogDir()、config.getDataDir())); quorumPeer.enableLocalSessions(config.areLocalSessionsEnabled())。 quorumPeer.enableLocalSessionsUpgrading(config.isLocalSessionsUpgradingEnabled())。 // quorumPeer.setSyncLimit(config.getSyncLimit())。quorumPeer.setQuorumPeers(config.getAllMembers())。 quorumPeer.setElectionType(config.getElectionAlg())。 quorumPeer.setMyid(config.getServerId())。 quorumPeer.setTickTime(config.getTickTime())。 quorumPeer.setMinSessionTimeout(config.getMinSessionTimeout())。 quorumPeer.setMaxSessionTimeout(config.getMaxSessionTimeout())。 quorumPeer.setInitLimit(config.getInitLimit())。 quorumPeer.setConnectToLearnerMasterLimit(config.getConnectToLearnerMasterLimit())。 quorumPeer.setObserverMasterPort(config.getObserverMasterPort())。 quorumPeer.setConfigFileName(config.getConfigFilename())。 quorumPeer.setClientPortListenBacklog(config.getClientPortListenBacklog())。 quorumPeer.setZKDatabase(新ZKDatabase(quorumPeer.getTxnFactory())); quorumPeer.setQuorumVerifier(config.getQuorumVerifier()、偽); もし(config.getLastSeenQuorumVerifier()!= nullの){ quorumPeer.setLastSeenQuorumVerifier(config.getLastSeenQuorumVerifier()、偽); } QuorumPeer.initConfigInZKDatabase()。 quorumPeer.setCnxnFactory(cnxnFactory); quorumPeer.setSecureCnxnFactory(secureCnxnFactory)。 quorumPeer.setSslQuorum(config.isSslQuorum())。 quorumPeer.setUsePortUnification(config.shouldUsePortUnification()); quorumPeer.setLearnerType(config.getPeerType()); quorumPeer.setSyncEnabled(config.getSyncEnabled()); quorumPeer.setQuorumListenOnAllIPs(config.getQuorumListenOnAllIPs()); if (config.sslQuorumReloadCertFiles){ quorumPeer.getX509Util()。enableCertFileReloading(); } // クォーラムsasl認証構成を設定します quorumPeer.setQuorumSaslEnabled(config.quorumEnableSasl); if (quorumPeer.isQuorumSaslAuthEnabled()){ quorumPeer.setQuorumServerSaslRequired(config.quorumServerRequireSasl); quorumPeer.setQuorumLearnerSaslRequired(config.quorumLearnerRequireSasl); quorumPeer.setQuorumServicePrincipal(config.quorumServicePrincipal); quorumPeer.setQuorumServerLoginContext(config.quorumServerLoginContext); quorumPeer.setQuorumLearnerLoginContext(config.quorumLearnerLoginContext); } quorumPeer.setQuorumCnxnThreadsSize(config.quorumCnxnThreadsSize); quorumPeer.initialize(); if (config.jvmPauseMonitorToRun){ quorumPeer.setJvmPauseMonitor(new JvmPauseMonitor(config)); } quorumPeer.start()。 //現時点では、quorumPeerのstartメソッドを呼び出すのではなく、quorumPeerスレッドを開始します。実際のスレッドは、super.start()のstartメソッドで開始されます quorumPeer.join(); //サーバーが初期化を完了するのを待ちます } キャッチ(例外:InterruptedException E){ // 一般的に、警告しかし、このIS OK LOG.warn( "クォーラムがピアの中断"、E); } 最後に{ IF(metricsProvider =!ヌル){ 試み{ metricsProvider.stop(); } キャッチ( スロー可能なエラー){ LOG.warn( "メトリックの停止中のエラー"、エラー); } } } }
サーバー起動の詳細なプロセスを次の図に示します。
2.サーバー要求応答
次に、次の図に示すように、サーバーはサービス応答要求を外部に提供します(応答書き込み操作)。
上記のプロセスはZooKeeperのZab整合性プロトコルに準拠しています。Zabプロトコルの正式名称はZookeeper Atomic Broadcast(Zookeeper Atomic Broadcast)です。ZookeeperはZabプロトコルを使用して、分散トランザクションの最終的な整合性を保証します。
ザブ合意と選挙規則の詳細については、以下を参照してください。
3、クライアントのソースコード分析
1.クライアントの初期化
クライアントの起動プロセスは次のとおりです。
最初に、クライアントはクラスター分析とネットワーク初期化(ClientCncxオブジェクト)を実行します。同時に、ClientCncxオブジェクトは、リクエスト/レスポンスとウォッチャーイベントを管理するために、SendThreadとEventThreadの2つのスレッドを作成します。コードは次のとおりです。
public ClientCnxn( String chrootPath、 HostProvider hostProvider、 int sessionTimeout、 ZooKeeper zooKeeper、 ClientWatchManager watcher、 ClientCnxnSocket clientCnxnSocket、 long sessionId、 byte [] sessionPasswd、 boolean canBeReadOnly){ this .zooKeeper = zooKeeper; this .watcher = watcher; this .sessionId = sessionId; this .sessionPasswd = sessionPasswd; this .sessionTimeout = sessionTimeout; この.hostProvider = hostProvider; this .chrootPath = chrootPath; connectTimeout = sessionTimeout / hostProvider.size(); readTimeout = sessionTimeout * 2/3 ; readOnly = canBeReadOnly; sendThread = new SendThread(clientCnxnSocket); eventThread = new EventThread(); this .clientConfig = zooKeeper.getClientConfig(); initRequestTimeout(); } public void start(){ sendThread.start(); eventThread.start(); }
2.クライアント要求管理
クライアントがサーバーにアクセスするプロセスは次のとおりです。
上の図から、ClientCncxがSendThreadとEventThreadの2つのスレッドを開始したことがわかります。これらの2つのスレッドはサーバーからのリクエストへの応答を処理し、もう1つのスレッドはリスニングイベントを処理します。
これらの2つのスレッドは、要求管理のキューに基づいており、outGoingQueueは、要求要求を送信するためのキューを処理するために使用され、PendingQueueは、サービス応答を待機して送信された要求を格納するために使用されます。トリガーする必要があるオブジェクトなので、キューのアプリケーションはZooKeeperの高いパフォーマンスを実現します。
したがって、クライアントは主にこれらのテクノロジーを使用します。基礎となる要求管理は、キュー>キュー処理のスレッド> NIOデフォルトの通信方法>同期ロック(キューで使用)です。
クライアントとサーバーの両方が、ジュートシリアライゼーションコンポーネントと独自の通信プロトコルを使用します。詳細については、次を確認してください:
4、ZooKeeperの操作とメンテナンス
Linuxでの毎日の使用:echo zkコマンド|毎日のZooKeeperの操作と保守のためのnc ip portコマンド、次のようなもの:echo mntr | nc 192.168.0.31 2181。
Linuxのncコマンドは強力なネットワークツールで、フルネームはnetcat、オンラインインストール:yum install -y ncです。一般的なzkコマンドは次のとおりです。
もちろん、独自のコードを使用して、インターフェースの操作と保守を実装することもできます。