9.Hystrix实践篇

本文介绍了如何在电影服务中使用Hystrix进行业务降级处理,包括引入依赖、配置降级方法和异常处理。同时,展示了Feign如何与Hystrix整合,实现服务间的熔断。另外,还探讨了Zuul结合Hystrix对电影和影厅服务的熔断策略。所有这些措施都是为了提高系统的稳定性和可用性。
摘要由CSDN通过智能技术生成

1.业务降级(在film服务工程中修改)
(1).引入依赖

 <dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

(2).controller层开发
在FilmController类中新增获取电影列表降级方法findFilmListFallback,并在findFilmList方法上添加@HystrixCommand注解,具体代码如下。

@Slf4j
@RestController
@RequestMapping("/films")
public class FilmController {
	//获取电影列表降级方法
	public ServerResponse findFilmListFallback(@RequestBody BasePageVO basePageVO) throws CommonServiceException {
        return ServerResponse.createByErrorCodeMessage(500, "请求处理降级返回");
    }

	//获取电影列表
    @HystrixCommand(fallbackMethod = "findFilmListFallback", commandProperties = {
            @HystrixProperty(name = "execution.isolation.strategy", value = "THREAD"),
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000"),
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50")
    }, threadPoolProperties = {
            @HystrixProperty(name = "coreSize", value = "10"),
            @HystrixProperty(name = "keepAliveTimeMinutes", value = "1000"),
            @HystrixProperty(name = "maxQueueSize", value = "10"),
            @HystrixProperty(name = "queueSizeRejectionThreshold", value = "8"),
            @HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "12"),
            @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "1500")
    })
    @RequestMapping(value = "/findFilmList", method = RequestMethod.POST)
    public ServerResponse findFilmList(@RequestBody BasePageVO basePageVO) throws CommonServiceException {
        //检查入参
        basePageVO.checkParam();
        if (basePageVO.getPageSize() > 1000) {
            //业务执行出现异常,触发fallback
            throw new CommonServiceException(500, "pageSIze太大");
        }

        //调用逻辑层,获取返回参数
        IPage<Film> results = filmService.findFilmList(basePageVO.getCurrentPage(), basePageVO.getPageSize());

        return ServerResponse.createBySuccess(PageUtil.getPageResult(results));
    }
}

(3).启动项目
在启动类MoviesFilmApplication上新增注解@EnableHystrix,然后启动项目。

@MapperScan(basePackages = {"com.steven.movies.film.dao"})
@EnableHystrix
@EnableDiscoveryClient
@SpringBootApplication
public class MoviesFilmApplication {

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

}

(4).测试
启动项目,然后在postman中请求“localhost:8080/movies/film-api/films/findFilmList”,可以查询到相应的信息,测试结果如下图所示。
在这里插入图片描述

(5).业务异常
业务执行异常,希望通过CommonServiceException抛出异常信息,而不是进入降级处理,解决方法是在@HystrixCommand注解里增加ignoreExceptions属性。

@Slf4j
@RestController
@RequestMapping("/films")
public class FilmController {
	//获取电影列表降级方法
	public ServerResponse findFilmListFallback(@RequestBody BasePageVO basePageVO) throws CommonServiceException {
        return ServerResponse.createByErrorCodeMessage(500, "请求处理降级返回");
    }

	//获取电影列表
    @HystrixCommand(fallbackMethod = "findFilmListFallback", commandProperties = {
            @HystrixProperty(name = "execution.isolation.strategy", value = "THREAD"),
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000"),
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50")
    }, threadPoolProperties = {
            @HystrixProperty(name = "coreSize", value = "10"),
            @HystrixProperty(name = "keepAliveTimeMinutes", value = "1000"),
            @HystrixProperty(name = "maxQueueSize", value = "10"),
            @HystrixProperty(name = "queueSizeRejectionThreshold", value = "8"),
            @HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "12"),
            @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "1500")
    }, ignoreExceptions = {CommonServiceException.class})
    @RequestMapping(value = "/findFilmList", method = RequestMethod.POST)
    public ServerResponse findFilmList(@RequestBody BasePageVO basePageVO) throws CommonServiceException {
        //检查入参
        basePageVO.checkParam();
        if (basePageVO.getPageSize() > 1000) {
            //业务执行出现异常,触发fallback
            throw new CommonServiceException(500, "pageSIze太大");
        }

        //调用逻辑层,获取返回参数
        IPage<Film> results = filmService.findFilmList(basePageVO.getCurrentPage(), basePageVO.getPageSize());

        return ServerResponse.createBySuccess(PageUtil.getPageResult(results));
    }
}

启动项目,然后在postman中请求“localhost:8080/movies/film-api/films/findFilmList”,可以查询到相应的信息,测试结果如下图所示。
在这里插入图片描述

2.Feign整合Hystrix(在hall服务工程中修改)
(1).依赖
Feign中包含了Hystrix,因此不需要引入依赖。

(2).引入配置

feign:
  hystrix:
    enabled: true

(3).Fallback开发
在feign目录下新建FilmFeignFallbackAPIImpl类,具体代码如下。

@Slf4j
@Service
public class FilmFeignFallbackAPIImpl implements FilmFeignAPI {
    @Override
    public ServerResponse findFilmListByHallId(Integer hallId) {
        log.error("请求处理降级返回");
        return ServerResponse.createByErrorCodeMessage(500, "请求处理降级返回");
    }
}

在@FeignClient注解上添加fallback属性。

@FeignClient(name = "film.service", path = "/films",fallback = FilmFeignFallbackAPIImpl.class)
public interface FilmFeignAPI extends BaseFeignAPI {
    //根据影厅id获取电影信息
    @RequestMapping(value = "/findFilmListByHallId/{hallId}", method = RequestMethod.GET)
    ServerResponse findFilmListByHallId(@PathVariable("hallId") Integer hallId);
}

(4).测试
不启动电影服务,模拟电影服务不可用触发fallback的场景,启动影厅服务,然后在postman中请求“localhost:8080/movies/hall-api/halls/findFilmListByHallIds”,可以查询到相应的信息,测试结果如下图所示。
在这里插入图片描述
在这里插入图片描述
由上图可知,影厅服务调用电影服务失败,触发fallback,一共触发6次。

(5).hall服务工程目录结构
在这里插入图片描述

4.Zuul整合Hystrix(在zuul和film服务工程中修改)
(1).引入配置

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timoutInMilliseconds: 1000

(2).fallback开发
首先在项目目录“/src/main/java/com/steven/movies/zuul”下新建“/fallback”目录,并在fallback目录下新建FilmProviderFallback和HallProviderFallback类,具体代码如下。

@Slf4j
@Component
public class FilmProviderFallback implements FallbackProvider {
    @Override
    public String getRoute() {
        return "film.service";
    }

    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        return new ClientHttpResponse() {
            //ClientHttpResponse的fallback状态码,返回HttpStatus
            @NonNull
            @Override
            public HttpStatus getStatusCode() {
                return HttpStatus.INTERNAL_SERVER_ERROR;
            }

            //ClientHttpResponse的fallback状态码,返回int
            @Override
            public int getRawStatusCode() {
                return this.getStatusCode().value();
            }

            //ClientHttpResponse的fallback状态码,返回String
            @NonNull
            @Override
            public String getStatusText() {
                return this.getStatusCode().getReasonPhrase();
            }

            //回收资源方法,用于回收当前fallback逻辑开启的资源对象
            @Override
            public void close() {

            }

            //设置方法体,Zuul会将本方法返回的输入流数据读取,并且通过HttpServletResponse的输出流输出到客户端
            @NonNull
            @Override
            public InputStream getBody() {
                log.error("zuul time:{}",System.currentTimeMillis());
                String result = "电影服务不可用";
                return new ByteArrayInputStream(result.getBytes(StandardCharsets.UTF_8));
            }

            //设置响应头
            @NonNull
            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders httpHeaders = new HttpHeaders();
                httpHeaders.setContentType(new MediaType("application", "json", StandardCharsets.UTF_8));
                return httpHeaders;
            }
        };
    }
}
@Slf4j
@Component
public class HallProviderFallback implements FallbackProvider {
    @Override
    public String getRoute() {
        return "hall.service";
    }

    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        return new ClientHttpResponse() {
            //ClientHttpResponse的fallback状态码,返回HttpStatus
            @NonNull
            @Override
            public HttpStatus getStatusCode() {
                return HttpStatus.INTERNAL_SERVER_ERROR;
            }

            //ClientHttpResponse的fallback状态码,返回int
            @Override
            public int getRawStatusCode() {
                return this.getStatusCode().value();
            }

            //ClientHttpResponse的fallback状态码,返回String
            @NonNull
            @Override
            public String getStatusText() {
                return this.getStatusCode().getReasonPhrase();
            }

            //回收资源方法,用于回收当前fallback逻辑开启的资源对象
            @Override
            public void close() {

            }

            //设置方法体,Zuul会将本方法返回的输入流数据读取,并且通过HttpServletResponse的输出流输出到客户端
            @NonNull
            @Override
            public InputStream getBody() {
                String result = "影厅服务不可用";
                return new ByteArrayInputStream(result.getBytes(StandardCharsets.UTF_8));
            }

            //设置响应头
            @NonNull
            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders httpHeaders = new HttpHeaders();
                httpHeaders.setContentType(new MediaType("application", "json", StandardCharsets.UTF_8));
                return httpHeaders;
            }
        };
    }
}

(3).film服务修改

@Slf4j
@RestController
@RequestMapping("/films")
public class FilmController {
    @Autowired
    private IFilmService filmService;

    @Value("${server.port}")
    private int port;

    public ServerResponse findFilmListFallback(@RequestBody BasePageVO basePageVO) throws CommonServiceException {
        log.error("film time:{}", System.currentTimeMillis());
        return ServerResponse.createByErrorCodeMessage(500, "请求处理降级返回");
    }

    //获取电影列表
    @HystrixCommand(fallbackMethod = "findFilmListFallback", commandProperties = {
            @HystrixProperty(name = "execution.isolation.strategy", value = "THREAD"),
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "900"),
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50")
    }, threadPoolProperties = {
            @HystrixProperty(name = "coreSize", value = "10"),
            @HystrixProperty(name = "keepAliveTimeMinutes", value = "1000"),
            @HystrixProperty(name = "maxQueueSize", value = "10"),
            @HystrixProperty(name = "queueSizeRejectionThreshold", value = "8"),
            @HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "12"),
            @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "1500")
    }, ignoreExceptions = {CommonServiceException.class})
    @RequestMapping(value = "/findFilmList", method = RequestMethod.POST)
    public ServerResponse findFilmList(@RequestBody BasePageVO basePageVO) throws CommonServiceException, InterruptedException {
        //检查入参
        basePageVO.checkParam();
        if (basePageVO.getPageSize() > 1000) {
            //休眠1秒,触发超时熔断
            Thread.sleep(1000);
        }

        //调用逻辑层,获取返回参数
        IPage<Film> results = filmService.findFilmList(basePageVO.getCurrentPage(), basePageVO.getPageSize());

        return ServerResponse.createBySuccess(PageUtil.getPageResult(results));
    }
}

(4).测试
启动项目,然后在postman中请求“localhost:8080/movies/film-api/films/findFilmList”,可以查询到相应的信息,测试结果如下图所示。
在这里插入图片描述
在postman中请求“localhost:8080/movies/hall-api/halls/findFilmListByHallIds”,可以查询到相应的信息,测试结果如下图所示。

在这里插入图片描述

(5).zuul服务工程目录结构
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值