背景
系统所有服务模块都注册到 consul,上游服务 service-a 通过 feign api 调用同样注册在 consul 上的 service-b,出现 Connection timeout 异常,在 consul 上发现 service-b 的 2 个节点 health check 一个正常一个异常,当把 service-b 的异常节点剔除后服务调用正常。
场景复现
1)启动服务注册中心 consul
对于 macos 来说很简单,本地启动命令:
brew tap hashicorp/tapbrew install hashicorp/tap/consulconsul agent -dev
复制代码
然后通过 http://localhost:8500/ 访问。
2)定义下游服务
定义下游 Feign API:
@FeignClient( name = "downstream-service")public interface DownStreamServiceApi {
@PostMapping("/serviceName") public String getServiceName();
}
复制代码
为了 mock 下游服务 service checks failing,可以采用如下配置:
spring: application: name: downstream-service cloud: consul: discovery: service-name: downstream-service heartbeat: # mock service checks failing enabled: false
复制代码
代码链接:https://github.com/itschenxiang/spring-boot-examples/tree/main/downstream-service
3)定义下游服务
引入下游 Feign API 并调用:
public class UpstreamServiceApplication {
// other code @Autowired private DownStreamServiceApi downStreamServiceApi;
@Bean public CommandLineRunner commandLineRunner() { return new CommandLineRunner() { @Override public void run(String... args) throws Exception { Executors.newSingleThreadScheduledExecutor() .scheduleAtFixedRate(() -> { log.info(downStreamServiceApi.getServiceName()); },5 ,5, TimeUnit.SECONDS); } }; }
}
复制代码
代码链接:https://github.com/itschenxiang/spring-boot-examples/tree/main/upstream-service
4)启动 2 个下游服务:1 个健康 1 个异常
# 通过配置文件分别启动 service checks 正常和异常服务java -jar target/downstream-service-0.0.1-SNAPSHOT.jar --spring.profiles.active=unhealthjava -jar target/downstream-service-0.0.1-SNAPSHOT.jar --spring.profiles.active=health
复制代码
Consul 上注册情况如下图所示(这里的例子不是真正服务不可用,而是模拟 service checks failing):
5)启动上游服务并调用下游服务,验证结果
下游服务实现中返回了服务端口,可以看到 service checks failing 的节点也被路由到。
2023-07-19 00:13:04.783 INFO 21574 --- [pool-2-thread-1] c.i.u.UpstreamServiceApplication : downstream-service:80822023-07-19 00:13:09.728 INFO 21574 --- [pool-2-thread-1] c.i.u.UpstreamServiceApplication : downstream-service:8081
复制代码
根因分析
问题的根因这里作者没有去追溯,只是从现象得到结论。欢迎熟悉 consul 和 feign 负载均衡原理的小伙伴在评论区给出见解。
解决方案
可以看到注册在 consul 上,service checks failing 的节点也可能被访问到,因此在下游服务出现脏节点的情况下可能导致上游服务出现问题。
解决方案:
在 downstream-service 前加一层负载均衡层(类似反向代理),ip 保持不变,保证路由到的都是服务健康节点。
参考链接
评论