feat(master):Hystrix1

后备1 + 合并
master
土豆兄弟 2 weeks ago
parent a29e4e7b11
commit d4ad93508b

@ -33,10 +33,10 @@
### 编程方式应用 Hystrix 请求合并 ### 编程方式应用 Hystrix 请求合并
-
### 注解方式应用 Hystrix 请求合并 ### 注解方式应用 Hystrix 请求合并
- 使用注解的方式比较多
### OpenFeign 集成 Hystrix 开启后备模式 ### OpenFeign 集成 Hystrix 开启后备模式

@ -49,6 +49,27 @@
<artifactId>fastjson</artifactId> <artifactId>fastjson</artifactId>
<version>1.2.51</version> <version>1.2.51</version>
</dependency> </dependency>
<!-- openfeign -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-micrometer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- feign 替换 JDK 默认的 URLConnection 为 okhttp -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
<!-- 使用原生的 Feign Api 做的自定义配置, encoder 和 decoder -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-gson</artifactId>
<version>12.1</version>
</dependency>
</dependencies> </dependencies>
<!-- <!--

@ -5,6 +5,7 @@ import lombok.extern.slf4j.Slf4j;
import org.example.hystrix.NacosClientHystrixCommand; import org.example.hystrix.NacosClientHystrixCommand;
import org.example.hystrix.NacosClientHystrixObservableCommand; import org.example.hystrix.NacosClientHystrixObservableCommand;
import org.example.hystrix.UseHystrixCommandAnnotation; import org.example.hystrix.UseHystrixCommandAnnotation;
import org.example.hystrix.request_merge.NacosClientCollapseCommand;
import org.example.service.NacosClientService4HystrixDemo; import org.example.service.NacosClientService4HystrixDemo;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.ServiceInstance;
@ -129,4 +130,156 @@ public class HystrixController {
JSON.toJSONString(result), Thread.currentThread().getName()); JSON.toJSONString(result), Thread.currentThread().getName());
return result.get(0); // 取一个返回 return result.get(0); // 取一个返回
} }
/*@GetMapping("/cache-hystrix-command")
public void cacheHystrixCommand(@RequestParam String serviceId) {
// 使用缓存 Command, 发起两次请求
CacheHystrixCommand command1 = new CacheHystrixCommand(
nacosClientService, serviceId
);
CacheHystrixCommand command2 = new CacheHystrixCommand(
nacosClientService, serviceId
);
List<ServiceInstance> result01 = command1.execute();
List<ServiceInstance> result02 = command2.execute();
log.info("result01, result02: [{}], [{}]",
JSON.toJSONString(result01), JSON.toJSONString(result02));
// 清除缓存
CacheHystrixCommand.flushRequestCache(serviceId);
// 使用缓存 Command, 发起两次请求
CacheHystrixCommand command3 = new CacheHystrixCommand(
nacosClientService, serviceId
);
CacheHystrixCommand command4 = new CacheHystrixCommand(
nacosClientService, serviceId
);
List<ServiceInstance> result03 = command3.execute();
List<ServiceInstance> result04 = command4.execute();
log.info("result03, result04: [{}], [{}]",
JSON.toJSONString(result03), JSON.toJSONString(result04));
}
@GetMapping("/cache-annotation-01")
public List<ServiceInstance> useCacheByAnnotation01(@RequestParam String serviceId) {
log.info("use cache by annotation01(controller) to get nacos client info: [{}]",
serviceId);
List<ServiceInstance> result01 =
cacheHystrixCommandAnnotation.useCacheByAnnotation01(serviceId);
List<ServiceInstance> result02 =
cacheHystrixCommandAnnotation.useCacheByAnnotation01(serviceId);
// 清除掉缓存
cacheHystrixCommandAnnotation.flushCacheByAnnotation01(serviceId);
List<ServiceInstance> result03 =
cacheHystrixCommandAnnotation.useCacheByAnnotation01(serviceId);
// 这里有第四次调用
return cacheHystrixCommandAnnotation.useCacheByAnnotation01(serviceId);
}
@GetMapping("/cache-annotation-02")
public List<ServiceInstance> useCacheByAnnotation02(@RequestParam String serviceId) {
log.info("use cache by annotation02(controller) to get nacos client info: [{}]",
serviceId);
List<ServiceInstance> result01 =
cacheHystrixCommandAnnotation.useCacheByAnnotation02(serviceId);
List<ServiceInstance> result02 =
cacheHystrixCommandAnnotation.useCacheByAnnotation02(serviceId);
// 清除掉缓存
cacheHystrixCommandAnnotation.flushCacheByAnnotation02(serviceId);
List<ServiceInstance> result03 =
cacheHystrixCommandAnnotation.useCacheByAnnotation02(serviceId);
// 这里有第四次调用
return cacheHystrixCommandAnnotation.useCacheByAnnotation02(serviceId);
}
@GetMapping("/cache-annotation-03")
public List<ServiceInstance> useCacheByAnnotation03(@RequestParam String serviceId) {
log.info("use cache by annotation03(controller) to get nacos client info: [{}]",
serviceId);
List<ServiceInstance> result01 =
cacheHystrixCommandAnnotation.useCacheByAnnotation03(serviceId);
List<ServiceInstance> result02 =
cacheHystrixCommandAnnotation.useCacheByAnnotation03(serviceId);
// 清除掉缓存
cacheHystrixCommandAnnotation.flushCacheByAnnotation03(serviceId);
List<ServiceInstance> result03 =
cacheHystrixCommandAnnotation.useCacheByAnnotation03(serviceId);
// 这里有第四次调用
return cacheHystrixCommandAnnotation.useCacheByAnnotation03(serviceId);
}*/
/**
* <h2></h2>
* */
@GetMapping("/request-merge")
public void requestMerge() throws Exception {
// 前三个请求会被合并
NacosClientCollapseCommand collapseCommand01 = new NacosClientCollapseCommand(
nacosClientService4HystrixDemo, "dev-protocol-springcloud-hystrix1");
NacosClientCollapseCommand collapseCommand02 = new NacosClientCollapseCommand(
nacosClientService4HystrixDemo, "dev-protocol-springcloud-hystrix2");
NacosClientCollapseCommand collapseCommand03 = new NacosClientCollapseCommand(
nacosClientService4HystrixDemo, "dev-protocol-springcloud-hystrix3");
Future<List<ServiceInstance>> future01 = collapseCommand01.queue();
Future<List<ServiceInstance>> future02 = collapseCommand02.queue();
Future<List<ServiceInstance>> future03 = collapseCommand03.queue();
future01.get();
future02.get();
future03.get();
Thread.sleep(2000);
// 过了合并的时间窗口, 第四个请求单独发起
NacosClientCollapseCommand collapseCommand04 = new NacosClientCollapseCommand(
nacosClientService4HystrixDemo, "dev-protocol-springcloud-hystrix4");
Future<List<ServiceInstance>> future04 = collapseCommand04.queue();
future04.get();
}
/**
* <h2></h2>
* */
@GetMapping("/request-merge-annotation")
public void requestMergeAnnotation() throws Exception {
Future<List<ServiceInstance>> future01 = nacosClientService4HystrixDemo.findNacosClientInfo(
"dev-protocol-springcloud-hystrix1"
);
Future<List<ServiceInstance>> future02 = nacosClientService4HystrixDemo.findNacosClientInfo(
"dev-protocol-springcloud-hystrix2"
);
Future<List<ServiceInstance>> future03 = nacosClientService4HystrixDemo.findNacosClientInfo(
"dev-protocol-springcloud-hystrix3"
);
future01.get();
future02.get();
future03.get();
Thread.sleep(2000);
Future<List<ServiceInstance>> future04 = nacosClientService4HystrixDemo.findNacosClientInfo(
"dev-protocol-springcloud-hystrix4"
);
future04.get();
}
} }

@ -0,0 +1,50 @@
package org.example.hystrix.request_merge;
import com.alibaba.fastjson.JSON;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import lombok.extern.slf4j.Slf4j;
import org.example.service.NacosClientService4HystrixDemo;
import org.springframework.cloud.client.ServiceInstance;
import java.util.Collections;
import java.util.List;
/**
* <h1> Hystrix Command</h1>
* */
@Slf4j
public class NacosClientBatchCommand extends HystrixCommand<List<List<ServiceInstance>>> {
private final NacosClientService4HystrixDemo nacosClientService;
private final List<String> serviceIds;
protected NacosClientBatchCommand(
NacosClientService4HystrixDemo nacosClientService, List<String> serviceIds
) {
super(
HystrixCommand.Setter.withGroupKey(
HystrixCommandGroupKey.Factory.asKey("NacosClientBatchCommand")
)
);
this.nacosClientService = nacosClientService;
this.serviceIds = serviceIds;
}
@Override
protected List<List<ServiceInstance>> run() throws Exception {
log.info("use nacos client batch command to get result: [{}]",
JSON.toJSONString(serviceIds));
return nacosClientService.getNacosClientInfos(serviceIds);
}
@Override
protected List<List<ServiceInstance>> getFallback() {
log.warn("nacos client batch command failure, use fallback");
return Collections.emptyList();
}
}

@ -0,0 +1,85 @@
package org.example.hystrix.request_merge;
import com.netflix.hystrix.HystrixCollapser;
import com.netflix.hystrix.HystrixCollapserKey;
import com.netflix.hystrix.HystrixCollapserProperties;
import com.netflix.hystrix.HystrixCommand;
import lombok.extern.slf4j.Slf4j;
import org.example.service.NacosClientService4HystrixDemo;
import org.springframework.cloud.client.ServiceInstance;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
/**
* <h1></h1>
* */
@Slf4j
public class NacosClientCollapseCommand
extends HystrixCollapser<List<List<ServiceInstance>>, List<ServiceInstance>, String> {
// 批量返回类型, 单个请求对象的返回类型, 请求参数的类型
private final NacosClientService4HystrixDemo nacosClientService;
private final String serviceId;
public NacosClientCollapseCommand(NacosClientService4HystrixDemo nacosClientService, String serviceId) {
super(
HystrixCollapser.Setter.withCollapserKey(
HystrixCollapserKey.Factory.asKey("NacosClientCollapseCommand")
).andCollapserPropertiesDefaults(
HystrixCollapserProperties.Setter().withTimerDelayInMilliseconds(300) // 等待 300ms 合并请求
)
);
this.nacosClientService = nacosClientService;
this.serviceId = serviceId;
}
/**
* <h2></h2>
* */
@Override
public String getRequestArgument() {
return this.serviceId;
}
/**
* <h2> Hystrix Command</h2>
* */
@Override
protected HystrixCommand<List<List<ServiceInstance>>> createCommand(
Collection<CollapsedRequest<List<ServiceInstance>, String>> collapsedRequests) {
List<String> serviceIds = new ArrayList<>(collapsedRequests.size()); // 合并请求的大小就是参数们的大小
serviceIds.addAll(
collapsedRequests.stream()
.map(CollapsedRequest::getArgument) // 获取每个请求的参数
.collect(Collectors.toList())
);
return new NacosClientBatchCommand(nacosClientService, serviceIds);
}
/**
* <h2></h2>
* */
@Override
protected void mapResponseToRequests(List<List<ServiceInstance>> batchResponse,
Collection<CollapsedRequest<List<ServiceInstance>,
String>> collapsedRequests) {
int count = 0;
for (CollapsedRequest<List<ServiceInstance>, String> collapsedRequest : collapsedRequests) {
// 从批量响应集合中按顺序取出结果
List<ServiceInstance> instances = batchResponse.get(count++);
// 将结果返回原 Response 中
collapsedRequest.setResponse(instances);
}
}
}

@ -0,0 +1,30 @@
package org.example.service;
import org.example.service.hystrix.bak.AuthorityFeignClientFallback;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* <h1> Authority Feign Client </h1>
* */
@FeignClient(
// contextId 是对 FeignClient 的声明, 每一个进行的通信都要进行定义, value 表示需要进行通信的服务id是什么
contextId = "AuthorityFeignClient", value = "e-commerce-authority-center",
fallback = AuthorityFeignClientFallback.class
// fallbackFactory = AuthorityFeignClientFallbackFactory.class
)
public interface AuthorityFeignClientHystrixDemo {
/**
* <h2> OpenFeign 访 Authority Token</h2>
*
* value , ip + port
* consumes, produces: , , 使 Api ,
* */
@RequestMapping(value = "/ecommerce-authority-center/authority/token",
method = RequestMethod.POST,
consumes = "application/json", produces = "application/json")
String getTokenByFeign(@RequestBody String usernameAndPassword);
}

@ -1,11 +1,17 @@
package org.example.service; package org.example.service;
import com.alibaba.fastjson.JSON;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.Future;
@Slf4j @Slf4j
@Service @Service
@ -35,4 +41,45 @@ public class NacosClientService4HystrixDemo {
log.info("request nacos client to get service instance info: [{}]", serviceId); log.info("request nacos client to get service instance info: [{}]", serviceId);
return discoveryClient.getInstances(serviceId); return discoveryClient.getInstances(serviceId);
} }
/**
* <h2> Hystrix </h2>
* */
public List<List<ServiceInstance>> getNacosClientInfos(List<String> serviceIds) {
log.info("request nacos client to get service instance infos: [{}]",
JSON.toJSONString(serviceIds));
List<List<ServiceInstance>> result = new ArrayList<>(serviceIds.size());
serviceIds.forEach(s -> result.add(discoveryClient.getInstances(s)));
return result;
}
/**
* <h2>使 Hystrix </h2>
*/
@HystrixCollapser(
batchMethod = "findNacosClientInfos",
scope = com.netflix.hystrix.HystrixCollapser.Scope.GLOBAL,
collapserProperties = {
// 时间窗口的填充
@HystrixProperty(name = "timerDelayInMilliseconds", value = "300")
}
)
public Future<List<ServiceInstance>> findNacosClientInfo(String serviceId) {
// 系统运行正常, 不会走这个方法
throw new RuntimeException("This method body should not be executed!");
}
/**
*
*/
@HystrixCommand // 使用默认的 GroupKey CommandKey
public List<List<ServiceInstance>> findNacosClientInfos(List<String> serviceIds) {
log.info("coming in find nacos client infos: [{}]", JSON.toJSONString(serviceIds));
return getNacosClientInfos(serviceIds);
}
} }

@ -0,0 +1,21 @@
package org.example.service.hystrix.bak;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.example.service.AuthorityFeignClientHystrixDemo;
import org.springframework.stereotype.Component;
/**
* <h1>AuthorityFeignClient fallback</h1>
* */
@Slf4j
@Component
public class AuthorityFeignClientFallback implements AuthorityFeignClientHystrixDemo {
@Override
public String getTokenByFeign(String usernameAndPassword) {
log.info("authority feign client get token by feign request error " +
"(Hystrix Fallback): [{}]", JSON.toJSONString(usernameAndPassword));
return "qqqqq";
}
}

@ -0,0 +1,27 @@
package org.example.service.hystrix.bak;
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;
import org.example.service.AuthorityFeignClientHystrixDemo;
import org.springframework.stereotype.Component;
/**
* <h1>OpenFeign Hystrix </h1>
* */
@Slf4j
@Component
public class AuthorityFeignClientFallbackFactory implements FallbackFactory<AuthorityFeignClientHystrixDemo> {
@Override
public AuthorityFeignClientHystrixDemo create(Throwable throwable) {
log.warn("authority feign client get token by feign request error " +
"(Hystrix FallbackFactory): [{}]", throwable.getMessage(), throwable);
return new AuthorityFeignClientHystrixDemo() {
@Override
public String getTokenByFeign(String usernameAndPassword) {
return "q-factory";
}
};
}
}
Loading…
Cancel
Save