分布式相关面试题

0 阅读3分钟

记录每天八股文,来源于ChatGPT和deepseek生成答案,如有侵权,请联系删除。

Feign的性能优化?

主要是从Http客户端的角度去优化性能,Feign底层默认是JDK自带的HttpURLConnection,这个是单线程发送Http请求的,不能配置线程池,可以使用能够池化技术的来提升性能,可以选择OkHttp或者HttpClient来替换默认的HttpURLConnection.

Feign怎样实现认证的传递?

实现接口RequestInterceptor,通过header实现认证传递, 在微服务架构中,使用Feign传递认证信息(如Token、JWT等)通常通过以下方式实现,确保服务间调用的安全上下文正确传递:


1. 使用 RequestInterceptor 自动添加请求头

通过自定义Feign拦截器,从当前请求或安全上下文中提取认证信息,并自动添加到Feign请求头中。

步骤:

  1. 创建拦截器类
    @Component
    public class FeignAuthInterceptor implements RequestInterceptor {
        @Override
        public void apply(RequestTemplate template) {
            // 从请求上下文中获取当前请求的Authorization头
            String authHeader = Optional.ofNullable(RequestContextHolder.getRequestAttributes())
                    .map(ServletRequestAttributes.class::cast)
                    .map(ServletRequestAttributes::getRequest)
                    .map(request -> request.getHeader("Authorization"))
                    .orElse("");
    
            // 或从Spring Security上下文中获取Token(如JWT)
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (authentication != null && authentication.getCredentials() instanceof String) {
                authHeader = "Bearer " + authentication.getCredentials();
            }
    
            // 添加认证头到Feign请求
            if (!authHeader.isEmpty()) {
                template.header("Authorization", authHeader);
            }
        }
    }
    
  2. Feign客户端启用拦截器
    @FeignClient(name = "target-service", configuration = FeignConfig.class)
    public interface TargetServiceClient {
        @GetMapping("/api/data")
        String getData();
    }
    
    // 配置类(可选,若拦截器已通过@Component自动注入)
    public class FeignConfig {
        @Bean
        public FeignAuthInterceptor feignAuthInterceptor() {
            return new FeignAuthInterceptor();
        }
    }
    

2. 集成OAuth2(如使用Spring Security OAuth)

若系统使用OAuth2协议,可通过OAuth2FeignRequestInterceptor自动传递Token。

步骤:

  1. 添加依赖
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-oauth2-client</artifactId>
    </dependency>
    
  2. 配置Feign客户端
    @FeignClient(
        name = "target-service",
        configuration = OAuth2FeignConfig.class
    )
    public interface TargetServiceClient {
        // 方法定义
    }
    
    // 配置类
    public class OAuth2FeignConfig {
        @Bean
        public RequestInterceptor oauth2FeignRequestInterceptor(OAuth2ClientContext context) {
            return new OAuth2FeignRequestInterceptor(context, new DefaultOAuth2ClientContext());
        }
    }
    

总结
  • 通用场景:优先使用RequestInterceptor自动传递请求头。
  • OAuth2集成:结合Spring Security OAuth2的拦截器也可以实现传递。
    通过以上方法,Feign可实现认证信息的无缝传递,确保微服务间调用的安全性。

为什么Feign第一次调用耗时很长?

ribbon默认是懒加载的,只有第一次调用的时候才会生成ribbon对应的组件,这就会导致首次调用的会很慢的问题 

Seata中xid怎样通过Feign进行全局传递

在 Seata 中,XID(全局事务 ID)需要在微服务之间进行传递,以保证全局事务的一致性。在使用 Feign 时,XID 可以通过拦截器的方式自动传递。具体过程如下:

  1. 配置 Feign 拦截器: 在 Seata 中,Feign 会自动将当前的 XID 加入到请求的头部。你需要为 Feign 客户端配置一个拦截器,它会在每个请求的 header 中加入当前的 XID。
  2. 添加 Seata Feign 拦截器: 通过 @EnableFeignClients 注解启用 Feign,并且在配置类中注册 SeataFeignInterceptor,它会自动在每次发送请求时,将全局事务 ID(XID)传递给下游服务。
@Configuration
@EnableFeignClients
public class FeignConfig {

    @Bean
    public RequestInterceptor requestInterceptor() {
        return new RequestInterceptor() {
            @Override
            public void apply(RequestTemplate template) {
                String xid = RootContext.getXID();
                if (xid != null) {
                    template.header(RootContext.KEY_XID, xid); // 将 XID 添加到请求头中
                }
            }
        };
    }
}
  1. 传递 XID: 当 Feign 发起 HTTP 请求时,SeataFeignInterceptor 会把当前全局事务的 XID 传递到请求头中。下游服务收到请求时,会从请求头中读取 XID,并自动设置到 RootContext 中,保持全局事务的一致性。
  2. XID 自动传递: 下游服务在接收到请求后,Seata 会自动将请求头中的 XID 设置到当前线程的 RootContext 中,从而确保事务能够在下游服务中正常执行。

这样,你就可以在通过 Feign 进行微服务调用时,自动传递 XID,实现分布式事务的传递与控制。

Seata 使用的是类似于传统的两阶段提交协议,确保了分布式事务在微服务架构中的一致性和原子性。