背景
系统所有服务模块都注册到 consul,上游服务 service-a 通过 feign api 调用同样注册在 consul 上的 service-b,出现 Connection timeout 异常,在 consul 上发现 service-b 的 2 个节点 health check 一个正常一个异常,当把 service-b 的异常节点剔除后服务调用正常。
场景复现
1)启动服务注册中心 consul
对于 macos 来说很简单,本地启动命令:
brew tap hashicorp/tap
brew install hashicorp/tap/consul
consul 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=unhealth
java -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:8082
2023-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 保持不变,保证路由到的都是服务健康节点。
参考链接
评论