• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Dubbo3 服务发现的推空保护

武飞扬头像
Saleson
帮助1

推空保护是Dubbo服务发现新增的一个提升稳定性的功能,目的是当注册中心出现抖动,consumer接收到注册中心推送了空provider urls过来时,直接忽略掉,从而保护consumer维护的服务发现信息不受影响。

但是在某些场景下却是会出现异常,我们做个实验:
1、启动Provider A, ip为192.168.1.10
2、启动Provider B, ip为192.168.1.11
3、启动Consumer, 调用Provider A和Provider B, 此时正常调用
4、停掉Provider A 和Provider B
5、在ip为192.168.1.10的机器上重新启动Provider B

这时再在Consumer 调用Provider A和Provider B, 调用Provider B正常,但是调用Provider A 却会报错:

org.apache.dubbo.rpc.RpcException: Failed to invoke the method sayHello in the service org.apache.dubbo.springboot.demo.ProviderAService. Tried 3 times of the providers [192.168.1.9:20880] (1/1) from the registry 127.0.0.1:2181 on the consumer 192.168.1.9 using the dubbo version 3.0.8.1-SNAPSHOT. Last error is: Failed to invoke remote method: sayHello, provider: dubbo://192.168.1.9:20880/org.apache.dubbo.springboot.demo.ProviderAService?anyhost=true&application=dubbo-springboot-demo-provider&background=false&category=providers,configurators,routers&check=false&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.springboot.demo.DService&methods=sayHello,sayHelloAsync&payload=10004&pid=19514&qos.enable=false&register-mode=interface&release=3.0.8.1-SNAPSHOT&side=provider&sticky=false, cause: org.apache.dubbo.remoting.RemotingException: Fail to decode request due to: java.io.IOException: Service org.apache.dubbo.springboot.demo.DemoService with version 0.0.0 not found, invocation rejected.
java.io.IOException: Service org.apache.dubbo.springboot.demo.DemoService with version 0.0.0 not found, invocation rejected.
	at org.apache.dubbo.remoting.transport.CodecSupport.checkSerialization(CodecSupport.java:166)
	at org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcInvocation.decode(DecodeableRpcInvocation.java:138)
	at org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcInvocation.decode(DecodeableRpcInvocation.java:93)
	at org.apache.dubbo.remoting.transport.DecodeHandler.decode(DecodeHandler.java:57)
	at org.apache.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:44)
	at org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:57)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at org.apache.dubbo.common.threadlocal.InternalRunnable.run(InternalRunnable.java:41)
	at java.lang.Thread.run(Thread.java:750)

	at org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:114)
	at org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:340)
	at org.apache.dubbo.rpc.cluster.router.RouterSnapshotFilter.invoke(RouterSnapshotFilter.java:46)
	at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:321)
	at org.apache.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:99)
	at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:321)
	at org.apache.dubbo.rpc.protocol.dubbo.filter.FutureFilter.invoke(FutureFilter.java:51)
	at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:321)
	at org.apache.dubbo.rpc.cluster.filter.support.ConsumerContextFilter.invoke(ConsumerContextFilter.java:110)
	at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:321)
	at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CallbackRegistrationInvoker.invoke(FilterChainBuilder.java:193)
	at org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster$ClusterFilterInvoker.invoke(AbstractCluster.java:92)
	at org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker.invoke(MockClusterInvoker.java:97)
	at org.apache.dubbo.registry.client.migration.MigrationInvoker.invoke(MigrationInvoker.java:283)
	at org.apache.dubbo.rpc.proxy.InvocationUtil.invoke(InvocationUtil.java:57)
	at org.apache.dubbo.rpc.proxy.InvokerInvocationHandler.invoke(InvokerInvocationHandler.java:73)
	at org.apache.dubbo.springboot.demo.DemoServiceDubboProxy1.sayHello(DemoServiceDubboProxy1.java)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:205)
	at com.sun.proxy.$Proxy54.sayHello(Unknown Source)
	at org.apache.dubbo.springboot.demo.consumer.ConsumerApplication.doSayHello(ConsumerApplication.java:61)
	at org.apache.dubbo.springboot.demo.consumer.ConsumerApplication.main(ConsumerApplication.java:49)
学新通

观察日志发现,consumer并没有识别到Provider A目前并没有实例,仍然认为192.168.1.10也是Provider A的实例,将调用Provider A的请求发送过去,此时192.168.1.10服务器上运行的却是Provider B应用,无法处理该请求,就抛出异常。

如图所示,Consumer 第一次访问Provider A和Provider B时,consumer维护的信息和实际的部署信息是一致的
学新通
但是在Csonumser第二次访问Provider A和Provider B时,consumer维护的信息和实际的部署信息已经不一致了
学新通

出现这个情况的原因是dubbo3默认开启的推空保护(ZookeeperRegistry$RegistryChildListenerImpl.doNotify()方法会ZookeeperRegistry.toUrlsWithEmpty()方法获取Provider Urls,在该方法中会判断推空保护的开关),
本意是防止注册中心抖动,可是在某些场景下会引发问题,例如:
应用最后一台实例下线后,ip被回收,其它应用发布时从ip池获取到该ip并使用
这种情况在测试环境更容易出现,因为测试环境普遍都是一个实例。

如果要在测试环境避免这种情况,目前最好的办法是关闭推空保护:

  • RegistryConfig.enableEmptyProtection 设置为false
  • springboot 应用中配置参数 dubbo.registry.enable-empty-protection=false

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgcbfja
系列文章
更多 icon
同类精品
更多 icon
继续加载