在服务中使用关联ID
Last updated
Last updated
我们已经确保每个流经网关的微服务调用都添加了关联ID,我们还希望确保:
关联ID对所调用的微服务是可访问的。
下游服务调用其他微服务时,关联ID也能够传播到被下游服务调用的微服务中
为了实现这一目标,我们将为每个微服务构建一组三个类:UserContextFilter、UserContext和UserContextInterceptor。这些类将协同工作,读取传入HTTP请求的关联ID,将其映射到一个在应用程序业务逻辑中易于访问和使用的类,然后确保关联ID传播到任何下游服务调用。
下图展示了我们将如何为许可服务构建这些不同组件:
当通过网关调用 licensing 服务时,TrackingFilter 会在传入网关的任何调用的HTTP头中注入关联ID。
UserContextFilter类是一个自定义的HTTP Servlet过滤器,将关联ID映射到UserContext类。UserContext类会在线程中存储这些值,以供稍后在调用中使用。
licensing 服务业务逻辑执行对 organization 服务的调用。
RestTemplate调用 organization 服务。RestTemplate使用自定义的Spring拦截器类UserContextInterceptor,将关联ID作为HTTP头注入到出站调用中。
重复代码 vs. 共享库重复代码与共享库之间的权衡问题在微服务设计中是一个模糊的领域。
微服务纯粹主义者认为不应该在服务之间使用自定义框架,因为这引入了人为的依赖关系。业务逻辑的更改或错误可能导致对所有服务进行广泛的重构。
另一方面,其他微服务从业者认为纯粹主义的方法不切实际,因为存在某些情况(比如前面的UserContextFilter示例)在这些情况下,构建一个共同的库并在服务之间共享是有意义的。
我们认为有一个中间地带。
在处理基础设施任务时,使用共同库是可以的。
但如果开始共享面向业务的类,那么你最终会面临问题,因为这会打破服务之间的边界。
在客户端弹性一章中,已经给出了 UserContextFilter、UserContext 和 UserContextHolder 的代码:
ThreadLocal与Resilience4jUserContextInterceptor 类将关联ID注入到从 RestTemplate 实例执行的任何出站HTTP服务请求中。这是为了确保我们可以建立服务调用之间的关联。
为此,我们将使用一个Spring拦截器,并将其注入到RestTemplate 类中:
因为 UserContextInterceptor 实现了 ClientHttpRequestInterceptor 和 RequestInterceptor 这两个接口,所以它可以通过两种方式进行使用:
日志聚合、身份验证等功能现在我们已经在每个服务中传递了关联ID,可以追踪事务在所有调用涉及的服务中的流动。为实现这一点,确保每个服务都记录到一个中央日志聚合点,将所有服务的日志条目集中到一个地方。在日志聚合服务中捕获的每个日志条目都将有一个关联ID。