REVIEW
gRPCは、主に、Googleによって開発されたプロトコルの開発のベースいるProtobuf(プロトコルバッファ)配列を設計したHTTP / 2標準プロトコルに基づいて、モバイルアプリケーションのために、高性能、汎用オープンRPCフレームワークであり、言語の数の開発をサポートします。
そのプラグイン機構を介してgRPCは、この資料はgRPCロードバランシングによって定義する方法について説明インターフェイス、非常に柔軟な負荷分散、コールチェーン、ヘルスチェック、認証局と他のモジュールとすることができます。
負荷分散スキーム
加えて、RPCサービスは、モジュールをデカップリング、クロスランゲージ・コールの問題を解決するために、重要な点は、サービスのマイクロモジュールを介してである、あなたは、アプリケーション層の待ち時間を短縮、非同期を通じて、アプリケーション層サービスのRPC呼び出し複数のサービスをノード・レベルを拡張することができます。
それはRPCサービスの間のステートレスなので、あなたはそのサービス機能を拡張するために、マシンのレベルを上げることができます。しかし、どのノードそれを複数使用するには?
一般的には、フロントロードバランスのRPC(LB)に添加してもよく、LBは、対応するサービスノードの後ろハング。アプリケーション層LBへの直接アクセスは、RPCノードは、アプリケーション層には見えない、LBの後ろに隠れて。この利点は、LBアドレスとポートが大幅にアプリケーション呼び出しの複雑さを軽減し、LBアルゴリズムを気にしない、アプリケーション層、アプリケーション層に提供することができる限り、より明白です。接続-LBの再とき、あなたはバックエンドサービスを再選択することができますので、このようにして、ウェブや他の短接続されたアプリケーションは、より優れたソリューションです。
しかし、大きな問題を抱えているため、長い連動サービスのために。例えば、長いアプリケーションはリンクがRPCサービスBのバックエンドに転送LB、LBランダムに接続され、Aは長いリンクに起因して、後続のすべての要求は、あなたは負荷分散の役割を果たしていないことができ、Bに行きます。あなたは、接続が解放され、各電話を接続していない、長いリンクを維持するために、RPCと最高のサービスを考えるかもしれません。gRPCようなアセンブリは、負荷分散、負荷分散を提供していませんが、公開されたインターフェースは限り拡張するNameResolverProvider
方法は、あなたが簡単にロード・バランシングモジュールを実現することができますインターフェイスを実装するクラス。
導入に基づいてバランスをとるGRPC荷重は、をご参照くださいjuejin.im/post/5cd6e6 ...
ここでNameResolver飼育係による負荷分散を実現する方法
ZkNameResolverProvider達成
public class ZkNameResolverProvider extends NameResolverProvider {
@Override
protected boolean isAvailable() {
return true;
}
@Override
protected int priority() {
return 5;
}
@Nullable
@Override
public NameResolver newNameResolver(URI targetUri, Attributes params) {
return new ZkNameResolver(targetUri);
}
@Override
public String getDefaultScheme() {
return "zk";
}
}
复制代码
ZkNameResolver達成
public class ZkNameResolver extends NameResolver implements Watcher {
private URI zkUri;
private ZooKeeper zoo;
private Listener listener;
private final int ZK_CONN_TIMEOUT = 3000;
private final String ZK_PATH = "/grpc_server_list";
ZkNameResolver(URI zkUri) {
this.zkUri = zkUri;
}
@Override
public String getServiceAuthority() {
return zkUri.getAuthority();
}
@Override
public void start(Listener listener) {
this.listener = listener;
final CountDownLatch latch = new CountDownLatch(1);
String zkAddr = zkUri.getHost() + ":" + zkUri.getPort();
System.out.printf("connect to zookeeper server %s", zkAddr);
try {
this.zoo = new ZooKeeper(zkAddr, ZK_CONN_TIMEOUT, new Watcher() {
@Override
public void process(WatchedEvent event) {
if (event.getState() == Event.KeeperState.SyncConnected) {
latch.countDown();
}
}
});
} catch (IOException e) {
System.out.printf(e);
System.out.printf("connect to zookeeper failed, JVM exited [%s]", e.getMessage());
System.exit(1);
}
try {
latch.await();
System.out.printf("connect to zookeeper succeed");
} catch (InterruptedException e) {
System.out.printf(e);
System.out.printf("CountDownLatch interrupted, JVM exited [%s]", e.getMessage());
System.exit(1);
}
try {
Stat stat = zoo.exists(ZK_PATH, true);
if (stat == null) {
System.out.printf("%s not exists", ZK_PATH);
} else {
System.out.printf("%s exists", ZK_PATH);
}
} catch (KeeperException | InterruptedException e) {
System.out.printf(e);
}
try {
List<String> children = zoo.getChildren(ZK_PATH, this);
addServersToListener(children);
} catch (KeeperException | InterruptedException e) {
System.out.printf(e);
System.out.printf("get children of %s failed [%s], JVM exited", ZK_PATH, e.getMessage());
System.exit(1);
}
}
// 把zookeeper ZK_PATH的子节点作为rpc的节点地址,注册到gRPC负载均衡服务中
private void addServersToListener(List<String> servers) {
System.out.printf("rpc servers:%s", servers);
ArrayList<EquivalentAddressGroup> addressGroups = new ArrayList<EquivalentAddressGroup>();
for (String server : servers) {
List<SocketAddress> socketAddresses = new ArrayList<SocketAddress>();
String[] address = server.split(":");
socketAddresses.add(new InetSocketAddress(address[0], Integer.parseInt(address[1])));
addressGroups.add(new EquivalentAddressGroup(socketAddresses));
}
if (addressGroups.size() > 0) {
listener.onAddresses(addressGroups, Attributes.EMPTY);
} else {
System.out.printf("No servers find, keep looking");
}
}
@Override
public void shutdown() {
try {
zoo.close();
} catch (InterruptedException e) {
System.out.printf(e);
}
}
@Override
public void process(WatchedEvent event) {
if (event.getType() == Event.EventType.None) {
System.out.printf("Zookeeper connection expired");
} else {
try {
List<String> children = zoo.getChildren(ZK_PATH, false);
addServersToListener(children);
zoo.getChildren(ZK_PATH, true);
} catch (Exception e) {
System.out.printf(e);
}
}
}
}
复制代码
- ホストRPCサービス:飼育係のパスとしてポート(
/grpc_server_list/rpc_host:50010
)、他のイベントの削除飼育係リスニングパスを作成 - ノードは、RPCオフラインまたはオンライン、飼育係から追加または削除されたノードの動的な情報を有する場合
listener.onAddresses
gRPCに負荷分散するために登録されたRPCサービスのアドレス
チャンネルを作成します。
this.channel = ManagedChannelBuilder
// 配置zk地址
.forTarget("zk://zkhost:2181")
// 配置NameResolverProvider实现类
.nameResolverFactory(new ZkNameResolverProvider())
.enableRetry()
.maxRetryAttempts(5)
.keepAliveTime(5, TimeUnit.MINUTES)
.keepAliveWithoutCalls(true)
.keepAliveTimeout(10, TimeUnit.MINUTES)
.idleTimeout(24, TimeUnit.HOURS)
// 轮询策略
.loadBalancerFactory(RoundRobinLoadBalancerFactory.getInstance())
.usePlaintext()
.build();
复制代码
forTarget("zk://zkhost:2181")
飼育係リンクアドレスを設定しますnameResolverFactory(new ZkNameResolverProvider())
コンフィギュレーションのNameResolverProvider
実装クラスは、によってgRPCを聞かせてZkNameResolverProvider
使用可能なノードのアドレス検索サービス- 構成に基づいてRPCコールサービス、
loadBalancerFactory(RoundRobinLoadBalancerFactory.getInstance())
コール対応するポーリングバックエンドサービス戦略
概要
gRPCインターフェイスを実装することにより、非常に柔軟なロード・バランシング・インターフェースを提供し、それが簡単にロードバランシングを実現することができます。カスタム負荷分散メカニズムによって、大幅にRPCネットワークのオーバーヘッドを改善し、同時に各RPCサービスへのポーリング、拡張されたRPC応答を各RPCとの長いリンクを維持するために、発信者を確保します。飼育係によって(特定のパスを監視するためのメカニズムを見ることができる/grpc_server_list
非常に利便性のバックエンドサービスレベルの拡張を改善する、組立ラインオフに登録動的実装サービスを子ノードを追加または削除します)。
ます。https://juejin.im/post/5d0a41a65188252b8d1d45b6で再現