SpringCloud-hystrix 理解服务容错保护

微服务架构中,系统往往拆分成多个服务单元,各单元的应用间通过服务注册与订阅方式相互依赖,由于各单元都在不同的进程中运行,依赖通过远程调用的方式执行,可能会因为网络原因导致调用失败,就需要服务容错保护。

下面创建一个hystrix客户端,点击这里创建一个Gradle工程,boot版本用1.5.x,添加依赖如下:

dependencyManagement {
    imports {
        mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Edgware.SR4'
    }
}

dependencies {
    compile('org.springframework.boot:spring-boot-starter')
    compile('org.springframework.boot:spring-boot-starter-web')
    compile('org.springframework.boot:spring-boot-starter-actuator')
    compile 'org.slf4j:slf4j-api:1.7.14'
    compile('org.springframework.cloud:spring-cloud-starter-hystrix')
    compile('org.springframework.cloud:spring-cloud-starter-eureka')
    compile('org.springframework.cloud:spring-cloud-starter-ribbon')
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

然后编写配置文件application.properties

spring.application.name=hystrix-base
server.port=8088

eureka.client.serviceUrl.defaultZone=http://peer1:1111/eureka/,http://peer1:1111/eureka/

注意,先启动上一章中的注册中心服务,单机或集群都可以。

打开断路器,2种方式

@EnableHystrix
or
@EnableCircuitBreaker

@EnableHystrix包含@EnableCircuitBreaker

编写controller,模拟服务超时引发断路,如下:

@RestController
public class HystrixDemoController {
    private final static Random random = new Random();

    @GetMapping("hello")
    @HystrixCommand(fallbackMethod = "error",commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "100")
    })
    public String hello()throws Exception{
        int value = random.nextInt(200);
        System.out.println("hello() costs "+ value + " ms.");
        Thread.sleep(value);
        return "hello";
    }

    public String error(){
        return "error";
    }

上面的代码,定义一个hello接口,使用@HystrixCommand配置接口断路超时时间为100毫秒,即超过100毫秒即引发断路。
启动服务,可以在注册中心http://localhost:1111/看到注册的服务,然后输入http://localhost:8088/hello并不断刷新,可以看到超时时会输出error。

其实,我们可以使用future模拟实现hystrix下,简单理解hystrix,如:

Random random = new Random();
        ExecutorService service = Executors.newFixedThreadPool(1);
        Future future = service.submit(()->{
            int value = random.nextInt(200);
            System.out.println("hello() costs "+ value + " ms.");
            Thread.sleep(value);
            return "hello";
        });
        try {
            future.get(100, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            System.out.println("超时保护!");
        }

先创建一个线程池,然后提交一个任务得到future,给get设置时间限制,超出则报异常。

若使用future模拟hystrix是优秀的,那另一种方式将是卓越的,就是rxjava,下面先了解下线程控制的几个方法:

//直接在当前线程运行
Schedulers.immediate()
//启动新线程并在新线程执行操作
Schedulers.newThread()
//内部实现一个无上限的线程池,可重用空闲线程
Schedulers.io()

接下来,我们用rxjava实现一下hystrix,如下:

Random random = new Random();
        Single.just("Hello")
                .subscribeOn(Schedulers.immediate()) 
                .subscribe(new Observer() {
                    @Override
                    public void onCompleted() {
                        System.out.println("执行完毕!");
                    }
                    @Override
                    public void onError(Throwable e) {
                        System.out.println("熔断保护!");
                    }
                    @Override
                    public void onNext(String s) {
                        int value = random.nextInt(200);
                        System.out.println("hello() costs "+ value + " ms.");
                        if (value > 100) {
                            throw new RuntimeException("Timeout!");
                        }
                    }
                });

上面就是在当前线程中发射字符串hello,若大于100毫秒则抛异常进入onError,否则进入onCompleted。
通过上面2种方式的模拟,相信大家对hystrix不再陌生,但是对它的使用还不太熟悉吧,除了注解的方式,我们还将介绍另一种方式--编程方式,如下:

    @GetMapping("hello2")
    public String hello2()throws Exception{
        return new HelloCommand().execute();
    }

    private class HelloCommand extends com.netflix.hystrix.HystrixCommand {
        protected HelloCommand(){
            super(HystrixCommandGroupKey.Factory.asKey("Hello"),100);//100毫秒
        }

        @Override
        protected String run() throws Exception {
            int value = random.nextInt(200);
            System.out.println("hello2() costs "+ value + " ms.");
            Thread.sleep(value);
            return "hello2";
        }

        @Override
        protected String getFallback() {
            return HystrixDemoController.this.error();
        }
    }

这是通过继承HystrixCommand实现自定义命令,可以更新灵活的实现自己的需求,但写法比较复杂。
学习交流,请加群:64691032

你可能感兴趣的:(SpringCloud-hystrix 理解服务容错保护)