簡體   English   中英

gRPC 客戶端負載均衡

[英]gRPC client-side load balancing

我不確定我是否正確理解通道和客戶端負載平衡在 grpc 中的工作方式。 我根據一個教程做了所有事情。

我有幾台服務器,我想用請求 go 。 我寫了一個簡單的 NameResolverProvider。

public class BalancingNameResolverProvider extends NameResolverProvider {
    private Set<String> replicas;
    private Optional<Map<String, Object>> config;
    private String schema;
    private int priority = 5;

    public BalancingNameResolverProvider(Set<String> replicas, Optional<Map<String, Object>> config, String schema, int priority) {
        this.replicas = replicas;
        this.config = config;
        this.schema = schema;
        this.priority = priority;
    }

    @Override
    protected boolean isAvailable() {
        return true;
    }

    @Override
    protected int priority() {
        return priority;
    }

    @Override
    public NameResolver newNameResolver(URI targetUri, NameResolver.Args args) {
        List<EquivalentAddressGroup> delegates = replicas.stream()
                .map(x -> new InetSocketAddress(x.split(":")[0], Integer.parseInt(x.split(":")[1])))
                .map(EquivalentAddressGroup::new)
                .collect(Collectors.toList());

        return new NameResolver() {
            private Optional<NameResolver.ConfigOrError> parsedConfig = config.map(x ->
                    args.getServiceConfigParser().parseServiceConfig(x)
            );

            @Override
            public String getServiceAuthority() {
                return targetUri.getAuthority();
            }

            @Override
            public void shutdown() {
            }

            @Override
            public void start(final NameResolver.Listener2 listener) {
                ResolutionResult.Builder builder = ResolutionResult.newBuilder()
                        .setAddresses(delegates)
                        .setAttributes(Attributes.EMPTY);
                parsedConfig.ifPresent(builder::setServiceConfig);
                listener.onResult(builder.build());
            }
        };
    }

    @Override
    public String getDefaultScheme() {
        return schema;
    }
}

我寫了一個簡單的客戶端。

            NameResolverRegistry.getDefaultRegistry().register(resolverConfig.toProvider());
            ManagedChannel channel = NettyChannelBuilder
                    .forTarget("???") //or forAddress("???")
                    .enableRetry()
                    .usePlaintext()
                    .build();
            try {
                HelloServiceGrpc.HelloServiceBlockingStub client = HelloServiceGrpc.newBlockingStub(channel);
                for (int i = 0; i < count; i++) {
                    System.out.println(client.hello(HelloRequest.newBuilder()
                            .setFirstName("first_" + i)
                            .setLastName("lastName_" + i)
                            .build())
                            .getGreeting());
                }
            } finally {
                channel.shutdown();
            }

但是在我查看的所有手冊中,要么為通道(forAddress)指定了一個主機和端口,要么在“forTarget()”中指定了某個名稱。

但是我有幾台服務器,我怎樣才能全部指定它們?

什么時候選擇服務器? 我正確理解 NameResolverProvider 參與其中,我在其中指定了服務器列表

我使用 round_robin 策略。 也許我不需要 NameResolverProvider?

解決多個地址的最簡單方法是利用 DNS 或 /etc/hosts 文件。 默認的 DNS 名稱解析器將加載所有地址,您可以調用managedChannel.defaultLoadBalancingPolicy("round_robin")連接到所有地址,而不僅僅是第一個有效的地址。

名稱解析器由傳遞給forTarget()的目標字符串的方案選擇。 因此,如果您的解析器方案是fixed-replicas ,您將傳遞一個類似於fixed-replicas:///的字符串作為目標字符串。 如果目標字符串中沒有方案,則使用默認名稱解析器。

forAddress()是一種轉換為host:port目標字符串的便利,但具有管理 IPv6 地址的邏輯,這些地址需要百分比編碼才能在 URI 中。 僅在使用默認名稱解析器(通常為 dns)時才有用。

DnsNameResolver 使用優先級 5,您可能不想覆蓋它,因此您可能應該為您的提供者使用較低的優先級,例如 4。

創建InetSocketAddress時要小心,確保只傳遞 IP 地址。 如果您將主機名傳遞給它,它將在構造函數中執行 DNS 解析。 NameResolver 不應在調用它們的正常線程中執行 I/O 或阻塞操作。 NameResolver 可以將Args.getOffloadExecutor()用於 I/O 等。 如果您在這里使用主機名,那么您最終會將它們解析為單個 IP 地址,並且永遠不會重新解析它們,這意味着如果它們發生更改,您需要重新啟動二進制文件。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM