Spring Cloud-hystrix使用例子(七)
继承方式
HystrixCommand
public class UserSelectAllCommand extends HystrixCommand<List<User>> {
private RestTemplate restTemplate;
/**
* 设置线程组 和命令名用于仪表盘统计信息
* 设置线程组 可以使同一个组使用同一个线程池
* .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("ThreadPoolKey") 可以跟细粒度的线程池划分
* @param restTemplate
*/
public UserSelectAllCommand(RestTemplate restTemplate){
super(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("YouGroupName"))
.andCommandKey(HystrixCommandKey.Factory.asKey("YouCommandName"))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withExecutionTimeoutInMilliseconds(10000)//设置超时时间。我这边全局设置无效 就对应设置
));
this.restTemplate=restTemplate;
}
@Override
protected List<User> run() throws Exception {
return restTemplate.getForObject("http://PROVIDER/user/findAll",List.class);
}
}
@Controller
@RequestMapping("/UserHystrixCommand")
public class UserHystrixCommandContorller {
@Autowired
RestTemplate restTemplate; //同步执行
@RequestMapping("/findAll")
@ResponseBody
public List<User> findAll() {
UserSelectAllCommand userSelectAllCommand = new UserSelectAllCommand(restTemplate);
return userSelectAllCommand.execute();
} //异步
@RequestMapping("/findAllAsyn")
@ResponseBody
public List<User> findAllAsyn() throws ExecutionException, InterruptedException {
UserSelectAllCommand userSelectAllCommand = new UserSelectAllCommand(restTemplate);
return userSelectAllCommand.queue().get();
} }
调用execute同步执行 queue 返回Future 异步执行
还可以通过执行
Observable observable= userSelectAllCommand.toObservable();//订阅的时候发起请求
Observable observable=userSelectAllCommand.observe();//立即发起请求
通过订阅获得请求结果
observable.subscribe(new Subscriber() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onNext(Object o) {
}
});
HystrixObservableCommand
与HystrixCommand是可以发射多次结果
public class UserSelectObservableCommand extends HystrixObservableCommand<User> {
/**
* 设置线程组 和命令名用于仪表盘统计信息
* 设置线程组 可以使同一个组使用同一个线程池
* .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("ThreadPoolKey") 可以跟细粒度的线程池划分
* @param restTemplate
*/
@Autowired
RestTemplate restTemplate;
private List<Integer> ids;
public UserSelectObservableCommand(List<Integer> ids, RestTemplate restTemplate) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("YouGroupName"))
.andCommandKey(HystrixCommandKey.Factory.asKey("YouCommandName"))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withExecutionTimeoutInMilliseconds(10000)//设置超时时间。我这边全局设置无效 就对应设置
));
this.restTemplate=restTemplate;
this.ids=ids;
}
@Override
protected Observable<User> construct() {
return Observable.create(new Observable.OnSubscribe<User>() {
@Override
public void call(Subscriber<? super User> subscriber) {
try{
if(!subscriber.isUnsubscribed()){
for (Integer id:
ids) {
MultiValueMap<String, String> map= new LinkedMultiValueMap<String, String>();
map.add("id",id.toString());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(map, headers);
//调用多次服务
User user=restTemplate.postForEntity("http://PROVIDER/user/findById", request,User.class).getBody();
subscriber.onNext(user);
}
}
subscriber.onCompleted();
}catch (Exception e){
e.printStackTrace();
subscriber.onError(e);
}
}
}).subscribeOn(Schedulers.io());
}
/**
* 服务降级执行逻辑
* 错误 超时 线程池拒绝 断路器熔断 执行
* @return
*/
@Override
protected Observable<User> resumeWithFallback() {
return Observable.create(new Observable.OnSubscribe<User>() {
@Override
public void call(Subscriber<? super User> observer) {
try {
if (!observer.isUnsubscribed()) {
User u = new User();
observer.onNext(u);
observer.onCompleted();
}
} catch (Exception e) {
observer.onError(e);
}
}
}).subscribeOn(Schedulers.io());
}
}
//异步
@RequestMapping("/process")
@ResponseBody
public void process() throws ExecutionException, InterruptedException {
UserSelectObservableCommand userSelectObservableCommand=new UserSelectObservableCommand(Arrays.asList(new Integer[]{1,2,3,4,6}),restTemplate);
Observable<User> observable= userSelectObservableCommand.observe();
observable.subscribe(new Subscriber<User>(){
List<User> users=new ArrayList<User>(); @Override
public void onCompleted() {
users.stream().forEach(c->{
System.out.println(c.getName());
}); } @Override
public void onError(Throwable throwable) { } @Override
public void onNext(User user) {
users.add(user);
}
}); }
注解方式
@Component
public class UserService {
@Autowired
RestTemplate restTemplate; @HystrixCommand(groupKey = "userService",commandKey = "findAll")
public List<User> findAll(){
return restTemplate.getForObject("http://PROVIDER/user/findAll",List.class);
} @HystrixCommand
public Future<List<User>> findAllAsyn(){
return new AsyncResult<List<User>>() {
@Override
public List<User> invoke() {
return findAll();
}
};
} /**
* ObservableExecutionMode.EAGER observe ()
* ObservableExecutionMode.LAZY toObservable ()
* ignoreExceptions 排除异常
* @param id
* @return
*/
@HystrixCommand(observableExecutionMode = ObservableExecutionMode.EAGER,ignoreExceptions = BusinessException.class)
public Observable<User> findUserByIdA(Integer id){ return Observable.create(new Observable.OnSubscribe<User>(){ @Override
public void call(Subscriber<? super User> subscriber) {
//判断是否取消订阅
if(subscriber.isUnsubscribed()){
User user=restTemplate.getForObject("http://PROVIDER/user/findById",User.class);
subscriber.onNext(user);
subscriber.onCompleted();
}
}
});
} }
@Controller
@RequestMapping("/UserHystrixCommandAnotation")
public class UserHystrixCommandAnotationContorller {
@Autowired
UserService userService;
//同步执行
@RequestMapping("/findAll")
@ResponseBody
public List<User> findAll(){
return userService.findAll();
} //异步
@RequestMapping("/findAllAsyn")
@ResponseBody
public List<User> findAllAsyn() throws ExecutionException, InterruptedException {
return userService.findAllAsyn().get();
} }
请求缓存
继承方式
public class UserSelectAllCommand extends HystrixCommand<List<User>> {
private RestTemplate restTemplate;
public static final HystrixCommandKey hystrixCommandKey=HystrixCommandKey.Factory.asKey("findAll");;
/**
* 设置线程组 和命令名用于仪表盘统计信息
* 设置线程组 可以使同一个组使用同一个线程池
* .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("ThreadPoolKey") 可以跟细粒度的线程池划分
* @param restTemplate
*/
public UserSelectAllCommand(RestTemplate restTemplate){
super(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("UserService"))
.andCommandKey(hystrixCommandKey)
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withExecutionTimeoutInMilliseconds(10000)//设置超时时间。我这边全局设置无效 就对应设置
));
this.restTemplate=restTemplate;
}
@Override
protected List<User> run() throws Exception {
System.out.println("执行了....");
return restTemplate.getForObject("http://PROVIDER/user/findAll",List.class);
}
/**
* 只需要重写这个方法 将开启缓存
* @return
*/
@Override
protected String getCacheKey() {
return "UserSelectAllCommand";//因为没有参数所以key是用类名
}
/**
* 清除缓存
*/
public static void clearKey(){
HystrixRequestCache.getInstance(UserSelectAllCommand.hystrixCommandKey,HystrixConcurrencyStrategyDefault.getInstance() ).clear("UserSelectAllCommand");
}
}
@Controller
@RequestMapping("/UserHystrixCommand")
public class UserHystrixCommandContorller {
@Autowired
RestTemplate restTemplate; //同步执行
@RequestMapping("/findAll")
@ResponseBody
public List<User> findAll() {
//开启缓存后 必须初始化一个context
HystrixRequestContext.initializeContext();
UserSelectAllCommand userSelectAllCommand = new UserSelectAllCommand(restTemplate);
userSelectAllCommand.execute();
userSelectAllCommand = new UserSelectAllCommand(restTemplate);
userSelectAllCommand.execute();
userSelectAllCommand = new UserSelectAllCommand(restTemplate);
//清空缓存
UserSelectAllCommand.clearKey();
return userSelectAllCommand.execute();
} }
注意每个HystrixCommand命令只能调用一次 多次调用会报错
注解方式
| @CacheResult | 标识结果被缓存 必须配合@HystrixCommand使用 可以使用cacheKeyMethod或者CacheKey设置缓存key |
cacheKeyMethod 标识获得缓存key的方法名 参数形式必须与目标方法一致 |
| @CacheRemove | 标识将清除指定key的缓存 commandKey 必须指定 用于定位到清除指定命令的缓存cacheKeyMethod 指定清除缓存key或者使用CacheKey指定 |
cacheKeyMethod 获得清除缓存key的方法名 参数形式必须与目标方法一致 commandKey 指定需要清除指定命令的缓存 |
| @Cachekey | 标识指定目标为缓存的key优先级比cacheKeyMethod低 |
指定缓存key的几种方式
@Component
public class UserService {
@Autowired
RestTemplate restTemplate; /**
* 如果没有指定cacheKey 则默认是参数
*
* @param id
* @return
*/
@CacheResult
@HystrixCommand(ignoreExceptions = BusinessException.class)
public User findUserById(Integer id) {
System.out.println("执行了。。。。");
User user = restTemplate.getForObject("http://PROVIDER/user/findById?id={id}", User.class, id);
return user;
} }
@RequestMapping("/findById")
@ResponseBody
public User findById(Integer id){
//开启缓存后 必须初始化一个context 可以在过滤器统一实现
HystrixRequestContext.initializeContext();
userService.findUserById(id);
userService.findUserById(id);
userService.findUserById(id);
return userService.findUserById(id);
}
使用cacheMethod定义缓存key
/**
* 如果没有指定cacheKey 则默认是参数
* @param id
* @return
*/
@CacheResult(cacheKeyMethod= "getFindUserByIdKey")
@HystrixCommand(ignoreExceptions = BusinessException.class)
public User findUserById(Integer id) {
System.out.println("执行了。。。。");
User user = restTemplate.getForObject("http://PROVIDER/user/findById?id={id}", User.class, id);
return user;
} /**
* 参数要与上面指定方法的一致
* @param id
* @return
*/
public String getFindUserByIdKey(Integer id){
return String.valueOf(id);
}
使用cacheKey定义缓存的key
/**
* 如果没有指定cacheKey 则默认是参数
* @param id
* @return
*/
@CacheResult
@HystrixCommand(ignoreExceptions = BusinessException.class)
public User findUserById(@CacheKey Integer id) {
System.out.println("执行了。。。。");
User user = restTemplate.getForObject("http://PROVIDER/user/findById?id={id}", User.class, id);
return user;
}
如果是对象可以使用
@CacheResult
@HystrixCommand(ignoreExceptions = BusinessException.class)
public User findUserById(@CacheKey("{属性名字}") User user) {
System.out.println("执行了。。。。");
User user = restTemplate.getForObject("http://PROVIDER/user/findById?id={id}", User.class, id);
return user;
}
清除缓存
/**
* CacheRemove.commandKey必须指定 通过他能够找到缓存的位置然后通过key删除
*
* @param user
* @return
*/
@CacheRemove(commandKey = "findUserById")
@HystrixCommand(ignoreExceptions = BusinessException.class)
public boolean saveEdit(@CacheKey("id") User user) {
return true;
}
commandKey必须指定 用于定位某个命令的key 没显式指定命令 则为方法名 几种指定的key的方式和缓存一致
请求合并
继承的方式
1.准备一个批量查询的Service
@Service
public class UserService {
@Autowired
private RestTemplate restTemplate; public List<User> findAll(List<Long> ids){
List<User> users=restTemplate.getForObject("http://PROVIDER/user?ids={1}", List.class, StringUtils.join(ids,","));
return users;
}
}
2.准备一个批处理Command
public class UserBatchCommand extends HystrixCommand<List<User>> {
UserService userService;
List<Long> ids;
public UserBatchCommand(UserService userService,List<Long> userIds){
super(Setter.withGroupKey(asKey("userServiceCommand")).andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withExecutionTimeoutInMilliseconds(10000)));//设置超时时间。我这边全局设置无效 就对应设置
this.userService=userService;
this.ids=userIds;
}
@Override
protected List<User> run() throws Exception {
return userService.findAll(ids);
}
}
3.定义请求合并器
/**
* 第一个泛型参数 为批量处理的请求的返回类型
* 第二个泛型参数 为单个请求的返回类型
* 第三个泛型参数 为参数类型
*/
public class UserCollapseCommand extends HystrixCollapser<List<User>,User ,Long> {
UserService userService;
Long userId; /**
* 用于获取请求参数
* @return
*/
@Override
public Long getRequestArgument() {
return userId;
}
public UserCollapseCommand(UserService userService,Long userId){
super(Setter.withCollapserKey(HystrixCollapserKey.Factory.asKey("userCollapsercommand"))
.andCollapserPropertiesDefaults(HystrixCollapserProperties.Setter().withTimerDelayInMilliseconds(100)));
this.userService=userService;
this.userId=userId;
} /**
* 合并请求产生批量处理的方法
* @param collection
* @return
*/
@Override
protected HystrixCommand<List<User>> createCommand(Collection<CollapsedRequest<User, Long>> collection) {
List<Long> userIds=new ArrayList<Long>(collection.size());
userIds.addAll(collection.stream().map(CollapsedRequest::getArgument).collect(Collectors.toList()));
return new UserBatchCommand(userService,userIds);
} /**
* 批量请求获得结果后 将结果拆分 返回给各个原子请求
* @param users
* @param collection
*/
@Override
protected void mapResponseToRequests(List<User> users, Collection<CollapsedRequest<User, Long>> collection) {
int count=0;
ObjectMapper objectMapper=new ObjectMapper();
for(CollapsedRequest<User,Long> collapsedRequest:collection) {
User user =objectMapper.convertValue(users.get(count++),User.class);
collapsedRequest.setResponse(user);
}
}
}
4.测试
@RunWith(SpringJUnit4ClassRunner .class)
@SpringBootTest(classes={SpringcloudConsumerApplication.class, hystrixCollapse.hystrixCollapserTest.class})
public class hystrixCollapserTest { @Autowired
UserService userService;
@Test public void simpleTest() throws ExecutionException, InterruptedException {
HystrixRequestContext context = HystrixRequestContext.initializeContext(); List<Future<User>> user=new ArrayList<Future<User>>();
for(long id=0;id<10;id++){
UserCollapseCommand userCollapseCommand=new UserCollapseCommand(userService,id);
User user1=userCollapseCommand.queue().get();
System.out.print(user1.getId());
}
Thread.sleep(4000); } }
当在一定窗口期内 的请求 会合并成一个请求 通过HystrixCollapserProperties.Setter().withTimerDelayInMilliseconds(100) 默认100毫秒
注解方式
@Service
public class UserSerivice {
@Autowired
private RestTemplate restTemplate; @HystrixCollapser(batchMethod = "findAll",collapserProperties = {@HystrixProperty(name = "timerDelayInMilliseconds",value="100")})
public User find(Long id){
return restTemplate.getForObject("http://PROVIDER/user/{1}", User.class, id);
} /**
* 直接返回list会转为linkendHashMap 所以这里手动转了一次 正式环境 都用包装类封装一次 ProcessResult7yt g
* @param ids
* @return
*/
@HystrixCommand(commandProperties={
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "10000")})
public List<User> findAll(List<Long> ids){
List<User> users=restTemplate.getForObject("http://PROVIDER/user?ids={1}", List.class, StringUtils.join(ids,","));
ObjectMapper objectMapper=new ObjectMapper();
List<User> userList=new ArrayList<User>();
for (Object obj:users
) {
userList.add(objectMapper.convertValue(obj,User.class));
}
return userList;
}
}
合并器原理图
未使用合并器

使用合并器后

请求合并器虽然能节省线程池的开销 但是因为有窗口期 如果窗口10m 一个请求耗时需要5m 也会等到窗口期过才发起请求
窗口期内有3个以上请求 才推荐使用请求合并
Spring Cloud-hystrix使用例子(七)的更多相关文章
- 第五章 服务容错保护:Spring Cloud Hystrix
在微服务架构中,我们将系统拆分为很多个服务,各个服务之间通过注册与订阅的方式相互依赖,由于各个服务都是在各自的进程中运行,就有可能由于网络原因或者服务自身的问题导致调用故障或延迟,随着服务的积压,可能 ...
- spring cloud: Hystrix(五):如禁止单个FeignClient使用hystrix
spring cloud: Hystrix(五):如禁止单个FeignClient使用hystrix 首先application.yml / applicatoin.propreties的配置项:fe ...
- Spring Cloud学习 之 Spring Cloud Hystrix(基础知识铺垫)
Spring Boot版本:2.1.4.RELEASE Spring Cloud版本:Greenwich.SR1 文章目录 前述: 快速入门: 命令模式: RxJava: 前述: 在微服务架构中, ...
- 笔记:Spring Cloud Hystrix 异常处理、缓存和请求合并
异常处理 在 HystrixCommand 实现的run方法中抛出异常,除了 HystrixBadRequestException之外,其他异常均会被Hystrix 认为命令执行失败并触发服务降级处理 ...
- 笔记:Spring Cloud Hystrix 服务容错保护
由于每个单元都在不同的进程中运行,依赖通过远程调用的方式执行,这样就有可能因为网络原因或是依赖服务自身问题出现调用故障或延迟,而这些问题会直接导致调用方的对外服务也出现延迟,若此时调用方的请求不断增加 ...
- Spring Cloud 微服务笔记(六)Spring Cloud Hystrix
Spring Cloud Hystrix Hystrix是一个延迟和容错库,旨在隔离远程系统.服务和第三方库,阻止链接故障,在复杂的分布式系统中实现恢复能力. 一.快速入门 1)依赖: <dep ...
- 试水Spring Cloud Hystrix
Spring Cloud Hystrix是一个容错库,它实现了断路器模式,使得当服务发生异常时,会自动切断连接,并将请求引导至预设的回调方法. 服务端 在Spring Tool Suite的文件菜单中 ...
- spring cloud: Hystrix(四):feign类似于hystrix的断容器功能:fallback
spring cloud: Hystrix(四):feign使用hystrix @FeignClient支持回退的概念:fallback方法,这里有点类似于:@HystrixCommand(fallb ...
- spring cloud: Hystrix(三):健康指数 health Indicator
spring cloud: Hystrix(三):健康指数 health Indicator ribbon+hystrix 当使用Hystrix时(spring-cloud-starter-hystr ...
- spring cloud: Hystrix(二):简单使用@HystrixCommand的commandProperties配置@HistrixProperty隔离策略
spring cloud: Hystrix(二):简单使用@HystrixCommand的commandProperties配置@HistrixProperty隔离策略 某电子商务网站在一个黑色星期五 ...
随机推荐
- golang LMDB入门例子——key range查询
如下,使用gomb库 package main import ( "bytes" "fmt" "io/ioutil" "os&qu ...
- P2932 [USACO09JAN]地震造成的破坏Earthquake Damage 爆搜
这题怎么这么水~~~本来以为挺难的一道题,结果随便一写就过了...本来还不知道损坏的牛棚算不算,结果不明不白就过了... 题干: 农夫John的农场遭受了一场地震.有一些牛棚遭到了损坏,但幸运地,所有 ...
- C++ 对象的赋值和复制 基本的
对象的赋值 如果对一个类定义了两个或多个对象,则这些对象之间是可以进行赋值,或者说,一个对象的值可以赋值给另一个同类的对象.这里所指的值是指对象中所有数 据的成员的值.对象之间进行赋值是“ ...
- Organize Your Train part II(hash)
http://poj.org/problem?id=3007 第一次用STL做的,TLE了,自己构造字符串哈希函数才可以.. TLE代码: #include <cstdio> #inclu ...
- Anagram Groups(字符串)
http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2316 理解错一点题意就能WA到死...题中对于 ...
- 工具分享1:文本编辑器EditPlus、汇编编译器masm、Dos盒子
工具已打包好,需要即下载 链接 https://pan.baidu.com/s/1dvMyvW 密码 mic4
- A - Fox And Snake
Problem description Fox Ciel starts to learn programming. The first task is drawing a fox! However, ...
- dom转换成jquery对象
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/stri ...
- C#:设置webBrowser框架与系统相对应的IE内核版本
通常情况下,我们直接调用C#的webBrowser控件,默认的浏览器内核是IE7. 那么如何修改控件调用的默认浏览器版本呢? /// <summary> /// 修改注册表信息来兼容当前 ...
- 【原创】.Net 微信 JS-SDK图片、语音上传接口的实现(MVC)-(一 、上传图片)
前段时间在做一个微信的项目,遇到了一个上传图片的问题,花了一下午,解决了这个问题,然后把总结出来的代码,分享了出来. 最近又有一个图片+语音的功能, 更是蛋疼, 本次采用的不是File文件上传,然后转 ...