grpc-ecosystem / grpc-spring

Spring Boot starter module for gRPC framework.
https://grpc-ecosystem.github.io/grpc-spring/
Apache License 2.0
3.52k stars 826 forks source link

net.devh.boot.grpc.client.nameresolver.DiscoveryClientNameResolver#needsToUpdateConnections #647

Open cyuegit opened 2 years ago

cyuegit commented 2 years ago

nacos NameResolver can not analyze metadata.for example,i change the weight of serviceinstance on nacos consoleui,but needsToUpdateConnections compare host and port,never care the weight。 i suggest make md5 for instanceList,this is a quick Comparators

ST-DDT commented 2 years ago

FFR:


I would like to confirm whether I understand your problem correctly.

1) You don't have access to the ServiceInstance's Metadata and thus cannot customize the LoadBalancer behavior? 2) Or the attributes won't get updated unless the service instance list actually changes?

cyuegit commented 2 years ago

Neither of the above 2. i can get the ServiceInstance's Metadata with Reflect. i customize my LoadBalancer ,but depend on the onSubchannelState. but onSubchannelState depend on needsToUpdateConnections。

please look up net.devh.boot.grpc.client.nameresolver.DiscoveryClientNameResolver.Resolve#resolveInternal

needsToUpdateConnections do not Compare ServiceInstance's Metadata, eg nacos.weight.

The logic for updating the gRPC server list using a discovery client Creates a new Resolve that stores a snapshot of the relevant states of the resolver. 兄弟 我是中国人,可以中文交流吗。 https://github.com/cyuegit/spring-boot-grpc needsToUpdateConnections 没监控元数据的变化,我在nacos控制页面改了权重,不能触发onSubchannelState变动。后面我的负载均衡策略没拿到onSubchannelState事件,没法更新ServiceInstanceList。 我自己后面写了CustomDiscoveryClientNameResolver,CustomDiscoveryClientResolverFactory ,重构了needsToUpdateConnections 方法,但是没法替换默认的DiscoveryClientResolverFactory。

GrpcDiscoveryClientAutoConfiguration 这个类我也看了,请指教

ST-DDT commented 2 years ago

Okay, from your description it looks like you dont get the updated metadata (weight).

I think we have to use the hash of the metadata in the check as well to ensure it does get updated correctly.

If you want to provide your own fix, make sure you register it with a higher priority than my resolver.

https://github.com/yidongnan/grpc-spring-boot-starter/blob/67c64c801f5845dd787a3ef7035eb63f2068f4be/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/nameresolver/DiscoveryClientResolverFactory.java#L116

And make sure you register it in the default registry

https://github.com/yidongnan/grpc-spring-boot-starter/blob/67c64c801f5845dd787a3ef7035eb63f2068f4be/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/autoconfigure/GrpcClientAutoConfiguration.java#L119

Writing in chinese is fine. IMO its easier to read the google translated text because I can check the additional context/meanings to decipher the content. If its pre translated then the meaning is already lost and I have to guess it.

cyuegit commented 2 years ago

step1:I customized the NameResolverProvider and set priority equal to 7. step2:I use the spi to load my customResolverProvider 微信截图_20220329110454 But start error. how to register it in the default registry?

ST-DDT commented 2 years ago

Please always post the stacktrace of the error. Otherwise I dont know what went wrong.

cyuegit commented 2 years ago
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'grpcNameResolverRegistration' defined in class path resource [net/devh/boot/grpc/client/autoconfigure/GrpcClientAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [net.devh.boot.grpc.client.nameresolver.NameResolverRegistration]: Factory method 'grpcNameResolverRegistration' threw exception; nested exception is java.util.ServiceConfigurationError: io.grpc.NameResolverProvider: Provider com.xcbeyond.springboot.grpc.nameresolver.CustomDiscoveryClientResolverFactory could not be instantiated
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:658) ~[spring-beans-5.3.15.jar:5.3.15]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:638) ~[spring-beans-5.3.15.jar:5.3.15]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352) ~[spring-beans-5.3.15.jar:5.3.15]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195) ~[spring-beans-5.3.15.jar:5.3.15]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582) ~[spring-beans-5.3.15.jar:5.3.15]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.15.jar:5.3.15]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.15.jar:5.3.15]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.15.jar:5.3.15]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.15.jar:5.3.15]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:233) ~[spring-beans-5.3.15.jar:5.3.15]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1282) ~[spring-beans-5.3.15.jar:5.3.15]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1243) ~[spring-beans-5.3.15.jar:5.3.15]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveBean(DefaultListableBeanFactory.java:494) ~[spring-beans-5.3.15.jar:5.3.15]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:349) ~[spring-beans-5.3.15.jar:5.3.15]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:342) ~[spring-beans-5.3.15.jar:5.3.15]
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1172) ~[spring-context-5.3.15.jar:5.3.15]
    at net.devh.boot.grpc.client.inject.GrpcClientBeanPostProcessor.getChannelFactory(GrpcClientBeanPostProcessor.java:200) ~[grpc-client-spring-boot-autoconfigure-2.13.1.RELEASE.jar:2.13.1.RELEASE]
    at net.devh.boot.grpc.client.inject.GrpcClientBeanPostProcessor.processInjectionPoint(GrpcClientBeanPostProcessor.java:175) ~[grpc-client-spring-boot-autoconfigure-2.13.1.RELEASE.jar:2.13.1.RELEASE]
    ... 34 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [net.devh.boot.grpc.client.nameresolver.NameResolverRegistration]: Factory method 'grpcNameResolverRegistration' threw exception; nested exception is java.util.ServiceConfigurationError: io.grpc.NameResolverProvider: Provider com.xcbeyond.springboot.grpc.nameresolver.CustomDiscoveryClientResolverFactory could not be instantiated
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.3.15.jar:5.3.15]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) ~[spring-beans-5.3.15.jar:5.3.15]
    ... 51 common frames omitted
Caused by: java.util.ServiceConfigurationError: io.grpc.NameResolverProvider: Provider com.xcbeyond.springboot.grpc.nameresolver.CustomDiscoveryClientResolverFactory could not be instantiated
    at java.util.ServiceLoader.fail(ServiceLoader.java:232) ~[na:1.8.0_291]
    at java.util.ServiceLoader.access$100(ServiceLoader.java:185) ~[na:1.8.0_291]
    at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:384) ~[na:1.8.0_291]
    at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:404) ~[na:1.8.0_291]
    at java.util.ServiceLoader$1.next(ServiceLoader.java:480) ~[na:1.8.0_291]
    at io.grpc.ServiceProviders.loadAll(ServiceProviders.java:67) ~[grpc-api-1.45.0.jar:1.45.0]
    at io.grpc.NameResolverRegistry.getDefaultRegistry(NameResolverRegistry.java:115) ~[grpc-api-1.45.0.jar:1.45.0]
    at net.devh.boot.grpc.client.autoconfigure.GrpcClientAutoConfiguration.grpcNameResolverRegistration(GrpcClientAutoConfiguration.java:119) ~[grpc-client-spring-boot-autoconfigure-2.13.1.RELEASE.jar:2.13.1.RELEASE]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_291]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_291]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_291]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_291]
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.3.15.jar:5.3.15]
    ... 52 common frames omitted
Caused by: java.lang.InstantiationException: com.xcbeyond.springboot.grpc.nameresolver.CustomDiscoveryClientResolverFactory
    at java.lang.Class.newInstance(Class.java:427) ~[na:1.8.0_291]
    at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:380) ~[na:1.8.0_291]
    ... 62 common frames omitted
Caused by: java.lang.NoSuchMethodException: com.xcbeyond.springboot.grpc.nameresolver.CustomDiscoveryClientResolverFactory.<init>()
    at java.lang.Class.getConstructor0(Class.java:3082) ~[na:1.8.0_291]
    at java.lang.Class.newInstance(Class.java:412) ~[na:1.8.0_291]
    ... 63 common frames omitted
ST-DDT commented 2 years ago

If you use the ServiceLoader API you cannot use constructor parameters or bean injection.

Thats why we create it as a spring bean:

https://github.com/yidongnan/grpc-spring-boot-starter/blob/67c64c801f5845dd787a3ef7035eb63f2068f4be/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/autoconfigure/GrpcDiscoveryClientAutoConfiguration.java#L35-L38

cyuegit commented 2 years ago

you mean i define AutoConfiguration in spring.factories by myself? But how do I make GrpcDiscoveryClientAutoConfiguration ineffective?

ST-DDT commented 2 years ago

A simple @Configuration should work as well. You don't have to exclude GrpcDiscoveryClientAutoConfiguration, but you can do so using any of these variants: https://www.baeldung.com/spring-data-disable-auto-config

cyuegit commented 2 years ago

Thanks, it's resolved