解决【zipkin整合seata的时候远程调用服务连接不上的问题】
问题:
在使用seata,使用 spring-cloud-alibaba-seata 和 spring-cloud-starter-sleuth 两个maven依赖时,在接口调用的时候,会报错:
Caused by: com.netflix.client.ClientException: Load balancer does not have available server for client: 192.168.106.18
at com.netflix.loadbalancer.LoadBalancerContext.getServerFromLoadBalancer(LoadBalancerContext.java:483) ~[ribbon-loadbalancer-2.3.0.jar:2.3.0]
at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:184) ~[ribbon-loadbalancer-2.3.0.jar:2.3.0]
at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:180) ~[ribbon-loadbalancer-2.3.0.jar:2.3.0]
at rx.Observable.unsafeSubscribe(Observable.java:10327) ~[rxjava-1.3.8.jar:1.3.8]
at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:94) ~[rxjava-1.3.8.jar:1.3.8]
at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:42) ~[rxjava-1.3.8.jar:1.3.8]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) ~[rxjava-1.3.8.jar:1.3.8]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) ~[rxjava-1.3.8.jar:1.3.8]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) ~[rxjava-1.3.8.jar:1.3.8]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) ~[rxjava-1.3.8.jar:1.3.8]
at rx.Observable.subscribe(Observable.java:10423) ~[rxjava-1.3.8.jar:1.3.8]
at rx.Observable.subscribe(Observable.java:10390) ~[rxjava-1.3.8.jar:1.3.8]
at rx.observables.BlockingObservable.blockForSingle(BlockingObservable.java:443) ~[rxjava-1.3.8.jar:1.3.8]
at rx.observables.BlockingObservable.single(BlockingObservable.java:340) ~[rxjava-1.3.8.jar:1.3.8]
at com.netflix.client.AbstractLoadBalancerAwareClient.executeWithLoadBalancer(AbstractLoadBalancerAwareClient.java:112) ~[ribbon-loadbalancer-2.3.0.jar:2.3.0]
at org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient.execute(LoadBalancerFeignClient.java:83) ~[spring-cloud-openfeign-core-2.2.2.RELEASE.jar:2.2.2.RELEASE]
... 120 common frames omitted
官方修改建议:
Spring Cloud Sleuth默认通过TraceFeignClientAutoConfiguration提供feign的集成,可以设置spring.sleuth.feign.enabled为false来使其无效。
来自官方issues:https://github.com/seata/seata/issues/2544
但是这种修改方式把sleuth关闭了,导致在zipkin控制台看到的接口调用栈都是没有任何关联的:
如果你需要使用seata,但是又不想关闭sleuth,则本篇博客就来解决这个问题。
解决思路:
在seata的官方文档中业务系统集成seata客户端,有五个步骤。在最后一个步骤:
步骤五:实现xid跨服务传递
手动 参考源码integration文件夹下的各种rpc实现 module
自动 springCloud用户可以引入spring-cloud-alibaba-seata,内部已经实现xid传递
这个意思也就是:需要把全局事务的xid,透传到构成全局事务的各个子服务中。
自动透传xid,可以直接引用 spring-cloud-alibaba-seata (由于这个包和sleuth冲突,所以我们主要看手动透传xid的方案。)
手动透传xid,可以参考官方源码的实现: https://github.com/seata/seata/tree/develop/integration
这里我就以http的实现思路来简单说一下:
如果构成全局事务的各个自服务是使用http协议的,比如使用的是SpringCloud。对于http协议透传xid的方式很简单:
在consumer端,只需要获取到xid然后把xid放到请求头中;
在provider端解析http的请求头,然后使用RootContext.bind(xid)绑定xid即可。
我们来看源码:
Consumer端:
Provider端:
解决方案:
我们可以直接把 io.seata.integration.http.DefaultHttpExecutor 和 io.seata.integration.http.HttpAutoConfiguration 配置到项目中即可。
但是如果我们使用的是SpringCloud,一般来说都会使用feign。那么我们就写一个feign拦截器来代替 DefaultHttpExecutor 。在provider端还是使用 HttpAutoConfiguration。
引入依赖:
首先,我们需要注意我们引入的maven依赖:
引入 seata-spring-boot-starter ,但是 不要引入 spring-cloud-alibaba-seata。
引入 seata-spring-boot-starter ,但是 不要引入 spring-cloud-alibaba-seata。
引入 seata-spring-boot-starter ,但是 不要引入 spring-cloud-alibaba-seata。
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.1.0</version> <!-- 当前最新版本为1.1.0 -->
</dependency>
备注:对于 seata-all maven依赖是否引入都可以。seata-spring-boot-starter 依赖中已经包含了 seata-all,所以可以不用单独引入seata-all。
Feign拦截器
/**
* feign拦截器,获取xid并放到请求头中
*
* @author anxiaole
* @email 745024471@qq.com
* @date 2020/5/12 15:27
*/
@Slf4j
public class SeataFeignInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate request) {
String xid = RootContext.getXID();
if (xid != null && !xid.trim().isEmpty()) {
log.debug("seata - feign add seata-xid http request header [{}]", xid);
request.header(RootContext.KEY_XID, xid);
}
}
}
Feign拦截器的配置:
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
/**
* @author anxiaole
* @email 745024471@qq.com
* @date 2020/5/9 10:19
*/
public class SeataFeignConfiguration {
@Bean
@ConditionalOnMissingBean
public SeataFeignInterceptor seataFeignInterceptor() {
return new SeataFeignInterceptor();
}
}
EnableSeata注解
import com.pandora.common.seata.feign.SeataFeignConfiguration;
import org.springframework.context.annotation.Import;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import io.seata.integration.http.HttpAutoConfiguration;
/**
* <pre>
* 开启seata分布式事务
*
* 1、在application启动类上使用此注解
* 2、需要在application.yml中配置如下参数:
* {@code
*
* # Seata 配置项,对应 SeataProperties 类
* seata:
* application-id: ${spring.application.name} # Seata 应用编号,默认为 ${spring.application.name}
* tx-service-group: my-application-group # Seata 事务组编号,用于 TC 集群名
* # 服务配置项,对应 ServiceProperties 类
* service:
* # 虚拟组和分组的映射
* vgroup-mapping:
* my-application-group: default
* # 分组和 Seata 服务的映射
* grouplist:
* default: localhost:8091
* }
*
* </pre>
*
* @author anxiaole
* @email 745024471@qq.com
* @date 2020/6/8 14:34
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import({SeataFeignConfiguration.class, HttpAutoConfiguration.class})
public @interface EnableSeata {
}
使用方法:
1、在web application启动类上加上@EnableSeata 注解
2、在 application.yml中加入seata配置项:
参考:
学习seata概念首先需要看官方文档: http://seata.io/zh-cn/docs/overview/what-is-seata.html
了解了概念之后,尝试把官方的案例启动成功: http://seata.io/zh-cn/docs/user/quickstart.html
seata和自己项目进行整合,建议看 芋道源码 的博客: http://www.iocoder.cn/categories/Seata/
了解了原理之后、官方案例运行成功了,可以直接看 芋道源码 博客相关源码: https://github.com/YunaiV/SpringBoot-Labs/tree/master/labx-17
以上是 解决【zipkin整合seata的时候远程调用服务连接不上的问题】 的全部内容, 来源链接: utcz.com/z/517219.html