在过去的几天里,我一直在探索Netflix Hystrix库,并欣赏了这个出色的库所提供的功能。
引用Hystrix网站上的内容:
Hystrix是一个延迟和容错库,旨在隔离对远程系统,服务和第三方库的访问点,停止级联故障,并在不可避免发生故障的复杂分布式系统中实现弹性。
这里有很多关键字可以解析,但是在我看来,体验Hystrix的最佳方法是尝试一个示例用例。
不可预测的服务
考虑一种服务,一个奇怪的服务,它采用以下结构的json消息并返回确认:
{"id":"1","payload": "Sample Payload","throw_exception":false,"delay_by": 0
}
该服务接收有效负载,但还接收两个字段:delay_by使服务在延迟几毫秒后确认响应,而“ throw_exceptions”字段将在指定的延迟后导致异常!
这是一个示例响应:
{"id":"1","received":"Sample Payload","payload":"Reply Message"
}
如果您一直遵循,这里是我与该示例的 github回购,我已经为该示例使用了Netflix Karyon 2 ,并且可以通过以下方式非常简洁地表达处理请求的代码–看看rx-java库是如何放置的在这里很好地使用:
import com.netflix.governator.annotations.Configuration;
import rx.Observable;
import service1.domain.Message;
import service1.domain.MessageAcknowledgement;import java.util.concurrent.TimeUnit;public class MessageHandlerServiceImpl implements MessageHandlerService {@Configuration("reply.message")private String replyMessage;public Observable<MessageAcknowledgement> handleMessage(Message message) {logger.info("About to Acknowledge");return Observable.timer(message.getDelayBy(), TimeUnit.MILLISECONDS).map(l -> message.isThrowException()).map(throwException -> {if (throwException) {throw new RuntimeException("Throwing an exception!");}return new MessageAcknowledgement(message.getId(), message.getPayload(), replyMessage);});}}
在这一点上,我们有一个很好的候选服务,可以做出任意延迟和失败的响应。
服务的客户
现在转到此服务的客户端。 我正在使用Netflix Feign进行此调用,这是另一个很棒的库,它所需要的只是用以下方式注释的Java接口:
package aggregate.service;import aggregate.domain.Message;
import aggregate.domain.MessageAcknowledgement;
import feign.RequestLine;public interface RemoteCallService {@RequestLine("POST /message")MessageAcknowledgement handleMessage(Message message);
}
它使用以下几行的配置来创建实现该接口所需的代理:
RemoteCallService remoteCallService = Feign.builder().encoder(new JacksonEncoder()).decoder(new JacksonDecoder()).target(RemoteCallService.class, "http://127.0.0.1:8889");
我有多个终结点,这些终结点将调用委派给该远程客户端,所有这些终结点都沿这些方向显示url模式– http:// localhost:8888 / noHystrix?message = Hello&delay_by = 0&throw_exception = false ,第一个是终结点的示例不使用Hystrix。
没有Hystrix案例
作为第一个示例,如果我尝试调用http:// localhost:8888 / noHystrix?message = Hello&delay_by = 5000&throw_exception = false或说http:// localhost:8888 / ,请考虑在没有Hystrix的情况下调用Remote服务。 noHystrix?message = Hello&delay_by = 5000&throw_exception = true ,在这两种情况下,用户对端点的请求只会在响应之前暂停 5秒钟。
这里应该立即显示一些事情:
- 如果服务响应缓慢,则客户端对服务的请求将被迫等待响应返回。
- 在高负载下,处理用户流量的所有线程很可能会用尽,从而使进一步的用户请求失败。
- 如果该服务引发异常,则客户端将无法正常处理该异常。
显然,需要像Hystrix这样的东西来处理所有这些问题。
Hystrix命令包装远程调用
我在前一个案例中使用了50个用户负载进行了小负载测试,结果如下:
================================================================================
---- Global Information --------------------------------------------------------
> request count 50 (OK=50 KO=0 )
> min response time 5007 (OK=5007 KO=- )
> max response time 34088 (OK=34088 KO=- )
> mean response time 17797 (OK=17797 KO=- )
> std deviation 8760 (OK=8760 KO=- )
> response time 50th percentile 19532 (OK=19532 KO=- )
> response time 75th percentile 24386 (OK=24386 KO=- )
> mean requests/sec 1.425 (OK=1.425 KO=- )
本质上,从服务延迟5秒会导致25秒的第75个百分位时间!现在考虑使用Hystrix命令包装服务调用进行相同的测试:
================================================================================
---- Global Information --------------------------------------------------------
> request count 50 (OK=50 KO=0 )
> min response time 1 (OK=1 KO=- )
> max response time 1014 (OK=1014 KO=- )
> mean response time 22 (OK=22 KO=- )
> std deviation 141 (OK=141 KO=- )
> response time 50th percentile 2 (OK=2 KO=- )
> response time 75th percentile 2 (OK=2 KO=- )
> mean requests/sec 48.123 (OK=48.123 KO=- )
奇怪的是,现在的第75个百分位时间是2毫秒!这怎么可能,使用Hystrix提供的出色工具,答案就变得显而易见,这里是此测试的Hystrix仪表板视图:
此处发生的情况是前10个请求超时,默认情况下使用Hystrix命令超时超过一秒,一旦前十个事务失败,Hystrix会将命令短路,从而阻止对远程服务的任何请求,因此低响应时间。 关于为什么这些事务未显示为失败的原因,是因为此处存在一个后备,当失败时,该后备会优雅地响应用户请求。
结论
这样做的目的是为了阐明为什么需要使用像Hystrix这样的库的动机,在此之后,我将详细介绍将Hystrix集成到应用程序中所需的内容以及该出色库提供的功能的广度。
翻译自: https://www.javacodegeeks.com/2015/10/gentle-introduction-to-hystrix.html