资源隔离,就是说,如果把对某一个依赖服务的所有调用请求,全部隔离在同一份资源池内,不会去占用其他资源了,这就叫做资源隔离。
Hystrix进行资源隔离,其实是提供了一个抽象,叫做command。这也是Hystrix最基本的资源隔离技术。

1.利用HystrixCommand获取单条数据

通过将调用商品服务的操作封装到HystrixCommand中,限定一个key,比如下面的GetProductInfoCommandGroup,我们可以简单的认为这是一个线程池,每次调用商品服务,就只会用该线程池中的资源,不会再去用其他线程资源了。

  1. public class GetProductInfoCommand extends HystrixCommand<ProductInfo> {
  2. private final Long productId;
  3. public GetProductInfoCommand(Long productId) {
  4. super(HystrixCommandGroupKey.Factory.asKey("GetProductInfoCommandGroup"));
  5. this.productId = productId;
  6. }
  7. @Override
  8. protected ProductInfo run() {
  9. System.out.println("hello~!");
  10. String url = "http://localhost:8081/product-info?productId=" + productId;
  11. // 调用商品服务接口
  12. String response = HttpUtil.get(url);
  13. return JSONObject.parseObject(response, ProductInfo.class);
  14. }
  15. }

我们在缓存服务接口中,根据productId创建command并执行,获取到商品数据。

  1. @GetMapping("/product-info")
  2. public String getProductInfo(Long productId) {
  3. HystrixCommand<ProductInfo> command = new GetProductInfoCommand(productId);
  4. // 通过command执行,获取最新商品数据
  5. ProductInfo productInfo = command.execute();
  6. System.out.println(productInfo);
  7. return "success";
  8. }

上面执行的是excute()方法,是同步的。也可以对command调用queue()方法,它仅仅将command放入线程池的一个等待队列,就立即返回,拿到一个Future对象,后面可以继续做其他事情,然后过一段时间对Future调用get()方法获取数据,这是异步。

2.利用HystrixObservableCommand批量获取数据

只要是获取商品数据,全部都绑定到同一个线程池里面取,我们通过HystriObservableCommand的一个线程取执行,而在这个线程里面,批量把多个productId的productInfo获取到。

  1. public class GetProductsInfoCommand extends HystrixObservableCommand<ProductInfo> {
  2. private final List<Long> productIds;
  3. public GetProductsInfoCommand(List<Long> productIds) {
  4. // 还是绑定在同一个线程池
  5. super(HystrixCommandGroupKey.Factory.asKey("GetProductInfoGroup"));
  6. this.productIds = productIds;
  7. }
  8. @Override
  9. protected Observable<ProductInfo> construct() {
  10. return Observable.unsafeCreate((Observable.OnSubscribe<ProductInfo>) subscriber -> {
  11. for (Long productId : productIds) {
  12. // 批量获取商品数据
  13. String url = "http://localhost:8081/product-info?productId=" + productId;
  14. String response = HttpUtil.get(url);
  15. ProductInfo productInfo = JSONObject.parseObject(response, ProductInfo.class);
  16. subscriber.onNext(productInfo);
  17. }
  18. subscriber.onCompleted();
  19. }).subscribeOn(Schedulers.io());
  20. }
  21. }

通过上面的HystrixObservableCommand,执行一些hystrix的API,获取到所有商品数据。

  1. @GetMapping("/products-info")
  2. public String getProductsInfo(List<Long> productIds) {
  3. GetProductsInfoCommand getProductsInfoCommand = new GetProductsInfoCommand(productIds);
  4. Observable<ProductInfo> observe = getProductsInfoCommand.observe();
  5. observe.subscribe(new Observer<ProductInfo>() {
  6. @Override
  7. public void onCompleted() {
  8. System.out.println("获取完了所有的商品数据");
  9. }
  10. @Override
  11. public void onError(Throwable e) {
  12. e.printStackTrace();
  13. }
  14. /**
  15. * 获取完一条数据,就回调一次这个方法
  16. * @param productInfo 商品信息
  17. */
  18. @Override
  19. public void onNext(ProductInfo productInfo) {
  20. System.out.println(productInfo);
  21. }
  22. });
  23. return "success";
  24. }

基于Hystrix线程池技术实现资源隔离 - 图1
从Nginx开始,缓存都失效了,Nginx通过缓存服务去调用商品服务。缓存服务默认的线程大小是10,最多只有10个线程去调用商品服务的接口。即使商品服务接口故障了,最多也只有10个线程会死在调用商品服务接口的路上,缓存服务的tomcat内其它线程还是可以用来调用其他的服务。