Hystrix里面的一项核心功能,就是资源隔离,就是将多个依赖服务的调用分别隔离到各自的资源池内。避免对某一个依赖服务的调用,因为依赖服务的延迟或失败,导致服务所有的线程资源全部耗费在这个服务的接口调用上。
Hystrix实现资源隔离,主要有两种技术:
- 线程池
- 信号量
1.信号量机制
信号量的资源隔离只是起到一个开关的作用,比如,服务A的信号量大于3,那么就是说它同时只允许有3个线程来访问服务A,其他的请求都会被拒绝,从而达到资源隔离和限流保护的作用。
2.线程池与信号量的区别
线程池隔离技术,使用Hystrix自己的线程去执行调用;信号量隔离技术,是直接让tomcat线程去调用依赖服务,信号量有多少,就允许多少个tomcat线程调用它。
适用场景:
- 线程池隔离:适合大多数场景,比如对依赖服务的网络请求的调用和访问、需要对调用的timeout进行控制。
信号量隔离:适合不是对外部依赖的访问,而是对内部的比较复杂的业务逻辑的访问,不涉及任何网络的请求。
3.信号量简单Demo
例子:我们在从商品服务获取到商品数据后,还要去获取商品属于哪个地理位置、省、市、区等。这些数据我们可能只需要在自己本地内存中获取,比如Map中。
public class LocationCache {private static final Map<Long, String> CITY_MAP = new HashMap<>();static {CITY_MAP.put(1L, "北京");}/*** 通过cityId 获取 cityName** @param cityId 城市id* @return 城市名*/public static String getCityName(Long cityId) {return CITY_MAP.get(cityId);}}
写一个CityNameCommand,策略设置为信号量。run()方法中获取本地缓存。目的是对本地缓存进行资源隔离。
public class CityNameCommand extends HystrixCommand<String> {private final Long cityId;public CityNameCommand(Long cityId) {// 设置信号量隔离策略super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("GetCityNameGroup")).andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE)));this.cityId = cityId;}@Overrideprotected String run() {// 需要进行信号量隔离的代码return LocationCache.getCityName(cityId);}}
在接口层,通过创建CityNameCommand,传入 cityId,执行 execute() 方法,那么获取本地 cityName 缓存的代码将会进行信号量的资源隔离。
@GetMapping("/v2/product-info")public String getProductInfoV2(Long productId) {HystrixCommand<ProductInfo> getProductInfoCommand = new ProductInfoCommand(productId);// 通过command执行,获取最新商品数据ProductInfo productInfo = getProductInfoCommand.execute();Long cityId = productInfo.getCityId();CityNameCommand cityNameCommand = new CityNameCommand(cityId);// 获取本地内存(cityName)的代码会被信号量进行资源隔离String cityName = cityNameCommand.execute();productInfo.setCityName(cityName);System.out.println(productInfo);return "success";}
