代码之家  ›  专栏  ›  技术社区  ›  user51

grpc客户端负载均衡失败,出现错误:警告:[Channel<1>:()]解析名称失败

  •  0
  • user51  · 技术社区  · 2 年前

    我正在尝试为我的java服务器实现grpc客户端负载平衡。 一 server 在端口6565和另一个端口上运行 server 运行在7575号港口。 除了端口之外,两台服务器的代码是相同的。

    现在我想为这些服务器实现客户端负载平衡。

    我已经 ServiceRegistry 分类如下-

    import io.grpc.EquivalentAddressGroup;
    import java.net.InetSocketAddress;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.stream.Collectors;
    
    public class ServiceRegistry {
    
        private static final Map<String, List<EquivalentAddressGroup>> MAP = new HashMap<>();
    
        public static  void register(String service, List<String> instances) {
            MAP.put(service, toEquivAddrGroup(instances));
        }
    
        public static List<EquivalentAddressGroup> getInstances(String service) {
            return MAP.get(service);
        }
        private static List<EquivalentAddressGroup> toEquivAddrGroup(List<String> instances) {
            return instances.stream().map(i -> i.split(":"))
                    .map(a -> new InetSocketAddress(a[0], Integer.parseInt(a[1])))
                    .map(EquivalentAddressGroup::new).collect(Collectors.toList());
        }
    }
    

    我的 TempNameResolver 类如下-

    import io.grpc.EquivalentAddressGroup;
    import io.grpc.NameResolver;
    import java.util.List;
    
    public class TempNameResolver extends NameResolver {
    
        private final String service;
    
        public TempNameResolver(String service) {
            this.service = service;
        }
    
        @Override
        public String getServiceAuthority() {
            return "temp";
        }
    
        @Override
        public void shutdown() {
    
        }
    
        @Override
        public void start(Listener2 listener) {
            List<EquivalentAddressGroup> addrGroups = ServiceRegistry.getInstances(this.service);
            ResolutionResult resolutionResult = ResolutionResult.newBuilder().setAddresses(addrGroups).build();
            listener.onResult(resolutionResult);
        }
    }
    

    TempNameResolverProvider 类是-

    import io.grpc.NameResolver;
    import io.grpc.NameResolverProvider;
    import java.net.URI;
    
    public class TempNameResolverProvider extends NameResolverProvider {
    
        @Override
        protected boolean isAvailable() {
            return true;
        }
    
        @Override
        protected int priority() {
            return 5;
        }
    
        @Override
        public NameResolver newNameResolver(URI targetUri, NameResolver.Args args) {
            System.out.println("Looking for service " + targetUri);
            return new TempNameResolver(targetUri.toString());
        }
    
        @Override
        public String getDefaultScheme() {
            return "dns";
        }
    }
    
    

    我的客户端代码是

    import client.DepositStreamObserver;
    import com.raj.models.*;
    import io.grpc.ManagedChannel;
    import io.grpc.ManagedChannelBuilder;
    import io.grpc.NameResolverRegistry;
    import io.grpc.stub.StreamObserver;
    import org.junit.jupiter.api.BeforeAll;
    import org.junit.jupiter.api.Test;
    import org.junit.jupiter.api.TestInstance;
    import java.util.Arrays;
    import java.util.concurrent.CountDownLatch;
    
    @TestInstance(TestInstance.Lifecycle.PER_CLASS)
    public class ClientSideLoadBalancerTest {
    
        private BankServiceGrpc.BankServiceBlockingStub bs;
        private BankServiceGrpc.BankServiceStub bss;
    
        @BeforeAll
        public void setUp() {
            ServiceRegistry.register("bank-service", Arrays.asList("localhost:6565", "localhost:7575"));
            NameResolverRegistry.getDefaultRegistry().register(new TempNameResolverProvider());
            ManagedChannel mc = ManagedChannelBuilder
    
                    //.forAddress("localhost", 8585)
                    .forTarget("bank-service")
                    .nameResolverFactory(new TempNameResolverProvider())
                    .usePlaintext()
                    .build();
            this.bs = BankServiceGrpc.newBlockingStub(mc);
            this.bss = BankServiceGrpc.newStub(mc);
        }
    
        @Test
        public void balanceTest() {
            for (int i = 0; i < 10; i++) {
                BalanceCheckRequest bcr = BalanceCheckRequest.newBuilder().setAccountNumber(i).build();
                Balance b = this.bs.getBalance(bcr);
                System.out.println("balance received " + b.getAmount());
            }
        }
    

    上面的代码运行良好。删除或注释不推荐使用的代码时 .nameResolverFactory(new TempNameResolverProvider()) 为了使全局名称解析能够工作,应用程序失败并出现以下错误-

    警告:[Channel<1>:(银行服务)]解析名称失败。status=status{code=UNAVAILABLE,description=无法解析主机银行服务,cause=java.lang.RuntimeException:java.net.UnnknownHostException:银行服务:名称解析中的临时故障 位于io.grpc.internal.DnsNameResolver.resolveAddresses(DnsNameResolver.java:223) 位于io.grpc.internal.DnsNameResolver.doResolve(DnsNameResolve.java:282) 位于io.grpc.internal.DnsNameResolver$Resolve.run(DnsNameResolve.java:318) 位于java.base/java.util.concurrent.ThreadPoolExecutiator.runWorker(ThreadPoolExecutiator.java:1136) 位于java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) 位于java.base/java.lang.Thread.run(Thread.java:833) 引起原因:java.net.UnnknownHostException:银行服务:名称解析临时失败 位于java.base/java.net.Inet6AddressImpl.lookupAllHostAddr(本机方法) 位于java.base/java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:52) 位于java.base/java.net.InetAddress$PlatformResolver.lookupByName(InetAddress.java:1048) 位于java.base/java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1638) 位于java.base/java.net.InetAddress$NameServiceAddresses.get(InetAddress.java:997) 位于java.base/java.net.InetAddress.getAllByName0(InetAddress.java:1628) 位于java.base/java.net.InetAddress.getAllByName(InetAddress.java:1494) 位于io.grpc.internal.DnsNameResolver$JdkAddressResolver.resolveAddress(DnsNameResolver.java:631) 位于io.grpc.internal.DnsNameResolver.resolveAddresses(DnsNameResolver.java:219) …还有5个 } 出现错误:不可用:无法解析主机银行服务

    UNAVAILABLE:无法解析主机银行服务 io.grpc.StatusRuntimeException:不可用:无法解析主机银行服务 在app//io.grpc.stub.ClientCalls.toStatusRuntimeException(ClientCalls.java:262) 位于app//io.grpc.stub.ClientCalls.getUnchecked(ClientCalls.java:243) 位于app//io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:156) 访问app//com.raj.models.BankServiceGrpc$BankServiceBlockingStub.getBalance(BankServiceGrpc.java:284) 位于app//client.lb.ClientSideLoadBalancerTest.balanceTest(ClientSideLoad平衡器测试.java:39) 在java.base@18/jdk.internal.reflect.DirectMethodHandleAccessor.ioke(DirectMethodHandleAccessor.java:104) 在java.base@18/java.lang.reflect.Method.ioke(Method.java:577) 位于app//org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725) 位于app//org.junit.jupiter.engine.execulation.MethodInvocation.prough(MethodInvocation.java:60) 位于app//org.junit.jupiter.engine.exexecution.InvocationInterceptorChain$ValidatingInvocation.procent(InvocationIntersectorChain.java:131) 位于app//org.junit.jupiter.engine.exextension.TimeoutExtension.incept(TimeoutExtension.java:149) 位于app//org.junit.jupiter.engine.exextension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140) 位于app//org.junit.jupiter.engine.extension.TimeoutExtension.enterceptTestMethod(TimeoutExtension.java:84) 位于app//org.junit.jupiter.engine.execulation.ExecutableInvoker$ReflectiveInterceptorCallLambda$ofVoidMethod$0(ExecutiableInvoker.java:115) 位于app//org.junit.jupiter.engine.execulation.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105) 位于app//org.junit.jupiter.engine.exexecution.InvocationInterceptorChain$InterceptedInvocation.prough(InvocationIntersectorChain.java:106) 位于app//org.junit.jupiter.engine.execulation.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) 位于app//org.junit.jupiter.engine.execulation.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) 位于app//org.junit.jupiter.engine.execulation.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) 位于app//org.junit.jupiter.engine.execulation.ExecutableInvoker.invoke(ExecutableInvoker.java:104) 位于app//org.junit.jupiter.engine.execulation.ExecutableInvoker.invoke(ExecutableInvoker.java:98) 位于app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptorLambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214) 位于app//org.junit.platform.engine.support.histrared.SthrowableCollector.execute(ThrowableCollector.java:73) 位于app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210) 位于app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135) 位于app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66) 位于app//org.junit.platform.engine.support.histrared.NodeTestTaskLambda$executeSecurive$6(NodeTestTask.java:151) 位于app//org.junit.platform.engine.support.histrared.SthrowableCollector.execute(ThrowableCollector.java:73) 位于app//org.junit.platform.engine.support.histrared.NodeTestTaskLambda$executeSecurive$8(NodeTestTask.java:141) 位于app//org.junit.platform.engine.support.histrared.Node.around(Node.java:137) 位于app//org.junit.platform.engine.support.histrared.NodeTestTaskLambda$executeSecurive$9(NodeTestTask.java:139) 位于app//org.junit.platform.engine.support.histrared.SthrowableCollector.execute(ThrowableCollector.java:73) 位于app//org.junit.platform.engine.support.histrared.NodeTestTask.executeSecurively(NodeTestTask.java:138) 在app//org.junit.platform.engine.support.histrared.NodeTestTask.execute(NodeTestTask.java:95) 在java.base@18/java.util.ArrayList.forEach(ArrayList.java:1511) 位于app//org.junit.platform.engine.support.histrared.SameThreadHierarchicalTestExecutiorService.invokeAll(SameThreadHierarchialTestExecutiorServices.java:41) 位于app//org.junit.platform.engine.support.histrared.NodeTestTaskLambda$executeSecurive$6(NodeTestTask.java:155) 位于app//org.junit.platform.engine.support.histrared.SthrowableCollector.execute(ThrowableCollector.java:73) 位于app//org.junit.platform.engine.support.histrared.NodeTestTaskLambda$executeSecurive$8(NodeTestTask.java:141) 位于app//org.junit.platform.engine.support.histrared.Node.around(Node.java:137) 位于app//org.junit.platform.engine.support.histrared.NodeTestTaskLambda$executeSecurive$9(NodeTestTask.java:139) 位于app//org.junit.platform.engine.support.histrared.SthrowableCollector.execute(ThrowableCollector.java:73) 位于app//org.junit.platform.engine.support.histrared.NodeTestTask.executeSecurively(NodeTestTask.java:138) 在app//org.junit.platform.engine.support.histrared.NodeTestTask.execute(NodeTestTask.java:95) 在java.base@18/java.util.ArrayList.forEach(ArrayList.java:1511) 位于app//org.junit.platform.engine.support.histrared.SameThreadHierarchicalTestExecutiorService.invokeAll(SameThreadHierarchialTestExecutiorServices.java:41) 位于app//org.junit.platform.engine.support.histrared.NodeTestTaskLambda$executeSecurive$6(NodeTestTask.java:155) 位于app//org.junit.platform.engine.support.histrared.SthrowableCollector.execute(ThrowableCollector.java:73) 位于app//org.junit.platform.engine.support.histrared.NodeTestTaskLambda$executeSecurive$8(NodeTestTask.java:141) 位于app//org.junit.platform.engine.support.histrared.Node.around(Node.java:137) 位于app//org.junit.platform.engine.support.histrared.NodeTestTaskLambda$executeSecurive$9(NodeTestTask.java:139) 位于app//org.junit.platform.engine.support.histrared.SthrowableCollector.execute(ThrowableCollector.java:73) 位于app//org.junit.platform.engine.support.histrared.NodeTestTask.executeSecurively(NodeTestTask.java:138) 在app//org.junit.platform.engine.support.histrared.NodeTestTask.execute(NodeTestTask.java:95) 位于app//org.junit.platform.engine.support.histrared.SameThreadHierarchicalTestExecutiorService.submit(SameThreadHierarchialTestExecutiorServices.java:35) 位于app//org.junit.platform.engine.support.hhierarchicalTestExecution.execute(HierarchicalTestExecution.java:57) 位于app//org.junit.platform.engine.support.hhierarchicalTestEngine.exexecute(HierarchicalTestEngine.java:54) 位于org.junit.platform.selauncher.core.EngineExecutionOrchestrator.exexecute(EngineExecutionOrhestrator.java:108) 位于org.junit.platform.selauncher.core.EngineExecutionOrchestrator.exexecute(EngineExecutionOrhestrator.java:88) 位于org.junit.platform.selauncher.core.EngineExecutionOrchestratorLambda$execute$0(EngineExecutionOrhestrator.java:54) 位于org.junit.platform.selauncher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrhestrator.java:67) 位于org.junit.platform.selauncher.core.EngineExecutionOrchestrator.exexecute(EngineExecutionOrhestrator.java:52) 位于org.junit.platform.selauncher.core.DefaultLauncher.execute(DefaultLauncher.java:96) 位于org.junit.platform.selauncher.core.DefaultLauncher.execute(DefaultLauncher.java:75) 网址:org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasss(JUnitPlatformTestClassProcessor.java:99) 网址:org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79) 网址:org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75) 网址:org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61) 在java.base@18/jdk.internal.reflect.DirectMethodHandleAccessor.ioke(DirectMethodHandleAccessor.java:104) 在java.base@18/java.lang.reflect.Method.ioke(Method.java:577) 网址:org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDisptch.java:36) 网址:org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDisptch.java:24) 位于org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33) 位于org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94) 位于jdk.proxy1/jdk.proxy1.$Proxy2.stop(未知源) 网址:org.gradle.api.internal.tasks.testing.worker.TestWorker$3.run(TestWorker.java:193) 位于org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintaineThreadName(TestWorker.java:129) 网址:org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100) 网址:org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60) 位于org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56) 网址:org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoader worker.java:133) 网址:org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoader worker.java:71) 位于app//worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorker Main.java:69) 位于app//worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorker main.java:74) 引起原因:java.lang.RuntimeException:java.net.UnnknownHostException:银行服务:名称解析临时失败 位于io.grpc.internal.DnsNameResolver.resolveAddresses(DnsNameResolver.java:223) 位于io.grpc.internal.DnsNameResolver.doResolve(DnsNameResolve.java:282) 位于io.grpc.internal.DnsNameResolver$Resolve.run(DnsNameResolve.java:318) 位于java.base/java.util.concurrent.ThreadPoolExecutiator.runWorker(ThreadPoolExecutiator.java:1136) 位于java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) 位于java.base/java.lang.Thread.run(Thread.java:833) 引起原因:java.net.UnnknownHostException:银行服务:名称解析临时失败 位于java.base/java.net.Inet6AddressImpl.lookupAllHostAddr(本机方法) 位于java.base/java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:52) 位于java.base/java.net.InetAddress$PlatformResolver.lookupByName(InetAddress.java:1048) 位于java.base/java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1638) 位于java.base/java.net.InetAddress$NameServiceAddresses.get(InetAddress.java:997) 位于java.base/java.net.InetAddress.getAllByName0(InetAddress.java:1628) 位于java.base/java.net.InetAddress.getAllByName(InetAddress.java:1494) 位于io.grpc.internal.DnsNameResolver$JdkAddressResolver.resolveAddress(DnsNameResolver.java:631) 位于io.grpc.internal.DnsNameResolver.resolveAddresses(DnsNameResolver.java:219) …还有5个

    我不知道为什么全局服务名称解析不起作用。我的代码出了什么问题?

    github上的完整代码是 here

    提前谢谢。

    0 回复  |  直到 2 年前
        1
  •  0
  •   HelloWood    2 年前

    我测试了您的代码,发现了两个问题:

    1. 风俗 NameResolver 优先级需要大于5,因为默认的dns名称解析程序优先级为5,如果具有相同的优先级,则默认使用dns。优先级可以是0-10。

    2. 在中注册服务时需要处理方案前缀 ServiceRegistry#register ,添加方案前缀 dns:/// 向当局 bank-service 。或在以下情况下删除前缀 getInstances ,因为创建时 名称解析程序 ,将使用scheme作为前缀。这个 银行服务 将注册为 dns:///bank-service

    我建议使用独立的方案,避免在使用领事等注册中心时与其他方案相同。

    如果您对grpc-java有更多要求,可以参考repo https://github.com/helloworlde/grpc-java-sample 了解更多详细信息。