(图片来源:https://github.com/Netflix/Hystrix/wiki)
然而任何一个服务的可用性都不是 100% 的,网络亦是脆弱的。当我依赖的某个服务不可用的时候,我自身是否会被拖死?当网络不稳定的时候,我自身是否会被拖死?这些在单机环境下不太需要考虑的问 题,在分布式环境下就不得不考虑了。假设我有5个依赖的服务,他们的可用性都是99.95%,即一年不可用时间约为4个多小时,那么是否意味着我的可用性 最多就是 99.95% 的5次方,99.75%(近乎一天),再加上网络不稳定因素、依赖服务可能更多,可用性会更低。考虑到所依赖的服务必定会在某些时间不可用,考虑到网络必 定会不稳定,我们应该怎么设计自身服务?即,怎么为出错设计?
Michael T. Nygard 在在精彩的《Release It!》一书中总结了很多提高系统可用性的模式,其中非常重要的两条是:
- 使用超时
- 使用断路器
第一条,通过网络调用外部依赖服务的时候,都必须应该设置超时。在健康的情况下,一般局域往的一次远程调用在几十毫秒内就返回了,但是当网络拥堵的 时候,或者所依赖服务不可用的时候,这个时间可能是好多秒,或者压根就僵死了。通常情况下,一次远程调用对应了一个线程或者进程,如果响应太慢,或者僵死 了,那一个进程/线程,就被拖死,短时间内得不到释放,而进程/线程都对应了系统资源,这就等于说我自身服务资源会被耗尽,导致自身服务不可用。假设我的 服务依赖于很多服务,其中一个非核心的依赖如果不可用,而且没有超时机制,那么这个非核心依赖就能拖死我的服务,尽管理论上即使没有它我在大部分情况还能 健康运转的。
断路器其实我们大家都不陌生(你会换保险丝么?),如果你家没有断路器,当电流过载,或者短路的时候,电路不断开,电线就会升温,造成火灾,烧掉房子。有了断路器之后,电流过载的时候,保险丝就会首先烧掉,断开电路,不至于引起更大的灾难(只不过这个时候你得换保险丝)。
当我们的服务访问某项依赖有大量超时的时候,再让新的请求去访问已经没有太大意义,那只会无谓的消耗现有资源。即使你已经设置超时1秒了,那明知依 赖不可用的情况下再让更多的请求,比如100个,去访问这个依赖,也会导致100个线程1秒的资源浪费。这个时候,断路器就能帮助我们避免这种资源浪费, 在自身服务和依赖之间放一个断路器,实时统计访问的状态,当访问超时或者失败达到某个阈值的时候(如50%请求超时,或者连续20次请失败),就打开断路 器,那么后续的请求就直接返回失败,不至于浪费资源。断路器再根据一个时间间隔(如5分钟)尝试关闭断路器(或者更换保险丝),看依赖是否恢复服务了。
超时机制和断路器能够很好的保护我们的服务,不受依赖服务不可用的影响太大,具体可以参看文章《 使用熔断器设计模式保护软件》。然而具体实现这两个模式还是有一定的复杂度的,所幸 Netflix 开源的 Hystrix框架 帮我们大大简化了超时机制和断路器的实现,Hystrix:供分布式系统使用,提供延迟和容错功能,隔离远程系统、访问和第三方程序库的访问点,防止级联失败,保证复杂的分布系统在面临不可避免的失败时,仍能有其弹性。在Codeplex上有一个.NET的移植版本https://hystrixnet.codeplex.com/ 。
使用Hystrix,需要通过Command封装对远程依赖的调用:
public class GetCurrentTimeCommand : HystrixCommand<long>
{
private static long currentTimeCache;
public GetCurrentTimeCommand()
: base(HystrixCommandSetter.WithGroupKey("TimeGroup")
.AndCommandKey("GetCurrentTime")
.AndCommandPropertiesDefaults(new HystrixCommandPropertiesSetter().WithExecutionIsolationThreadTimeout(TimeSpan.FromSeconds(1.0)).WithExecutionIsolationThreadInterruptOnTimeout(true)))
{
}
protected override long Run()
{
using (WebClient wc = new WebClient())
{
string content = wc.DownloadString("http://tycho.usno.navy.mil/cgi-bin/time.pl");
XDocument document = XDocument.Parse(content);
currentTimeCache = long.Parse(document.Element("usno").Element("t").Value);
return currentTimeCache;
}
}
protected override long GetFallback()
{
return currentTimeCache;
}
}
然后在需要的时候调用这个Command:
GetCurrentTimeCommand command = new GetCurrentTimeCommand();
long currentTime = command.Execute();
上述是同步调用,当然如果业务逻辑允许且更追求性能,或许可以选择异步调用:
该例中,不论 WebClient. DownloadString () 自身有没有超时机制(可能你会发现很多远程调用接口自身并没有给你提供超时机制),用 HystrixCommand 封装过后,超时是强制的,默认超时时间是1秒,当然你可以根据需要自己在构造函数中调节 Command 的超时时间,例如说2秒:
HystrixCommandSetter.WithGroupKey("TimeGroup")
.AndCommandKey("GetCurrentTime")
.AndCommandPropertiesDefaults(new HystrixCommandPropertiesSetter().WithExecutionIsolationThreadTimeout(TimeSpan.FromSeconds(2.0)).WithExecutionIsolationThreadInterruptOnTimeout(true))
当Hystrix执行命令超时后,Hystrix 执行命令超时或者失败之后,是会尝试去调用一个 fallback 的,这个 fallback 即一个备用方案,要为 HystrixCommand 提供 fallback,只要重写 protected virtual R GetFallback()方法即可。
一般情况下,Hystrix 会为 Command 分配专门的线程池,池中的线程数量是固定的,这也是一个保护机制,假设你依赖很多个服务,你不希望对其中一个服务的调用消耗过多的线程以致于其他服务都没 线程调用了。默认这个线程池的大小是10,即并发执行的命令最多只能有是个了,超过这个数量的调用就得排队,如果队伍太长了(默认超过 5),Hystrix就立刻走 fallback 或者抛异常。
根据你的具体需要,你可能会想要调整某个Command的线程池大小,例如你对某个依赖的调用平均响应时间为200ms,而峰值的QPS是200,那么这个并发至少就是 0.2 x 200 = 40 (Little's Law),考虑到一定的宽松度,这个线程池的大小设置为60可能比较合适:
public GetCurrentTimeCommand()
: base(HystrixCommandSetter.WithGroupKey("TimeGroup")
.AndCommandKey("GetCurrentTime")
.AndCommandPropertiesDefaults(new HystrixCommandPropertiesSetter().WithExecutionIsolationThreadTimeout(TimeSpan.FromSeconds(1.0)).WithExecutionIsolationThreadInterruptOnTimeout(true))
.AndThreadPoolPropertiesDefaults(new HystrixThreadPoolPropertiesSetter().WithCoreSize(60) // size of thread pool
.WithKeepAliveTime(TimeSpan.FromMinutes(1.0)) // minutes to keep a thread alive (though in practice this doesn't get used as by default we set a fixed size)
.WithMaxQueueSize(100) // size of queue (but we never allow it to grow this big ... this can't be dynamically changed so we use 'queueSizeRejectionThreshold' to artificially limit and reject)
.WithQueueSizeRejectionThreshold(10) // number of items in queue at which point we reject (this can be dyamically changed)
.WithMetricsRollingStatisticalWindow(10000) // milliseconds for rolling number
.WithMetricsRollingStatisticalWindowBuckets(10)))
{
}
说了这么多,还没提到Hystrix的断路器,其实对于使用者来说,断路器机制默认是启用的,但是编程接口默认几乎不需要关心这个,机制和前面讲的 也差不多,Hystrix会统计命令调用,看其中失败的比例,默认当超过50%失败后,开启断路器,那之后一段时间的命令调用直接返回失败(或者走 fallback),5秒之后,Hystrix再尝试关闭断路器,看看请求是否能正常响应。下面的几行Hystrix源码展示了它如何统计失败率的:
public HealthCounts GetHealthCounts()
{
// we put an interval between snapshots so high-volume commands don't
// spend too much unnecessary time calculating metrics in very small time periods
long lastTime = this.lastHealthCountsSnapshot;
long currentTime = ActualTime.CurrentTimeInMillis;
if (currentTime - lastTime >= this.properties.MetricsHealthSnapshotInterval.Get().TotalMilliseconds || this.healthCountsSnapshot == null)
{
if (Interlocked.CompareExchange(ref this.lastHealthCountsSnapshot, currentTime, lastTime) == lastTime)
{
// our thread won setting the snapshot time so we will proceed with generating a new snapshot
// losing threads will continue using the old snapshot
long success = counter.GetRollingSum(HystrixRollingNumberEvent.Success);
long failure = counter.GetRollingSum(HystrixRollingNumberEvent.Failure); // fallbacks occur on this
long timeout = counter.GetRollingSum(HystrixRollingNumberEvent.Timeout); // fallbacks occur on this
long threadPoolRejected = counter.GetRollingSum(HystrixRollingNumberEvent.ThreadPoolRejected); // fallbacks occur on this
long semaphoreRejected = counter.GetRollingSum(HystrixRollingNumberEvent.SemaphoreRejected); // fallbacks occur on this
long shortCircuited = counter.GetRollingSum(HystrixRollingNumberEvent.ShortCircuited); // fallbacks occur on this
long totalCount = failure + success + timeout + threadPoolRejected + shortCircuited + semaphoreRejected;
long errorCount = failure + timeout + threadPoolRejected + shortCircuited + semaphoreRejected;
healthCountsSnapshot = new HealthCounts(totalCount, errorCount); }
}
return healthCountsSnapshot;
}
其中 failure 表示命令本身发生错误、success 自然不必说,timeout 是超时、threadPoolRejected 表示当线程池满后拒绝的命令调用、shortCircuited 表示断路器打开后拒绝的命令调用,semaphoreRejected 使用信号量机制(而不是线程池)拒绝的命令调用。
http://www.cnblogs.com/shanyou/p/4752226.html
相关推荐
综上所述,Hystrix通过一系列精心设计的原则和机制,有效地解决了分布式系统中的可用性挑战,提高了系统的健壮性和稳定性。在实际项目中,使用Hystrix可以极大地简化服务容错和高可用性的实现,减少因依赖服务故障...
《Hystrix Dashboard 1.5.12:构建...对于Java开发者而言,掌握Hystrix Dashboard 的使用,能够提升系统的稳定性,确保服务的高可用性。同时,了解其背后的工作原理,有助于我们在遇到复杂系统问题时,迅速定位并解决。
Hystrix 是一个由 Netflix 开发并开源的容错库,它旨在通过添加延迟容忍和容错逻辑来隔离服务之间的交互,从而提高系统的整体弹性和性能。在分布式系统中,服务之间通常会通过网络进行通信。然而,网络延迟、故障...
### Hystrix熔断器简介及其工作原理 #### 一、Hystrix概念与背景 ...总之,Hystrix 作为一种强大的工具,不仅能够有效防止服务雪崩效应,还能提高系统的整体健壮性和可用性,是构建稳健分布式系统的必备组件之一。
Spring Cloud 提供了断路器模式的实现,名为 Hystrix,用于防止服务间的级联故障,提高系统的容错性。断路器模式的核心思想是在调用远程服务时,通过一个中间层(即断路器)来监控调用的健康状况。当服务出现故障时...
请求缓存机制允许将最近请求的结果存储起来,当接收到相同的请求时,可以直接从缓存中读取结果而不是重新发起网络调用,这有助于减少不必要的网络交互,提高系统的响应速度。 ##### 2.4 请求批处理 Hystrix还支持...
总结,Hystrix通过HystrixCommand实现了服务调用的封装,配合丰富的配置选项,能够有效地防止服务雪崩,提高系统的健壮性。同时,通过熔断和降级策略,确保了在服务不稳定时,系统仍能提供一定的可用性。在实际开发...
为了提高系统的可用性和可靠性,通常会将单一的服务进行集群部署。然而,在实际运行过程中,由于网络故障或服务自身的不稳定因素,可能会导致服务无法正常响应请求。这种情况下,若大量请求涌入,将会引起服务响应...
在现代微服务架构中,系统容错能力是至关重要的,Hystrix 是 Netflix 开源的一个用于处理分布式系统中延迟和故障的库,它通过隔离请求、降级策略以及熔断机制来保护服务免受异常的影响,提高系统的整体可用性。...
Hystrix是Netflix开源的一个用于构建弹性微服务架构的库,它主要目标是提供容错机制,防止服务雪崩,确保系统的稳定性和高可用性。在本篇文章中,我们将深入剖析Hystrix的工作原理,理解其执行流程,并探讨其中的...
在实际项目中,合理地配置和使用Hystrix不仅能提高系统的容错能力,还能优化整体的响应时间和资源利用率。理解并掌握Hystrix的这些特性对于开发健壮的微服务架构至关重要。 在压缩包文件列表中的"springcloud"可能...
《熔断器Hystrix:微服务...总结来说,Hystrix作为微服务架构的重要组件,通过其独特的熔断、降级和隔离机制,为服务的稳定性和高可用性提供了坚实保障。理解并熟练运用Hystrix,对于构建健壮的分布式系统至关重要。
其本质是线程没有及时回收,这可能导致系统资源耗尽,从而影响服务的稳定性和可用性。 为了解决服务雪崩,有几种常见的策略。首先,可以调整服务调用的超时时长,但这并不总是最佳方案,因为它可能过于僵化,无法...
《Spring Cloud ...总结,Spring Cloud Netflix Hystrix 是一个强大的工具,通过熔断器机制,实现了服务间的容错和隔离,提高了分布式系统的稳定性。理解和熟练运用 Hystrix,对于构建健壮的微服务架构至关重要。
在"Maven"的`pom.xml`文件中,添加`spring-cloud-starter-netflix-hystrix`和`spring-cloud-starter-netflix-eureka-client`依赖,确保Hystrix和Eureka客户端的可用性。 接下来,我们需要配置Hystrix。在`...
10. **最佳实践**:使用Hystrix Dashboard时,应定期检查和分析监控数据,识别潜在的性能瓶颈和故障点,及时调整服务架构和配置,提高整个微服务系统的健壮性。 总之,standalone Hystrix Dashboard 1.5.6提供了轻...
Hystrix的主要目标是隔离服务之间的调用,防止级联失败,并提供回退机制,确保系统的稳定性和高可用性。通过创建一个命令对象来封装服务调用,Hystrix可以在命令执行失败时启用备用逻辑,这就是断路器模式。 接下来...
这种架构可以很好地适应云环境,提高系统的可用性和容错性。 在实际项目中,我们还需要考虑其他的细节,例如日志记录、监控、配置管理等。但总的来说,Spring Boot与Consul、Feign和HystrixCommand的整合,为微服务...
这些代码通常会展示如何配置各个组件,如何编写服务提供者和服务消费者,以及如何在实际场景中利用它们来提高系统性能和可靠性。通过实践,你可以深入理解这些组件的用法,并将其应用于自己的项目中,提升微服务系统...
Spring Cloud Hystrix 是一个基于 Netflix Hystrix 实现的服务降级、断路器和熔断器框架,它被广泛应用于分布式系统中的容错管理,以提高系统的稳定性和可用性。在微服务架构中,服务间通信是常见的操作,而Spring ...