hystrix熔断 简介
这是其他两篇文章的后续文章– 动机 ,说明为什么在分布式系统中需要类似Hystrix的内容以及Hystrix的基本介绍 。
这将是我的Hystrix旅程的总结,其中包含各种属性的详细信息,这些属性可以进行调整以更改Hystrix的行为,并涉及一些高级概念
调整Hystrix行为
Hystrix的配置在此Wiki中进行了解释,简要介绍了两个主要的组来控制Hystrix的属性,
- 命令属性
- ThreadPool属性
属性遵循Wiki中说明的优先顺序,这里我将重点介绍通过属性文件指定的属性。
对于示例命令,定义了以下方式:
public class HelloWorldCommand extends HystrixCommand<String> {
private static final Logger logger = LoggerFactory.getLogger(HelloWorldCommand.class);
private final String name;
public HelloWorldCommand(String name) {
super(HystrixCommandGroupKey.Factory.asKey("default"));
this.name = name;
}
@Override
protected String run() throws Exception {
logger.info("HelloWorld Command Invoked");
return "Hello " + name;
}
}
可以调整的第一个行为是在线程池中执行命令还是与调用方(SEMAPHORE策略类型)执行线程相同。 如果执行在线程池中,则可以设置请求超时。
hystrix.command.HelloWorldCommand.execution.isolation.strategy=THREAD
hystrix.command.HelloWorldCommand.execution.isolation.thread.timeoutInMilliseconds=1000
第二种行为是断路器,它根据在滚动时间窗内收集的信息进行工作,这种方式进行配置,例如持续10秒:
hystrix.command.HelloWorldCommand.metrics.rollingStats.timeInMilliseconds=10000
在此窗口中,如果某个百分比的故障(例如50%)发生在请求阈值(例如10秒内发生20个故障),则电路断开,其配置如下所示:
hystrix.command.HelloWorldCommand.circuitBreaker.requestVolumeThreshold=20
hystrix.command.HelloWorldCommand.circuitBreaker.errorThresholdPercentage=50
电路断开后,它将保持这种状态并保持以下设置的时间,在这种情况下为5秒:
hystrix.command.HelloWorldCommand.circuitBreaker.sleepWindowInMilliseconds=5000
线程池设置是使用指定的组密钥控制的,在本示例中称为默认组密钥。 不过,也可以将特定的“ Threadpool Key”指定为构造函数的一部分。
hystrix.threadpool.default.coreSize=10
hystrix.threadpool.default.queueSizeRejectionThreshold=5
在这里,可以并行运行10个命令,而其他5个则保留在队列中,超过该队列将拒绝请求。
要求折叠
Tomaz Nurkiewicz在他的博客网站NoBlogDefFound中做了出色的解释Request Collapsing的工作 。 我的示例有些简化,请考虑以下情况,其中有很多请求要检索给定id的Person,方法如下:
public class PersonService {
public Person findPerson(Integer id) {
return new Person(id, "name : " + id);
}
public List<Person> findPeople(List<Integer> ids) {
return ids
.stream()
.map(i -> new Person(i, "name : " + i))
.collect(Collectors.toList());
}
}
该服务以固定的响应进行响应,但假定该调用是对远程数据存储的。 还可以看到,该服务实现了一个批处理方法,以在给定ID列表的情况下检索人员列表。
请求折叠是一项功能,它将一段时间内发生的多个用户请求批量处理为一个这样的远程呼叫,然后将响应散发回用户。
可以通过以下方式定义采用一组id并获得人员响应的hystrix命令:
public class PersonRequestCommand extends HystrixCommand<List<Person>>{
private final List<Integer> ids;
private final PersonService personService = new PersonService();
private static final Logger logger = LoggerFactory.getLogger(PersonRequestCommand.class);
public PersonRequestCommand(List<Integer> ids) {
super(HystrixCommandGroupKey.Factory.asKey("default"));
this.ids = ids;
}
@Override
protected List<Person> run() throws Exception {
logger.info("Retrieving details for : " + this.ids);
return personService.findPeople(this.ids);
}
}
到目前为止,这很简单,复杂的逻辑现在在RequestCollapser中,如下所示:
package aggregate.commands.collapsed;
import com.netflix.hystrix.HystrixCollapser;
import com.netflix.hystrix.HystrixCollapserKey;
import com.netflix.hystrix.HystrixCollapserProperties;
import com.netflix.hystrix.HystrixCommand;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
public class PersonRequestCollapser extends HystrixCollapser<List<Person>, Person, Integer> {
private final Integer id;
public PersonRequestCollapser(Integer id) {
super(Setter.
withCollapserKey(HystrixCollapserKey.Factory.asKey("personRequestCollapser"))
.andCollapserPropertiesDefaults(HystrixCollapserProperties.Setter().withTimerDelayInMilliseconds(2000)));
this.id = id;
}
@Override
public Integer getRequestArgument() {
return this.id;
}
@Override
protected HystrixCommand<List<Person>> createCommand(Collection<CollapsedRequest<Person, Integer>> collapsedRequests) {
List<Integer> ids = collapsedRequests.stream().map(cr -> cr.getArgument()).collect(Collectors.toList());
return new PersonRequestCommand(ids);
}
@Override
protected void mapResponseToRequests(List<Person> batchResponse, Collection<CollapsedRequest<Person, Integer>> collapsedRequests) {
Map<Integer, Person> personMap = batchResponse.stream().collect(Collectors.toMap(Person::getId, Function.identity()));
for (CollapsedRequest<Person, Integer> cr: collapsedRequests) {
cr.setResponse(personMap.get(cr.getArgument()));
}
}
}
这里发生了一些事情,首先,参数化类型签名中的类型指示响应的类型(List <Person>),调用者期望的响应类型(Person)和请求的请求类型(请求的ID)。人)。 然后有两种方法,一种是创建批处理命令,第二种是将响应映射回原始请求。
现在,从用户的角度来看,这没有多大变化,就好像对单个命令一样进行调用,并且Request Collapsing处理批处理,分派和映射回响应。 这是示例测试的样子:
@Test
public void testCollapse() throws Exception {
HystrixRequestContext requestContext = HystrixRequestContext.initializeContext();
logger.info("About to execute Collapsed command");
List<Observable<Person>> result = new ArrayList<>();
CountDownLatch cl = new CountDownLatch(1);
for (int i = 1; i <= 100; i++) {
result.add(new PersonRequestCollapser(i).observe());
}
Observable.merge(result).subscribe(p -> logger.info(p.toString())
, t -> logger.error(t.getMessage(), t)
, () -> cl.countDown());
cl.await();
logger.info("Completed executing Collapsed Command");
requestContext.shutdown();
}
结论
Hystrix的功能远远不止我在此介绍的内容。 它确实是一个很棒的库,对于创建弹性系统至关重要。我已经开始欣赏设计这个出色的库所花费的大量思考过程。
翻译自: https://www.javacodegeeks.com/2015/11/gentle-introduction-to-hystrix-wrapup.html
hystrix熔断 简介