前書き
dubboレジストリのコードは、dubbo-registryモジュールで定義されています。dubboがconsul、redis、およびzookeeperを使用してレジストリを実装できることがわかります。デフォルトはメモリに基づくレジストリであり、マルチキャストはブロードキャストに基づくレジストリです。
レジストリはRegistryServiceインターフェイスを継承し、RegistryServiceインターフェイスはレジストリの基本的な操作を定義します
public interface RegistryService {
// 注册
void register(URL url);
// 注销
void unregister(URL url);
// 订阅
void subscribe(URL url, NotifyListener listener);
// 退订
void unsubscribe(URL url, NotifyListener listener);
// 查找服务地址
List<URL> lookup(URL url);
}
サブスクライブおよびサブスクライブ解除時に、NotifyListenerインターフェイスが渡されることがわかります。サブスクリプションまたはサブスクライブ解除アクションが発生すると、このインターフェイスはドロップされます。
継承関係は次の図のようになります
。AbstractRegistryはレジストリの内容をキャッシュして、レジストリが利用できないときにサービスを正常に提供できるようにします。
登録やサブスクライブなどの操作は比較的簡単です。つまり、サービスをキャッシュに追加および削除し、対応するリスナーをキャッシュに追加および削除します。
FailbackRegistryは再試行メカニズムを追加します
レジストリはどのように作成されますか?
レジストリの作成はファクトリモデルを介して実現され、各レジストリの実現はファクトリクラスに対応します
@SPI("dubbo")
public interface RegistryFactory {
@Adaptive({
"protocol"})
Registry getRegistry(URL url);
}
特定のファクトリクラスの実装がAbstractRegistryFactoryを継承していることがわかります。AbstractRegistryFactoryが実行する操作を見てみましょう。
public Registry getRegistry(URL url) {
// 省略部分代码
// 只有一个线程创建服务注册实例
LOCK.lock();
try {
// 访问缓存
Registry registry = REGISTRIES.get(key);
if (registry != null) {
return registry;
}
//create registry by spi/ioc
// 是个抽象方法,子类来实现具体的创建过程
registry = createRegistry(url);
if (registry == null) {
throw new IllegalStateException("Can not create registry " + url);
}
REGISTRIES.put(key, registry);
return registry;
} finally {
// Release the lock
LOCK.unlock();
}
}
マルチスレッド環境で1つのレジストリのみが作成されるようにロックします。特定の作成プロセスを実装するためのサブクラスである抽象メソッドcreateRegistryがあります。
Zookeeperレジストリ
本番環境で使用できる成熟したレジストリフレームワーク
フローの説明:
- サービスプロバイダーの起動時:独自のURLアドレスを/dubbo/com.foo.BarService/providersディレクトリに書き込みます
- サービスコンシューマが開始するとき:/dubbo/com.foo.BarService/providersディレクトリのプロバイダーURLアドレスをサブスクライブします。そして、独自のURLアドレスを/dubbo/com.foo.BarService/consumersディレクトリに書き込みます
- モニタリングセンターの起動時:/dubbo/com.foo.BarServiceディレクトリにあるすべてのプロバイダーとコンシューマーのURLアドレスをサブスクライブします。
各インターフェイスノードには、次の4つの子ノードがあります(インターフェイスノードとその子ノードは永続ノードです)
ノード名 | 効果 | 子ノードが永続ノードであるかどうか |
---|---|---|
コンフィギュレータ | サービス管理用のストアオーバーライドまたは不在のURL | 番号 |
消費者 | サービスコンシューマーURL | はい |
プロバイダー | サービスプロバイダーのURL | 番号 |
ルーター | サービス管理のルーティングURLを設定する | 番号 |
コンシューマーノードは主に監視用であり、他の3つのノードはリスナーをセットアップし、変更が発生すると特定のイベントがトリガーされます
レジストリに対するZookeeperRegistry操作は、ZookeeperClientに引き渡されます。バージョン2.7.xより前は、Dubboは2つのzookeeperクライアント、zkclientとcuratorの実装をサポートしていたため、イベント監視インターフェイスを含むzookeeperの操作用に一連のAPIが抽出されました。2.7.xバージョンはキュレータークライアントのみをサポートします
public interface ZookeeperClient {
void create(String path, boolean ephemeral);
void delete(String path);
List<String> getChildren(String path);
List<String> addChildListener(String path, ChildListener listener);
void addDataListener(String path, DataListener listener);
void addStateListener(StateListener listener);
}
ZookeeperClientには、レジストリに対するすべての操作が含まれ、3種類のリスナーを定義します
- StateListener、接続ステータスを監視します
- ChildListener、ノードのすべての子ノードをリッスンします(任意のイベントを取得します)
- DataListener、このノードとその子ノードの変更を監視します(ノードの追加、削除、更新など)
AbstractZookeeperClientは、主にリスナーを追加および削除するための同時実行制御を実行します。リスナーが特定のパスに追加されている場合、それ以上追加されません。
CuratorZookeeperClientは、主にcuraotrapiを使用してzookeeperを操作します。その内部クラスCuratorWatcherImplは、curatorのイベントをdubboのイベントに変換します。
リファレンスブログ
[1] https://zhuanlan.zhihu.com/p/97300195