企业官网网站模板下载,西安百度公司开户,app开发 网站建设,设计师图片素材上周参加了在Geecon上Sam Newman的微服务讨论后#xff0c;我开始思考更多有关用于监视#xff0c;报告和诊断的面向服务/微服务平台最可能的基本功能#xff1a;相关ID。 关联ID允许在面向服务的复杂平台中进行分布式跟踪#xff0c;在该平台中#xff0c;对单个应用程序… 上周参加了在Geecon上Sam Newman的微服务讨论后我开始思考更多有关用于监视报告和诊断的面向服务/微服务平台最可能的基本功能相关ID。 关联ID允许在面向服务的复杂平台中进行分布式跟踪在该平台中对单个应用程序的请求通常可以由多个下游服务处理。 如果没有关联下游服务请求的能力那么很难理解平台中如何处理请求。 我已经在我最近从事的几个SOA项目中看到了关联ID的好处但是正如Sam在他的演讲中提到的那样通常很容易想到在构建应用程序的初始版本时不需要这种类型的跟踪。 但是当您确实意识到好处和需求时很难将其改造到应用程序中。 我还没有找到在基于Java / Spring的应用程序中实现相关ID的完美方法但是在通过电子邮件与Sam聊天后他提出了一些建议我现在将其变成一个使用Spring Boot的简单项目以演示如何做到这一点。被实施。 为什么 在两次Sam的Geecon谈话中他都提到根据他的经验关联ID对于诊断目的非常有用。 关联ID本质上是一个生成的ID它与单个通常是用户驱动的请求一起进入应用程序该请求通过堆栈向下传递到相关服务。 在SOA或微服务平台中这种类型的ID非常有用因为进入应用程序的请求通常被“散布”或由多个下游服务处理而关联ID允许所有下游请求从请求的初始点到根据ID进行关联或分组。 然后可以通过关联所有下游服务日志并匹配所需的ID来使用相关ID来执行所谓的“分布式跟踪”以在整个应用程序堆栈中查看请求的跟踪如果使用集中式日志记录这非常容易框架例如logstash 。 面向服务领域的主要参与者一直在讨论分布式跟踪和关联请求的需求因此Twitter创建了他们的开源Zipkin框架 通常将其插入RPC框架Finagle 和Netflix。已将其Karyon网络/微服务框架开源这两个框架均提供分布式跟踪。 当然在该领域有商业产品其中一个产品是AppDynamics 虽然很酷但价格却很高。 在Spring Boot中创建概念验证 与Zipkin和Karyon一样它们都具有相对侵入性因为您必须在通常是自以为是的框架之上构建服务。 对于某些用例这可能很好但对于其他用例而言却没什么用特别是在构建微服务时。 我最近一直在尝试使用Spring Boot 并且该框架通过提供许多预配置的明智默认值而建立在广为人知和喜爱至少对我而言的Spring框架上。 这使您可以快速构建微服务尤其是通过RESTful接口进行通信的微服务。 本博客pos的其余部分说明了我如何希望实现一种实现关联ID的非侵入性方式。 目标 允许为进入应用程序的初始请求生成关联ID 启用相关ID传递给下游服务使用的方法应尽可能不侵入代码 实作 我在GitHub上创建了两个项目 一个包含一个实现其中所有请求都以同步方式处理 即在单个线程上处理所有请求处理的传统Spring方法还有一个用于异步非阻塞时的实现。 正在使用的通信方式即结合使用Servlet 3异步支持和Spring的DeferredResult和Java的Futures / Callables。 本文的大部分内容描述了异步实现因为这更有趣 Spring Boot异步DeferredResult Futures通信相关ID Github回购 这两个代码库中的主要工作都是由CorrelationHeaderFilter承担的CorrelationHeaderFilter是一个标准的Java EE筛选器它检查HttpServletRequest标头中是否存在correlationId。 如果找到一个则在RequestCorrelation类中设置一个ThreadLocal变量稍后讨论。 如果未找到相关标识则生成一个相关标识并将其添加到RequestCorrelation类中 public class CorrelationHeaderFilter implements Filter {//...Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)throws IOException, ServletException {final HttpServletRequest httpServletRequest (HttpServletRequest) servletRequest;String currentCorrId httpServletRequest.getHeader(RequestCorrelation.CORRELATION_ID_HEADER);if (!currentRequestIsAsyncDispatcher(httpServletRequest)) {if (currentCorrId null) {currentCorrId UUID.randomUUID().toString();LOGGER.info(No correlationId found in Header. Generated : currentCorrId);} else {LOGGER.info(Found correlationId in Header : currentCorrId);}RequestCorrelation.setId(currentCorrId);}filterChain.doFilter(httpServletRequest, servletResponse);}//...private boolean currentRequestIsAsyncDispatcher(HttpServletRequest httpServletRequest) {return httpServletRequest.getDispatcherType().equals(DispatcherType.ASYNC);} 此代码中唯一可能不会立即显而易见的是条件检查currentRequestIsAsyncDispatcherhttpServletRequest 但这是为了防止当Async Dispatcher线程运行以返回结果时正在执行的相关ID代码请注意因为我最初并不希望Async Dispatcher再次触发执行过滤器。 这是RequestCorrelation类其中包含一个简单的ThreadLocal String静态变量用于保存当前执行线程的相关ID通过上面的CorrelationHeaderFilter设置 public class RequestCorrelation {public static final String CORRELATION_ID correlationId;private static final ThreadLocalString id new ThreadLocalString();public static String getId() { return id.get(); }public static void setId(String correlationId) { id.set(correlationId); }
} 一旦将关联ID存储在RequestCorrelation类中就可以通过调用RequestCorrelation中的静态getId方法将其检索并添加到下游服务请求或数据存储访问等中。 将这种行为封装在应用程序服务之外可能是一个好主意并且您可以在我创建的RestClient类中看到如何执行此操作的示例该类构成Spring的RestTemplate并处理标头中相关性ID的设置从调用类透明地显示。 Component
public class CorrelatingRestClient implements RestClient {private RestTemplate restTemplate new RestTemplate();Overridepublic String getForString(String uri) {String correlationId RequestCorrelation.getId();HttpHeaders httpHeaders new HttpHeaders();httpHeaders.set(RequestCorrelation.CORRELATION_ID, correlationId);LOGGER.info(start REST request to {} with correlationId {}, uri, correlationId);//TODO: error-handling and fault-tolerance in productionResponseEntityString response restTemplate.exchange(uri, HttpMethod.GET,new HttpEntityString(httpHeaders), String.class);LOGGER.info(completed REST request to {} with correlationId {}, uri, correlationId);return response.getBody();}
}//... calling Class
public String exampleMethod() {RestClient restClient new CorrelatingRestClient();return restClient.getForString(URI_LOCATION); //correlation id handling completely abstracted to RestClient impl
}使这项工作适用于异步请求… 当您同步处理所有请求时上面包含的代码可以很好地工作但是在SOA /微服务平台中以非阻塞异步方式处理请求通常是个好主意。 在Spring中可以通过将DeferredResult类与Servlet 3异步支持结合使用来实现。 在异步方法中使用ThreadLocal变量的问题在于最初处理请求并创建DeferredResult / Future的线程将不是执行实际处理的线程。 因此需要一点胶水代码以确保相关性id跨线程传播。 这可以通过使用所需功能扩展Callable来实现不要担心示例调用类代码看起来不直观-在Spring中DeferredResults和Futures之间的这种适应是必然的在整个过程中包括样板ListenableFutureAdapter的完整代码为在我的GitHub存储库中 public class CorrelationCallableV implements CallableV {private String correlationId;private CallableV callable;public CorrelationCallable(CallableV targetCallable) {correlationId RequestCorrelation.getId();callable targetCallable;}Overridepublic V call() throws Exception {RequestCorrelation.setId(correlationId);return callable.call();}
}//... Calling ClassRequestMapping(externalNews)
public DeferredResultString externalNews() {return new ListenableFutureAdapter(service.submit(new CorrelationCallable(externalNewsService::getNews)));
} 这样就可以了-无论处理的同步/异步性质如何相关ID的传播 您可以克隆包含我的异步示例的Github报告并通过在命令行上运行mvn spring-bootrun来执行应用程序。 如果您在浏览器中或通过curl访问http// localhost8080 / externalNews 您将在Spring Boot控制台中看到类似于以下内容的内容该内容清楚地表明了在初始请求中生成的关联ID然后被传播到模拟外部调用请查看ExternalNewsServiceRest类以了解如何实现 [nio-8080-exec-1] u.c.t.e.c.w.f.CorrelationHeaderFilter : No correlationId found in Header. Generated : d205991b-c613-4acd-97b8-97112b2b2ad0
[pool-1-thread-1] u.c.t.e.c.w.c.CorrelatingRestClient : start REST request to http://localhost:8080/news with correlationId d205991b-c613-4acd-97b8-97112b2b2ad0
[nio-8080-exec-2] u.c.t.e.c.w.f.CorrelationHeaderFilter : Found correlationId in Header : d205991b-c613-4acd-97b8-97112b2b2ad0
[pool-1-thread-1] u.c.t.e.c.w.c.CorrelatingRestClient : completed REST request to http://localhost:8080/news with correlationId d205991b-c613-4acd-97b8-97112b2b2ad0结论 我对这个简单的原型感到非常满意它确实满足了我上面列出的两个目标。 未来的工作将包括为此代码编写一些测试不要为TDDing而感到羞耻并将此功能扩展到更实际的示例。 我要非常感谢Sam不仅是因为在Geecon的精彩演讲中分享了他的知识还感谢我抽出时间来回复我的电子邮件。 如果您对微服务和相关工作感兴趣我强烈建议您参阅Sams Microservice书籍该书可在OReilly的Early Access中获得 。 我很喜欢阅读当前可用的章节并且最近实施了许多SOA项目我可以从中获得很多不错的建议。 我将以极大的兴趣关注本书的发展 资源资源 我多次使用Tomasz Nurkiewicz的优秀博客来学习如何最好地在Spring中连接所有DeferredResult / Future代码 http://www.nurkiewicz.com/2013/03/deferredresult-asynchronous-processing.html 翻译自: https://www.javacodegeeks.com/2014/05/implementing-correlation-ids-in-spring-boot-for-distributed-tracing-in-soamicroservices.html