spring-boot-starter-actuator 与 hystrix-servo-metrics-publisher 冲突

标签 spring-boot hystrix

我将 spring-boot 1.4.3.RELEASE 与 Netflix Hystrix 一起使用,我将通过 JMX 提供 Hystrix 指标。 Hystrix 包含在此代码段的项目中

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-dependencies</artifactId>
      <version>Brixton.SR5</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

对于通过 JMX 的指标,我使用 hystrix-servo-metrics-publisher 1.5.9
<dependency>
  <groupId>com.netflix.hystrix</groupId>
  <artifactId>hystrix-servo-metrics-publisher</artifactId>
  <version>1.5.9</version>
</dependency>

hystrix-servo-metrics-publisher 易于使用。提供一个单行的静态 block 就足够了HystrixPlugins.getInstance().registerMetricsPublisher(HystrixServoMetricsPublisher.getInstance());如此处所示
@EnableCircuitBreaker
@SpringBootApplication
public class ExampleApplication extends SpringBootServletInitializer {
  static {
    HystrixPlugins.getInstance().registerMetricsPublisher(HystrixServoMetricsPublisher.getInstance());
  }

  @Override
  protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
    return application.sources(ExampleApplication.class);
  }

  public static void main(String[] args) {
    SpringApplication.run(ExampleApplication.class, args);
}
} 

它工作得很好。

但是我们的项目中还需要 Spring Boot Actuator。添加依赖后
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

hystrix-servo-metrics-publisher 不再工作了。包com.netlix.servo在 JMX MBean/属性中不可用。

这是 具有禁用 spring-boot-starter-actuator 依赖项的示例项目:
hystrix-servo-metrics-publisher-jmx-example

如果启用了依赖项,则 hystrix-servo-metrics-publisher 不再起作用。

最佳答案

更新 :
我注意到您在示例项目中使用的是 Spring Boot 1.4.3,并且您的项目设置不正确。 Spring Boot 2.0.x 的情况有所不同,见下文。

您的示例项目设置问题

您正在使用 hystrix-servo-metrics-publisher版本 1.5.9 .此版本与 Hystrix 版本不兼容 1.5.3 Spring Cloud 使用 Brixton.SR5 .您可以通过启动您的应用程序来观察不兼容性,调用http://localhost:8080/remotecall (创建初始 Hystrix 指标)然后 http://localhost:8080/metrics (访问执行器端点)。然后你会得到一个 java.lang.NoSuchMethodError: com.netflix.hystrix.HystrixThreadPoolProperties.maximumSize()Lcom/netflix/hystrix/strategy/properties/HystrixProperty; .将版本设置为 1.5.3解决了这个问题。

Spring Boot 1.x 解决方案

使用 Actuator 不再显示 JMX 指标的原因是由 ServoMetricsAutoConfiguration 引起的。 ,如果使用 Spring Boot Actuator 则激活。这里暴露了一个监视器注册 bean,它的配置依赖于 SpringMetricsConfigBean .新的默认注册表类是 BasicMonitorRegistry .

要恢复原来的默认 JMX 监视器注册表,添加 resources/application.properties与行 netflix.metrics.servo.registryClass=com.netflix.servo.jmx.JmxMonitorRegistry .
通过这种方式,指标通过 JMX 和 Spring Actuator 指标端点公开。

Spring Boot 2.0.x 解决方案

对于 Spring Boot 2,问题是不同的。我将问题追溯到 io.micrometer.core.instrument.binder.hystrix.HystrixMetricsBinder ( micrometerspring-boot-actuator-autoconfigure 的依赖项)。在这里,任何现有的发布者都被替换为 MicrometerMetricsPublisherMetricsAutoConfiguration类被触发。因此,声明 HystrixPlugins.getInstance().registerMetricsPublisher(HystrixServoMetricsPublisher.getInstance());没有达到预期的效果。发布者被简单地丢弃了......

Hystrix 插件的问题是每个插件类型一次只能注册一个插件。因此,一种解决方案是用“元”插件替换现有插件,该插件委托(delegate)给多个插件实例。 HystrixSecurityAutoConfiguration 中也使用了这种方法.通过下面的配置类,我设法通过 JMX 和 Spring Boot Actuator(例如/actuator/metrics/hystrix.execution)公开了 Hystrix 指标:

import com.netflix.hystrix.*;
import com.netflix.hystrix.contrib.servopublisher.HystrixServoMetricsPublisher;
import com.netflix.hystrix.strategy.HystrixPlugins;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;
import com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;
import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher;
import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherCollapser;
import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherCommand;
import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherThreadPool;
import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;

@Configuration
@ConditionalOnClass({Hystrix.class, HystrixServoMetricsPublisher.class})
@AutoConfigureAfter(MetricsAutoConfiguration.class)
public class HystrixServoAndMicrometerConfig {

    @PostConstruct
    public void init() {
        // Keeps references of existing Hystrix plugins
        HystrixMetricsPublisher existingMetricsPublisher = HystrixPlugins.getInstance().getMetricsPublisher();
        HystrixConcurrencyStrategy concurrencyStrategy = HystrixPlugins.getInstance().getConcurrencyStrategy();
        HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance().getEventNotifier();
        HystrixPropertiesStrategy propertiesStrategy = HystrixPlugins.getInstance().getPropertiesStrategy();
        HystrixCommandExecutionHook commandExecutionHook = HystrixPlugins.getInstance().getCommandExecutionHook();

        if (existingMetricsPublisher != null) {
            HystrixPlugins.reset();
            // Registers existing plugins except the new ServoAndExistingMetricsPublisher plugin
            HystrixPlugins.getInstance().registerMetricsPublisher(new ServoAndExistingMetricsPublisher(
                    existingMetricsPublisher, HystrixServoMetricsPublisher.getInstance()));
            HystrixPlugins.getInstance().registerConcurrencyStrategy(concurrencyStrategy);
            HystrixPlugins.getInstance().registerEventNotifier(eventNotifier);
            HystrixPlugins.getInstance().registerPropertiesStrategy(propertiesStrategy);
            HystrixPlugins.getInstance().registerCommandExecutionHook(commandExecutionHook);
        } else {
            HystrixPlugins.getInstance().registerMetricsPublisher(HystrixServoMetricsPublisher.getInstance());
        }
    }

    private static class ServoAndExistingMetricsPublisher extends HystrixMetricsPublisher {

        private static class ServoAndOtherMetricsPublisherCommand implements HystrixMetricsPublisherCommand {
            private final HystrixMetricsPublisherCommand servoMetricsPublisherCommand;
            private final HystrixMetricsPublisherCommand existingMetricsPublisherCommand;

            ServoAndOtherMetricsPublisherCommand(HystrixMetricsPublisherCommand servoMetricsPublisherCommand,
                                                 HystrixMetricsPublisherCommand existingMetricsPublisherCommand) {
                this.servoMetricsPublisherCommand = servoMetricsPublisherCommand;
                this.existingMetricsPublisherCommand = existingMetricsPublisherCommand;
            }

            @Override
            public void initialize() {
                servoMetricsPublisherCommand.initialize();
                existingMetricsPublisherCommand.initialize();
            }
        }

        private final HystrixMetricsPublisher existingMetricsPublisher;
        private final HystrixMetricsPublisher servoMetricsPublisher;

        ServoAndExistingMetricsPublisher(HystrixMetricsPublisher existingMetricsPublisher,
                                         HystrixMetricsPublisher servoMetricsPublisher) {
            this.existingMetricsPublisher = existingMetricsPublisher;
            this.servoMetricsPublisher = servoMetricsPublisher;
        }

        @Override
        public HystrixMetricsPublisherCommand getMetricsPublisherForCommand(HystrixCommandKey commandKey, HystrixCommandGroupKey commandGroupKey, HystrixCommandMetrics metrics, HystrixCircuitBreaker circuitBreaker, HystrixCommandProperties properties) {
            HystrixMetricsPublisherCommand servoMetricsPublisherCommand = servoMetricsPublisher.getMetricsPublisherForCommand(commandKey, commandGroupKey, metrics, circuitBreaker, properties);
            HystrixMetricsPublisherCommand existingMetricsPublisherCommand = existingMetricsPublisher.getMetricsPublisherForCommand(commandKey, commandGroupKey, metrics, circuitBreaker, properties);
            return new ServoAndOtherMetricsPublisherCommand(servoMetricsPublisherCommand, existingMetricsPublisherCommand);
        }

        @Override
        public HystrixMetricsPublisherThreadPool getMetricsPublisherForThreadPool(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolMetrics metrics, HystrixThreadPoolProperties properties) {
            return servoMetricsPublisher.getMetricsPublisherForThreadPool(threadPoolKey, metrics, properties);
        }

        @Override
        public HystrixMetricsPublisherCollapser getMetricsPublisherForCollapser(HystrixCollapserKey collapserKey, HystrixCollapserMetrics metrics, HystrixCollapserProperties properties) {
            return servoMetricsPublisher.getMetricsPublisherForCollapser(collapserKey, metrics, properties);
        }
    }
}

关于spring-boot-starter-actuator 与 hystrix-servo-metrics-publisher 冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42509711/

相关文章:

spring-boot - 将 liquibase 添加到现有 Spring Boot 项目的正确方法

java - 将上下文路径添加到 Spring Boot 应用程序

tomcat - 如何在通过 jenkins 将 war 文件部署到 AWS beanstalk 时包含 .ebextensions 目录?

spring-boot - Netflix 功能区和 Hystrix 超时

spring - 将 Spring(Boot?)添加到现有的 RESTEasy JAX-RS 应用程序

spring-boot - 如何在 Turbine 中添加额外的 Hystrix 指标聚合

java - 无法在回退方法中从父线程访问 InheritableThreadLocal 对象

Hystrix 配置说明 : metrics. rollingStats.timeInMilliseconds

java - 将 HystrixCommands 迁移到 Resilience4j

java - Spring boot可复用springdoc-openapi参数注解