最近几天我直在探索Netflix Hystrix library,领会到了这个优秀类库提供的特性。
引用Hystrix网站的原话:
Hystrix is a latency and fault tolerance library designed to isolate points of access to remote systems,
services and 3rd party libraries, stop cascading failure and enable resilience in complex distributed systems where
failure is inevitable.
Hystrix通过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力,阻止故障的连锁反应
,并允许你快速失败并迅速恢复。
这里有很多要分析的关键词,然而体验Hystrix的最佳方式就是亲手做一个例子来试试。
一个不可预测的服务考虑一个服务,一个携带json结构信息并且返回一个确认的奇怪服务。
{ "id":"1", "payload": "Sample Payload", "throw_exception":false, "delay_by": 0 }
这个服务有一个payload属性,但是额外多带了两个属性。
delay_by 在延迟到达指定的毫秒数后返回一个确认响应。
throw_exceptions 在指定的延迟后导致异常
下面是响应例子:
{ "id":"1", "received":"Sample Payload", "payload":"Reply Message" }
这里是我的 github地址 ,可以下载示例代码。在这个例子中我用到了 Netflix Karyon2 ,示例代码处理请求的部分非常简洁。来看看
这个类库用在这是多好用吧:
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 来进行调用,这是另一个很棒的类库,需通过注解方式来使用:
package aggregate.service; import aggregate.domain.Message; import aggregate.domain.MessageAcknowledgement; import feign.RequestLine; public interface RemoteCallService { @RequestLine("POST /message") MessageAcknowledgement handleMessage(Message message); }
在这几行中,它创建了一个代理,其实现了使用配置的接口。
RmoteCallService 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的例子在第一个例子中,考虑不用Hystrix来调用这个远程服务,如果我尝试以以下方式调用
http://localhost:8888/noHystrix?message=Hello&delay_by=5000&throw_exception=false或
http://localhost:8888/noHystrix?message=Hello&delay_by=5000&throw_exception=true,
在这两种实例中用户对服务的请求都会在等待5秒后才会收到响应。
有些事情在这里就立即很明显了:
1.如果服务响应缓慢,那么客户对服务的请求就会被强制等待到服务返回。
2.在高负载下,很有可能所有处理用户请求的线程资源被耗竭,而不能响应用户的进一步请求。
3.如果服务抛出异常,客户端不能很好的处理。
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秒延迟,在到了75%的时候,延迟竟然达到了25秒。现在来看一下用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默认时间1秒的,一但前10个交易失败后,命令就会堵塞其他客户对远程服务的请求。
,因此会有较低的响应时间。为什么这些交易没有显示失败呢,这是因为这里会有一个反馈,优雅的告诉用户请求失败了。
作者:supercrsky 发表于2015/10/13 16:10:46 原文链接
阅读:6 评论:0 查看评论