精通springcloud:高级负载均衡和断路器
Posted jinggege795
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了精通springcloud:高级负载均衡和断路器相关的知识,希望对你有一定的参考价值。
高级负载均衡和断路器
本章将继续讨论第6章所涉猎的主题,即服务间通信。我们将把该主题扩展到更高级的负载均衡、超时和断路示例。
Spring Cloud提供的功能使得微服务之间的通信实现既简单又便捷。但是,不应忘记的是,我们在这种通信中遇到的主要困难均涉及系统的处理时间。如果开发人员的系统中有许多微服务,那么需要处理的首要问题之一就是延迟 (Delay) 问题。本章将讨论一些Spring Cloud功能,这些功能可以帮助开发人员避免延迟问题。这些延迟问题是在处理单个输入请求时,由于服务之间的跳数(Hop)太多,来自多个服务的响应缓慢或服务暂时不可用而导致的。有若干种策略都可以处理部分失败,这些策略包括设置网络超时、限制等待请求的数量、实现不同的负载均衡方法,或者设置断路器模式和回退实现等。
我们还将再次讨论Ribbon和Feign客户端,这次将重点关注其更高级的配置功能。本章将介绍一个全新的库,即Nettlix Hystrix。该库实现了断路器模式。
本章将要讨论的主题包括:
口使用 Ribbon客户端的不同负载均衡算法。
口~为应用程序启 用断路器。
口使用配置属性 自定义Hystrix.
口使用Hystrix仪表板监控服务间通信。
口联合使用Hystrix和Feign客户端。
负载均衡规则
Spring Cloud Netlix提供了不同的负载均衡算法,以便为用户提供不同的帮助。具体选择哪一种方法取决于开发人员的需求。在Netlix OSS术语中,该算法称为规则( Rule)。自定义规则类应该已经实现了IRule 基本接口。Spring Cloud中默认可用以下实现。
口RoundRobinRule: 此规则将简单地使用众所周知的轮询调度算法选择服务器,在该算法中,传入的请求将按顺序分布在所有实例上。它通常用作更高级规则的默认规则或回退逻辑,此类规则有
ClientConfigEnabledRoundRobinRule 和ZoneAvoidanceRule等。例如,ZoneAvoidanceRule就是Ribbon客户端的默认规则。
口
AvailabilityFilteringRule:此规则将跳过标记为电路跳闸(Circuit Tripped)或具有大量并发连接的服务器。它还将使用RoundRobinRule作为基类。默认情况下,如果HTTP客户端连续3次无法与其建立连接,则实例会电路跳闸。可以使用niws.loadbalancer. <clientName> .connctionFailureCountThreshold 属性自定义此方法。一旦实例电路跳闸,它将在下一次重试之前的下一个30秒内保持这种状态。也可以在配置设置中覆盖此属性。
口WeightedResponseTimeRule: 通过此实现,实例的流量转发器(Traffic VolumeForwarder)与实例的平均响应时间成反比。换句话说,响应时间越长,它的权重就越小。在这种情况下,负载均衡客户端将记录服务的每个实例的流量和响应时间。
口BestAvailableRule:根据类说明文档中的描述,此规则会跳过具有跳闸断路器的服务器,并选择具有最低并发请求的服务器。
➊注意:
跳闸斯路器( Tripped Circuit Breaker)是一个取自电气工程的术语,它意味着没有电流流过电路。在IT术语中,它指的是发送到服务的连续请求太多失败的情况,因此,客户端上的软件会立即中断调用远程服务的任何进一步尝试,以便释放服务器端的应用程序。
WeightedResponseTime 规则
到目前为止,我们通常都是通过从Web浏览器或REST客户端调用服务来手动测试它们。但是,当前的更改不允许这样的方法,因为我们需要为服务设置假延迟,并且还要生成许多HTTP请求。
引入 Hoverfly 进行测试
在这一点上,我们想引入一个有趣的框架,它可能是这类测试的完美解决方案。这个框架就是Hoverfly,它是一种用于存根(Stub)或模拟HTTP服务的轻量级服务虚拟化工具。它最初是用Go编写的,但也为开发人员提供了一个用于管理Java中的Hoverfly的富有表现力的API。Hoverfly Java由SpectoLabs维护,它提供了抽象二进制和API调用的类、用于创建模拟的领域专用语言(Domain Specified Language, DSL),以及与JUnit测试框架的集成。这个框架有一个笔者个人非常喜欢的功能。开发人员可以通过调用DSL定义中的一种方法,轻松地为每个模拟服务添加延迟。要为项目启用Hoerfly,开发人员必须在Maven的pom.xml中包含以下依赖项。
<dependency>
<groupId>io。specto</groupId>
<arti factId>hoverfly-java</artifactId>
<version>0.9.0</version>
<scope>test</ scope>
</dependency>
测试规则
本节所讨论的示例可以在GitHub上找到。要访问它,必须切换到weighted_ Ib 分支
tp:/github.com/piomin/sample-spring-cloud- comm/tree/weighted. Ilb) 。JUnit 测试类名为CustomerControllerTest,它位于src/estjava目录下。要启用Hoverfly测试,应该定义JUnit @ClassRule. HoverflyRule 类提供了一个API,该API允许开发人员使用不同的地址、特征(Characteristics) 和响应来模拟许多服务。在下面的源代码片段中,你可能会看到我们的示例微服务account-service 的两个实例已经在@ClassRule中声明。你可能还记得,该服务已经由customer-service 服务和order-service服务调用。现在来看一看customer-service服务模块中的测试类。它使用端口8091和9091上可用的account-service服务的两个实例的预定义响应来模拟GET /customer/*方法。第一个延迟了200毫秒,而第二个则延迟了50毫秒。
@ClassRule
public static HoverflyRule hoverflyRule = HoverflyRule
.inSimulationMode (ds1 (
service ("account-service :8091")
.andDelay(200,TimeUnit . MILLISECONDS) . forA1l ()
.get (startsWith ("/customer/"))
.willReturn (success("[{\\"id\\":\\"1\\", \\"number\\":\\"1234567890\\",
\\ "balance\\":5000}]", "application/json")),
service ("account-service: 9091")
. andDelay(50,, TimeUnit . MILLISECONDS) . forAll ()
.get (startswith(" /customer/"))
.willReturn (success("[{\\"id\\": \\"2\\", \\"number\\":\\"1234567891\\",
\\ "balance\\":8000}]", "application/json")))
.printSimulationData() ;
在运行该测试之前,还应该修改ribon.listOfServers 配置文件,方法是将其更改为listOfServers: account-service:8091, account-service:9091。 只应该在使用Hoverfly时进行这样的修改。
以下是一个用于测试用例的test方法,它将调用由customer-service 服务公开的GET/withAccounts/ {id}端点1000次。在这1000次中,每一次都将使用该客户所拥有的账户列表,依次调用account-service服务的GET customer/ {customerld}端点。每一次请求都将使用WeightedResponseTimeRule规则在account-service 服务的两个实例之间进行负载均衡。
@RunWith (Spr ingRunner .class)
@SpringBootTest (webEnvironment = WebEnvironment . DEFINED PORT)
public class CustomerControllerTest {
private static Logger LOGGER =
LoggerFactory.getLogger (CustomerControllerTest.class);
@Autowired
TestRestTemplate template ;
@Test
public void testCus tomerwithAccounts () (
for(inti=0;i<1000;1++)(
Customer c = template.getForobject ("/wi thAccounts/{id}",
Customer.class, 1) ;
LOGGER. info("Customer: { }", c);
}
}
}
使用加权响应规则(Weighted Response Rule)实现的方法非常有趣。在开始测试之后,传入的请求在两个account-service服务实例之间以50:50的比例进行负载均衡。但是,经过一段时间后,大多数都会转发给具有更小延迟的实例。
以笔者个人在本地计算机上启动的JUnit测试为例,最终,端口9091上的实例处理了731个请求,端口8091 上的实例处理了269个请求。但是,在测试的末尾阶段,该比例看起来有点不同,并且加权更有利于具有较小延迟的实例,其中传入流量在两个实例之间的比例大致被划分为4:1。
现在,可以通过添加第三个account-service服务实例来稍微改变一下我们的测试用例,新服务实例的延迟大约为10秒。此修改旨在模拟HTTP通信中的超时。以下是来自JUnit的@ClassRule 定义的片段,其中最新的服务实例将侦听端口10091。
service ("account- service :10091")
.andDelay (10000, TimeUnit .MILLISECONDS) . forAll ()
.get (startswith ("/customer/"))
.willReturn (success ("[(\\"id\\": \\"3\\",\\ "number\\": \\"1234567892\\",
\\"balance\\":1 0000}]", "application/json"))
相应地,我们还应该在Ribbon配置中执行以下更改,以便为最新的account-service服务实例启用负载均衡。
listOfServers: account -service :8091, account-service:9091, account-service:10091
还必须执行的最后一项修改, 就是RestTemplate bean声明。虽然和上一个测试用例一样,它需要获得保留,但是在本实例中,开发人员可以将读取和连接超时都设置为1秒,因为在测试期间启动的第三个account-service服务实例的延迟为10秒,所以发送到那里的每个请求都会在1秒后因为超时而终止。
@LoadBa lanced
@Bean
RestTemplate restTemplate (RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder
.setConnectTimeout (1000)
. setReadTimeout (1000)
.build();
}
如果此时运行与以前相同的测试,其结果将不会令人满意。所有声明的实例之间的分配将是: 420 个请求由侦听端口8091 (延迟200亳秒)的实例处理,468 个请求由侦听端口9091 (延迟50毫秒)的实例处理,并且仍然还有112个请求被发送到第三个实例,它们显然会由于超时而被终止。为什么会出现这样的统计数据呢?我们可以将默认的负载均衡规则从WeightedResponseTimeRule 更改为AvailabiltyFilteringRule,然后再重新运行测试。经过这样的修改之后,现在将会向第一个和第二个实例各发送496 个请求,而只有8个请求被发送到第三个实例,并且一秒超时。有趣的是,如果将默认规则设置为BestAvailableRule,则所有请求都将发送到第一个实例。
通过上述示例,相信开发人员已经完全明白了Ribbon客户端的所有可用负载均衡规则之间的差异。
自定义Ribbon客户端
可以使用Spring bean声明覆盖Ribbon 客户端的多个配置设置。与Feign一样,它应该在名为configuration的客户端注解字段中声明,如@RibbonClient(name= "account- service",configuration=RibonConfiguration.class)。使用此方法可以自定义以下功能。
口IClientConfig: 其默认实现是DefaultClientConfiglmpl.
口IRule:此组件将用于确定应从列表中选择哪一个服务实例。值得一提的是,ZoneAvoidanceRule实现类是自动配置的。
口IPing:这是一个在后台运行的组件。它负责确保服务实例正在运行。
口ServerList<Server>: 这可以是静态的也可以是动态的。如果它是动态的(由DynamicServerListL oadBalancer使用),那么后台线程将以预定义的间隔刷新并过滤列表。默认情况下,Ribbon使用从配置文件中获取的静态服务器列表。它由
ConfigurationBasedServerList 实现。
口ServerListFilter<Server> : ServerListFilter 同样是一个组件,它将由DynamicServerListL oadBalancer使用,可以过滤从ServerList实现返回的服务器。该接口有两种实现,即自动配置的
ZonePreferenceServerListilter 和ServerListSubsetFilter.
口lLoadBalancer: 它负责在客户端的服务的可用实例之间执行负载均衡。默认情况下,Ribbon 将使用ZoneAwarel oadBalancer.
口ServerListUpdater: 它负责更新给定应用程序的可用实例列表。默认情况下,Ribbon将使用PollingServerListUpdater.
现在让我们来看一个配置类示例,它将定义IRule和IPing组件的默认实现。通过提供@RibbonClients(
defaultConfiguration-RibbonConfiguration.class)注解,可以为单个Ribbon客户端以及应用程序类路径中可用的所有Ribbon客户端定义如下所示的配置。
@Configuration
public class RibbonConfiguration {
@Bean
public IRule ribbonRule () {
return new WeightedResponseTimeRule() ;
}
@Bean
public IPing ribbonPing() {
return new PingUrl () ;
}
}
即使没有使用Spring的经验,开发人员可能也已经猜到(基于之前的示例),这里也可以使用properties文件自定义配置。在这种情况下,Spring Cloud Netlix将与由Netflix提供的Ribbon 说明文档中描述的属性兼容。以下这些类就是受到支持的属性,它们应该以<clientName> .ribbon为前缀,或者如果它们适用于所有客户端,则仅使用ribbon作为前缀。
口NFLoadBalancerClassName: ILoadBalancer 默认实现类。
口
NFLoadBalancerRuleClassName: IRule 默认实现类。
口
NFLoadBalancerPingClassName: IPing 默认实现类。
口NIWSServerListClassName: ServerList 默认实现类。
口
NIWSServerListFilterClassName: ServerLstFilter 默认实现类。
以下示例与前面的@Configuration类相似,它将覆盖Spring Cloud 应用程序使用的IRule和IPing默认实现。
account- service:
ribbon:
NFLoadBalancerPingClassName: com. netflix. loadbalancer。PingUrlNFLoadBalancerRuleClas sName :
com. netflix.loadbalancer。WeightedResponseTimeRule
总结
因为文章包含的内容实在是太多了,就不给大家做过多的介绍了,需要这份文档来学习的小伙伴,可以转发此文关注小编。
扫码来获取就可以了!
以上是关于精通springcloud:高级负载均衡和断路器的主要内容,如果未能解决你的问题,请参考以下文章
#yyds干货盘点# springcloud整合feign实现服务负载均衡,断路器
Spring Cloud——分布式spring应用如何获得重试、负载均衡和断路器的好处