跳至主要內容

SpringCloudNetflixHystrix

soulballad微服务SpringCloud NetfilxSpringCloud约 1216 字大约 4 分钟

Spring Cloud Netflix Hystrix

服务短路(CircuitBreaker)

QPS: Query Per Second

TPS: Transaction Per Second

QPS: 经过全链路压测,计算单机极限QPS,集群 QPS = 单机 QPS * 集群机器数量 * 可靠性比率

全链路压测 除了压 极限QPS,还有错误数量

全链路:一个完整的业务流程操作

JMeter:可调整型比较灵活

Spring Cloud Hystrix Client

官网: https://github.com/Netflix/Hystrix

Reactive Java 框架:

  • Java 9 Flow API
  • Reactor
  • RxJava(Reactive X)

激活 Hystrix

通过 @EnableHystrix 激活

Hystrix 配置信息wiki:https://github.com/Netflix/Hystrix/wiki/Configuration

注解方式(Annotation)
@RestController
public class HystrixDemoController {

    private final static Random random = new Random();

    /**
     * 当{@link #helloWorld} 方法调用超时或失败时,
     * fallback 方法{@link #errorContent()}作为替代返回
     *
     * @return
     */
    @GetMapping("hello-world")
    @HystrixCommand(fallbackMethod = "errorContent",
            commandProperties = {@HystrixProperty(
                    name = "execution.isolation.thread.timeoutInMilliseconds",
                    value = "100"
            )}
    )
    public String helloWorld() throws Exception {

        // 如果随机时间 大于 100 ,那么触发容错
        int value = random.nextInt(200);

        System.out.println("helloWorld() costs "+value+" ms.");

        Thread.sleep(value);

        return "Hello,World";
    }

    public String errorContent() {
        return "Fault";
    }
}
编程方式
    /**
     * 当{@link #helloWorld} 方法调用超时或失败时,
     * fallback 方法{@link #errorContent()}作为替代返回
     *
     * @return
     */
    @GetMapping("hello-world-2")
    public String helloWorld2() {
        return new HelloWorldCommand().execute();
    }

    /**
     * 编程方式
     */
    private class HelloWorldCommand extends com.netflix.hystrix.HystrixCommand<String> {

        protected HelloWorldCommand() {
            super(HystrixCommandGroupKey.Factory.asKey("HelloWorld"), 100);
        }

        @Override
        protected String run() throws Exception {
            // 如果随机时间 大于 100 ,那么触发容错
            int value = random.nextInt(200);

            System.out.println("helloWorld() costs " + value + " ms.");

            Thread.sleep(value);

            return "Hello,World";
        }

        //容错执行
        protected String getFallback() {
            return HystrixDemoController.this.errorContent();
        }
    }

其他 Java 执行方式

Future
public class FutureDemo {

    public static void main(String[] args) {

        Random random = new Random();

        ExecutorService service = Executors.newFixedThreadPool(1);

        Future<String> future = service.submit(() -> { // 正常流程
            // 如果随机时间 大于 100 ,那么触发容错
            int value = random.nextInt(200);

            System.out.println("helloWorld() costs " + value + " ms.");

            Thread.sleep(value);

            return "Hello,World";
        });

        try {
            future.get(100, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            // 超时流程
            System.out.println("超时保护!");
        }

        service.shutdown();
    }
}
RxJava
public class RxJavaDemo {

    public static void main(String[] args) {

        Random random = new Random();

        Single.just("Hello,World") // just 发布数据
            // 订阅的线程池 immediate = Thread.currentThread()
            .subscribeOn(Schedulers.immediate()) 
            .subscribe(new Observer<String>() {
                @Override
                public void onCompleted() { // 正常结束流程
                    System.out.println("执行结束!");
                }
                @Override
                public void onError(Throwable e) { // 异常流程(结束)
                    System.out.println("熔断保护!");
                }

                @Override
                public void onNext(String s) { // 数据消费 s = "Hello,World"
                    // 如果随机时间 大于 100 ,那么触发容错
                    int value = random.nextInt(200);

                    if (value > 100) {
                        throw new RuntimeException("Timeout!");
                    }

                    System.out.println("helloWorld() costs " + value + " ms.");
                }
            });
    }
}

Health Endpoint(/health)

{
  status: "UP",
  diskSpace: {
    status: "UP",
    total: 500096983040,
    free: 304113217536,
    threshold: 10485760
  },
  refreshScope: {
    status: "UP"
  },
  hystrix: {
    status: "UP"
  }
}

激活熔断保护

@EnableCircuitBreaker 激活 :@EnableHystrix + Spring Cloud 功能

@EnableHystrix 激活,没有一些 Spring Cloud 功能,如 /hystrix.stream 端点

Hystrix Endpoint(/hystrix.stream)

data: {
    "type": "HystrixThreadPool",
    "name": "HystrixDemoController",
    "currentTime": 1509545957972,
    "currentActiveCount": 0,
    "currentCompletedTaskCount": 14,
    "currentCorePoolSize": 10,
    "currentLargestPoolSize": 10,
    "currentMaximumPoolSize": 10,
    "currentPoolSize": 10,
    "currentQueueSize": 0,
    "currentTaskCount": 14,
    "rollingCountThreadsExecuted": 5,
    "rollingMaxActiveThreads": 1,
    "rollingCountCommandRejections": 0,
    "propertyValue_queueSizeRejectionThreshold": 5,
    "propertyValue_metricsRollingStatisticalWindowInMilliseconds": 10000,
    "reportingHosts": 1
}

Hystrix Dashboard

激活 Dashboard

@EnableHystrixDashboard

server.port=7070

@SpringBootApplication
@EnableHystrixDashboard
public class SpringCloudHystrixDashboardDemoApplication {

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

查看监控结果:

  1. actuator hystrix stream:

    最开始只显示 ping,请求 /hello-world 或者 /hello-world2 后,有请求数据显示

    1570267319372

  2. hystrix dashboard:

    1570267470159

整合 Netflix Turbine

  1. 引入 maven 依赖

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-turbine</artifactId>
    </dependency>
    
  2. 激活 trubine

    使用注解 @EnableTurbine

  3. 配置 eureka

    在 application.properties 中配置

    server.port=8080
    management.server.port=8081
    
    eureka.client.service-url.defaultZone=\
      http://localhost:9090/eureka
    eureka.instance.metadata-map.management.port = \
      ${management.server.port}
    
    # turbine 配置
    turbine.aggregator.cluster-config=CUSTOMERS
    turbine.app-config=customer
    
  4. 使用浏览器访问

    • localhost:8081/actuator/hystrix.stream

      1570266864185

    • localhost:8080/turbine.stream?cluster=CUSTOMERS

      1570266942510

    • hystrix dashboard: localhost:7070/hystrix

      1570267062918

问答部分

  1. ribbon 是用来做什么的,只能负载均衡吗?

    答: 主要用于客户端负载

  2. Kafka 与 ActiveMQ?

    答:ActiveMQ 相对来说是比较完善的中间件,Kafka 在能力上比较灵活,它放弃不少约束,性能相对较好

  3. 要提交 java 的基础,有什么好的书籍推荐吗?

    答:起始基本经典的书要读,Java编程思想、Effective Java 1和2。相关类名,比如集合,要选择读。

  4. 注释 {@link} 怎么用,什么作用啊,怎么弄出来的,没看清楚

    答:@JavaDoc 一部分,通过 Java 注释生成Html 文档。

    @link 应用某个类,比如 {@link String}

    @since 从哪个版本开始

    @author 作者

    里面嵌入 java 代码

  5. spring cloud 的config配置,获取到的 git 中的 properties 文件的一些属性(比如,my.name),可以直接在其他 spring 的 xml 中使用吗?需要怎样配置?

    答:利用注解 @ImportResource("abc.xml")

    abc.xml

    <bean id="person" class="com.gupao.domain.Person">
    	<property name="name" value="${my.name}"/>
    </bean>
    

    启动类:Main.java

    @ImportResource("abc.xml")
    @SpringBootApplication
    public class Main{
        public static void main(String[] args){
            SpringApplication.run(Main.class, args);
        }
    }
    
  6. 将实时数据缓存到 Redis,再由 Storm 去消费,这种做法好吗?有没有更好的方案

    答:Storm 消费数据需要强持久性,Redis 相比 DB 逊色一点。

  7. spring boot 中用 new SpringApplicationBuilder().sources(AppConfig.class) 方式启动,是先加载 AppConfig 还是先加载配置文件?

    答:AppConfig 是一个配置 @Configuration Class,那么配置文件是一个外部资源,其实不会相互影响。

    如果 AppConfig 中增加了 @PropertySource 或者 @PropertySources 的话,会优先加载 @PropertySource 中的配置资源

上次编辑于:
贡献者: soulballad