基礎篇——Spring Cloud Hystrix
一、Hystrix使用之建立請求命令
繼承HystrixCommand:
public class UserCommand extends HystrixCommand<User> { private RestTemplate restTemplate; private Long id; public UserCommand(Setter setter, RestTemplate restTemplate, Long id) { super(setter); this.restTemplate = restTemplate;this.id = id; } @Override protected User run() { return restTemplate.getForObject("http://USER-SERVICE/user?id={1}", User.class, id); } }
注:同步執行,User user = new UserCommand(restTemplate, 1L).execute();
非同步執行,Future<User> futureUser = new UserCommand(restTemplate, 1L).queue();
Hot Observable,Observable<String> ho = new UserCommand(restTemplate, 1L).observe();
Cold Observable,Observable<String> go = new UserCommand(restTemplate, 1L).toObservable();
註解@HystrixCommand實現同步執行:
public class UserService { @Autowired private RestTemplate restTemplate; @HystrixCommandpublic User getUserById(Long id) { return restTemplate.getForObject("http://USER-SERVICE/user?id={1}", User.class, id); } }
註解@HystrixCommand實現非同步執行:
public class UserService { @Autowired private RestTemplate restTemplate; @HystrixCommand public Future<User> getUserByIdAsync(final String id) { return new AsyncResult<User>() { @Override public User invoke() { return restTemplate.getForObject("http://USER-SERVICE/user?id= {1}", User.class, id); } }; } }
繼承HystrixObservableCommand:
public class UserObservableCommand extends HystrixObservableCommand<User> { private RestTemplate restTemplate; private Long id; public UserObservableCommand(Setter setter, RestTemplate restTemplate, Long id) { super(setter); this.restTemplate = restTemplate; this.id = id; } @Override protected Observable<User> construct() { return Observable.create(new Observable.OnSubscribe<User>(){ @Override public void call(Subscribe<? super User> observable) { try { if (!observable.isSubscribed()) { User user = restTemplate.getForObject("http://USER-SERVICE/user?id={1}", User.class, id); observable.onNext(user); observable.onCompleted(); } } catch (Exception e) { observable.onError(e); } } }); } }
註解@HystrixCommand實現響應式命令:
public class UserService { @Autowired private RestTemplate restTemplate; @HystrixCommand public Observable<User> getUserById(final String id) { return Observable.create(new Observable.OnSubscribe<User>() { @Override public void call(Subscribe<? super User> observable) { try { if (!observable.isSubscribe()) { User user = restTemplate.getForObject("http://USER-SERVICE/user?id={1}", User.class, id); observable.onNest(user); observable.onCompleted(); } } catch (Exception e) { observable.onError(e); } } }); } }
二、定義服務降級
對於有返回值的服務,也就是說呼叫者需要請求服務獲取到某些有用的資訊,如果在HystrixCommand或HystrixObservableCommand執行出現錯誤、超時、執行緒池拒絕、斷路器熔斷等情況,需要進行服務降級處理來保障呼叫者的體驗。對於繼承HystrixCommand執行請求服務,需要重寫getFallBack方法;
public class UserCommand extends HystrixCommand<User> { @Override protected User getFallBack() { return new User(); } }
對於繼承HystrixObservableCommand執行請求服務,需要重寫resumeWithFallBack方法;
public class UserObservableCommand extends HystrixObservableCommand<User> { @Override protected User resumeWithFallBack() { return new User(); } }
對於註解@HystrixCommand執行請求服務,需要使用屬性fallBackMethod="方法名",且“方法名”必須在同一類中;
public class UserService { @Autowired private RestTemplate restTemplate; @HystrixCommand(fallBackMethod="defaultUserById") public Observable<User> getUserById(final String id) { return Observable.create(new Observable.OnSubscribe<User>() { @Override public void call(Subscribe<? super User> observable) { try { if (!observable.isSubscribe()) { User user = restTemplate.getForObject("http://USER-SERVICE/user?id={1}", User.class, id); observable.onNest(user); observable.onCompleted(); } } catch (Exception e) { observable.onError(e); } } }); } protected User defaultUserById() { return new User(); } }
當然對於一些不需要服務返回必須有用資訊的請求,可以選擇不使用服務降級處理,可以直接將錯誤資訊返回給呼叫者即可。例如:使用HystrixCommand請求寫操作的服務,如果寫入不成功,直接將錯誤返回給呼叫者,通知其稍後重試即可。
三、異常處理
Hystrix執行請求服務的異常有兩種,HystrixBadRequestException和其他。因為服務降級策略的存在,除了由HystrixBadRequestException包裝的異常外,其他的所有異常都會觸發服務降級策略。註解@HystrixCommand通過屬性ignoreExceptions實現指定異常向HystrixBadRequestException的包裝,當服務請求出現指定異常時,不觸發服務降級策略。
當發生服務降級時,獲取詳細的異常服務,在繼承類HystrixCommand或HystrixObserableCommand中,通過其父類方法getExecutionException獲得;
@Override protected User getFallBack() { Throwable e = getExecutionException(); return new User(); }
註解@HystrixCommand屬性fallBackMethod指定方法中接收引數Throwable e;
protected User defaultUserById(Throwable e) { return new User(); }
四、命令名稱、分組以及執行緒池劃分
分組、命令名稱和執行緒池劃分是Hystrix對服務請求的細粒化分配,即此次服務請求被分配到某組某個執行緒池的某個命令,能夠更好的統計和分配,在繼承方式中設定組名、命令名稱和劃分的執行緒池名稱;
public UserCommand(RestTemplate restTemplate, Long id) { super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("GroupName")) .andCommandKey(HystrixCommandKey.Factory.asKey("CommandName")) .andThreadPoolKey(HystrixCommandThreadPoolKey.Factory.asKey("ThreadPoolKey"))); this.restTemplate = restTemplate; this.id = id; }
註解@HystrixCommand通過屬性groupKey、commandKey、threadPoolKey來設定服務請求的組、命令和執行緒池劃分;
@HystrixCommand(fallBackMethod="defaultUserById", groupKey="UserGroup", commandKey="getUserById", threadPoolKey="userThreadPool") public Observable<User> getUserById(final String id) { return Observable.create(new Observable.OnSubscribe<User>() { @Override public void call(Subscribe<? super User> observable) { try { if (!observable.isSubscribe()) { User user = restTemplate.getForObject("http://USER-SERVICE/user?id={1}", User.class, id); observable.onNest(user); observable.onCompleted(); } } catch (Exception e) { observable.onError(e); } } }); }