转载

解决Spring Cloud Alibaba/Spring Cloud整合Zipkin之后的报错问题

点击上方 "IT牧场" ,选择 "设为星标" 技术干货每日送达!

TIPS

本文服务发现组件以Nacos为例。 本文基于  Spring Cloud Greenwich SR1

问题复现

依赖


 

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-zipkin</artifactId>

</dependency>

配置


 

spring:

zipkin:

base-url: http://localhost:9411/

sleuth:

sampler:

probability: 1.0

结果

只要你的API被调用,应用就会疯狂报类似如下的异常。


 

2019-08-24 23:10:25.330 ERROR [user-center,,,] 48628 --- [.naming.updater] com.alibaba.nacos.client.naming : [NA] failed to update serviceName: DEFAULT_GROUP@@localhost


java.lang.IllegalStateException: failed to req API:/nacos/v1/ns/instance/list after all servers([localhost:8848]) tried: failed to req API:http://localhost:8848/nacos/v1/ns/instance/list. code:404 msg: service not found: DEFAULT_GROUP@@localhost

at com.alibaba.nacos.client.naming.net.NamingProxy.reqAPI(NamingProxy.java:380) ~[nacos-client-1.0.0.jar:na]

at com.alibaba.nacos.client.naming.net.NamingProxy.reqAPI(NamingProxy.java:304) ~[nacos-client-1.0.0.jar:na]

at com.alibaba.nacos.client.naming.net.NamingProxy.queryList(NamingProxy.java:217) ~[nacos-client-1.0.0.jar:na]

at com.alibaba.nacos.client.naming.core.HostReactor.updateServiceNow(HostReactor.java:273) ~[nacos-client-1.0.0.jar:na]

at com.alibaba.nacos.client.naming.core.HostReactor$UpdateTask.run(HostReactor.java:318) [nacos-client-1.0.0.jar:na]

at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_201]

at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266) [na:1.8.0_201]

at java.util.concurrent.FutureTask.run(FutureTask.java) [na:1.8.0_201]

at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_201]

at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [na:1.8.0_201]

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_201]

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_201]

at java.lang.Thread.run(Thread.java:748) [na:1.8.0_201]


原因:

Spring Cloud把 http://localhost:9411/ 当作了服务发现组件里面的服务名称;于是,Nacos Client尝试从Nacos Server寻找一个名为  localhost:9411 的服务…这个服务根本不存在啊,于是就疯狂报异常(因为Nacos Client本地定时任务,刷新本地服务发现缓存)

解决方案

知道原因之后,要想解决很简单:

让Spring Cloud 正确识别 http://localhost:9411/ ,当成一个URL,而不要当做服务名。 把Zipkin Server注册到Nacos

谈谈Zipkin Server注册到服务发现组件

Zipkin Server 官方并不支持注册到服务发现组件!!!!在  https://github.com/openzipkin/zipkin/issues/2540 里面,官方人员解答得很清楚了:

@nkorange [1] thank you for reaching out. We have had several users ask about service discovery with Zipkin Server over the years (see  #1870 [2] ) and less ask about dynamic/external configuration. We don't currently support any service discovery as a first-class feature. There is a workaround to use Eureka mentioned in  #1870 [3] . So unless a user is using that, or is building a custom Zipkin Server (which we don't officially support), there should be no service discovery.

If you want to come chat with us on Gitter ( https://gitter.im/openzipkin/zipkin [4] ) about next steps, please do.

详见 We don't currently support any service discovery as a first-class feature.

如果你想要注册到服务发现组件,那么可以参考 https://github.com/openzipkin/zipkin/issues/1870 说明自己改造Zipkin Server让其注册到服务发现组件,但这样做不会得到任何官方的技术支持!!

所以,将Zipkin Server注册到Nacos或者其他服务发现组件,不是最优解。我们的解决方案就演变成了:让Spring Cloud 正确识别 http://localhost:9411/ ,当成一个URL,而不要当做服务名。这一种解决方案。

配置走你!


 

spring:

zipkin:

base-url: http://localhost:9411/

discovery-client-enabled: false

从这个配置的注释( 代码见 org.springframework.cloud.sleuth.zipkin2.ZipkinProperties#discoveryClientEnabled )来看,只要设置成false,那么就会把  http://localhost:9411/ 当成一个URL,而不是服务名称了。

你以为已经牛逼了,然而当你去测试的时候,发现 然并卵 ,一点效果都没有。

Spring Cloud Sleuth Bug、解决方案与Pull Request

问题代码在这里: org.springframework.cloud.sleuth.zipkin2.sender.ZipkinRestTemplateSenderConfiguration.DiscoveryClientZipkinUrlExtractorConfiguration.ZipkinClientNoOpConfiguration ,里面是这么玩的:


 

@Configuration

@ConditionalOnProperty(value = "spring.zipkin.discoveryClientEnabled", havingValue = "false")

static class ZipkinClientNoOpConfiguration {

...

}

当你看到这个代码的时候,就应该知道解决方案啦!那就是你得把配置修改为:


 

spring:

zipkin:

base-url: http://localhost:9411/

discoveryClientEnabled: false

就可以了!

这其实是Spring Cloud Sleuth子项目 spring-cloud-sleuth-zipkin 的一个Bug!

相关的Issue在: https://github.com/spring-cloud/spring-cloud-sleuth/issues/1376 解决的Pul Request在: https://github.com/spring-cloud/spring-cloud-sleuth/pull/1379  , 代码已经合并了,在  Spring Cloud Greenwich SR3  版本中会修正!

简单总结一下:

如果你使用的是Greenwich SR3之前的版本,务必使用  spring.zipkin.discoveryClientEnabled = false ,否则配置不生效!! 如果你使用的是Greenwich SR3及更高版本,可使用  discovery-client-enabled  或者  discoveryClientEnabled  。

为什么Zipkin Server不支持服务发现,Spring Cloud还弄个服务发现的配置?

我暂时没有找到Spring Cloud这样做的意图。我的猜想:是因为早期Spring Cloud是使用自己编写代码实现Zipkin Server的(从Finchley开始,改成了直接用Zipkin官方现成的jar包启动),这种方式可以注册到你想要的服务发现组件上(因为本质上,Zipkin Server就是个基于Spring Boot的应用嘛)。

一点吐槽

个人觉得Spring Cloud这部分的设计不太优雅,如果让我来设计的话,我应该会这么设计:

URL模式:


 

spring:

zipkin:

base-url: http://localhost:9411/

服务名称的模式:


 

spring:

zipkin:

base-url: lb://zipkin-server/

这样带来的好处:

scheme( http:// 、  lb:// )就可以区分出是具体URL还是微服务名称了,无需配置  discoveryClientEnabled lb://  协议和Spring Cloud Gateway形成了呼应,学习成本也比较低,使用体验更加一致

不过工作比较忙,只有创意,暂时没有时间提交PR…哈哈,所以…吐槽完还是得继续忍着啊…

干货分享

最近将个人学习笔记整理成册,使用PDF分享。关注我,回复如下代码,即可获得百度盘地址,无套路领取!

001:《Java并发与高并发解决方案》学习笔记; 002:《深入JVM内核——原理、诊断与优化》学习笔记; 003:《Java面试宝典》 004:《Docker开源书》 005:《Kubernetes开源书》 006:《DDD速成(领域驱动设计速成)》 007: 全部 008: 加技术讨论群

近期热文

References

[1] @nkorange:  https://github.com/nkorange

[2] #1870:  https://github.com/openzipkin/zipkin/issues/1870

[3] #1870:  https://github.com/openzipkin/zipkin/issues/1870

[4]https://gitter.im/openzipkin/zipkin

想知道更多?长按/扫码关注我吧↓↓↓ 解决Spring Cloud Alibaba/Spring Cloud整合Zipkin之后的报错问题 >>>技术讨论群<<< 喜欢就点个 "在看" 呗^_^

原文  http://mp.weixin.qq.com/s?__biz=MzI4ODQ3NjE2OA==&mid=2247485505&idx=2&sn=a4cc17fc5f388707440bf395d5a12158
正文到此结束
Loading...