继承方式

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使用例子(七)的更多相关文章

  1. 第五章 服务容错保护:Spring Cloud Hystrix

    在微服务架构中,我们将系统拆分为很多个服务,各个服务之间通过注册与订阅的方式相互依赖,由于各个服务都是在各自的进程中运行,就有可能由于网络原因或者服务自身的问题导致调用故障或延迟,随着服务的积压,可能 ...

  2. spring cloud: Hystrix(五):如禁止单个FeignClient使用hystrix

    spring cloud: Hystrix(五):如禁止单个FeignClient使用hystrix 首先application.yml / applicatoin.propreties的配置项:fe ...

  3. Spring Cloud学习 之 Spring Cloud Hystrix(基础知识铺垫)

    Spring Boot版本:2.1.4.RELEASE Spring Cloud版本:Greenwich.SR1 文章目录 前述: 快速入门: 命令模式: RxJava: 前述: ​ 在微服务架构中, ...

  4. 笔记:Spring Cloud Hystrix 异常处理、缓存和请求合并

    异常处理 在 HystrixCommand 实现的run方法中抛出异常,除了 HystrixBadRequestException之外,其他异常均会被Hystrix 认为命令执行失败并触发服务降级处理 ...

  5. 笔记:Spring Cloud Hystrix 服务容错保护

    由于每个单元都在不同的进程中运行,依赖通过远程调用的方式执行,这样就有可能因为网络原因或是依赖服务自身问题出现调用故障或延迟,而这些问题会直接导致调用方的对外服务也出现延迟,若此时调用方的请求不断增加 ...

  6. Spring Cloud 微服务笔记(六)Spring Cloud Hystrix

    Spring Cloud Hystrix Hystrix是一个延迟和容错库,旨在隔离远程系统.服务和第三方库,阻止链接故障,在复杂的分布式系统中实现恢复能力. 一.快速入门 1)依赖: <dep ...

  7. 试水Spring Cloud Hystrix

    Spring Cloud Hystrix是一个容错库,它实现了断路器模式,使得当服务发生异常时,会自动切断连接,并将请求引导至预设的回调方法. 服务端 在Spring Tool Suite的文件菜单中 ...

  8. spring cloud: Hystrix(四):feign类似于hystrix的断容器功能:fallback

    spring cloud: Hystrix(四):feign使用hystrix @FeignClient支持回退的概念:fallback方法,这里有点类似于:@HystrixCommand(fallb ...

  9. spring cloud: Hystrix(三):健康指数 health Indicator

    spring cloud: Hystrix(三):健康指数 health Indicator ribbon+hystrix 当使用Hystrix时(spring-cloud-starter-hystr ...

  10. spring cloud: Hystrix(二):简单使用@HystrixCommand的commandProperties配置@HistrixProperty隔离策略

    spring cloud: Hystrix(二):简单使用@HystrixCommand的commandProperties配置@HistrixProperty隔离策略 某电子商务网站在一个黑色星期五 ...

随机推荐

  1. SecureCRT——设置打印中文字符

    1. 设置方法 使用SecureCRT打印由STM32发送的中文字符提示信息,显示乱码.在网上找了一些链接,再加上自己摸索,终于出了能够让SecureCRT打印中文的方法. 设置以下几个地方即可. 1 ...

  2. System.IO.Path

    System.IO.Path 分类: C#2011-03-23 10:54 1073人阅读 评论(0) 收藏 举报 扩展磁盘string2010c System.IO.Path提供了一些处理文件名和路 ...

  3. hihocoder 1676 树上等差数列 黑科技树形dp

    #1676 : 树上的等差数列 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一棵包含N个节点的无根树,节点编号1~N.其中每个节点都具有一个权值,第i个节点的权值 ...

  4. class--类①

    原来看其他人的代码,发现有好多class之类的语句,当时没太注意.可后来,我觉得应该有学习新知识的必要了. 类定义是以关键字 class 开头,后跟类的名称.类的主体是包含在一对花括号中.类定义后必须 ...

  5. 687C

    dp 以前做过 忘了. 想破脑袋不知道怎么设状态 dp[i][j][k]表示选到第i个硬币,当前和为j,能否弄出k dp[i][j][k]|=dp[i-1][j][k]|dp[i-1][j][k-c[ ...

  6. 原生JS---7

    原生js学习笔记7——本地存储之cookie操作 什么是cookie • 用来保存页面信息的,如用户名.密码 • cookie的特性:同一个网站中所有的页面共享一套cookie:数量.大小限制:过期时 ...

  7. qW3xT.2挖矿病毒 解决过程及坑

    周一早上老大让我把项目更新一下,然后配置一下elasticsearch,我登上服务器之后部署的时候没有什么感觉,但是在配置elasticsearch的过程中感觉服务器哪个地方有点不对,下意识的top了 ...

  8. ubuntu Ngin Install

    安装gcc g++的依赖库 #apt-get install build-essential #apt-get install libtool 安装 pcre依赖库 #sudo apt-get upd ...

  9. itext 生成doc文档 小结(自己备忘)

    1.引入maven <dependency> <groupId>com.lowagie</groupId> <artifactId>itext</ ...

  10. nodejs 中使用 mysql 实现 crud

    首先要使用 mysql 就必须要安装 npm install mysql 然后封装 sql 函数 const mySql = require('mysql'); let connection ; le ...