解决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还是微服务名称了,无需配置 discoveryClientEnabledlb:// 协议和Spring Cloud Gateway形成了呼应,学习成本也比较低,使用体验更加一致

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

干货分享

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

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

近期热文

分布式事务中间件 Seata 的设计原理Java 8中Stream API的这些奇技淫巧!你都Get到了吗?分享 | 阿里巴巴如何管理代码分支?干货 | 这次我们看看阿里的人是如何蹂躏CPU的深度解析 Spring Bean 的加载阿里工程师谈,什么是好的代码?

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之后的报错问题_第1张图片>>>技术讨论群<<<喜欢就点个"在看"呗^_^

你可能感兴趣的:(解决Spring Cloud Alibaba/Spring Cloud整合Zipkin之后的报错问题)