精通springcloud:高级负载均衡和断路器

Posted jinggege795

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了精通springcloud:高级负载均衡和断路器相关的知识,希望对你有一定的参考价值。

高级负载均衡和断路器

本章将继续讨论第6章所涉猎的主题,即服务间通信。我们将把该主题扩展到更高级的负载均衡、超时和断路示例。

精通springcloud:高级负载均衡和断路器

 

 

Spring Cloud提供的功能使得微服务之间的通信实现既简单又便捷。但是,不应忘记的是,我们在这种通信中遇到的主要困难均涉及系统的处理时间。如果开发人员的系统中有许多微服务,那么需要处理的首要问题之一就是延迟 (Delay) 问题。本章将讨论一些Spring Cloud功能,这些功能可以帮助开发人员避免延迟问题。这些延迟问题是在处理单个输入请求时,由于服务之间的跳数(Hop)太多,来自多个服务的响应缓慢或服务暂时不可用而导致的。有若干种策略都可以处理部分失败,这些策略包括设置网络超时、限制等待请求的数量、实现不同的负载均衡方法,或者设置断路器模式和回退实现等。

精通springcloud:高级负载均衡和断路器

 

我们还将再次讨论Ribbon和Feign客户端,这次将重点关注其更高级的配置功能。本章将介绍一个全新的库,即Nettlix Hystrix。该库实现了断路器模式。

本章将要讨论的主题包括:

口使用 Ribbon客户端的不同负载均衡算法。

口~为应用程序启 用断路器。

口使用配置属性 自定义Hystrix.

口使用Hystrix仪表板监控服务间通信。

口联合使用Hystrix和Feign客户端。

负载均衡规则

Spring Cloud Netlix提供了不同的负载均衡算法,以便为用户提供不同的帮助。具体选择哪一种方法取决于开发人员的需求。在Netlix OSS术语中,该算法称为规则( Rule)。自定义规则类应该已经实现了IRule 基本接口。Spring Cloud中默认可用以下实现。

精通springcloud:高级负载均衡和断路器

 

口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时进行这样的修改。

精通springcloud:高级负载均衡和断路器

 

以下是一个用于测试用例的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。

精通springcloud:高级负载均衡和断路器

 

现在,可以通过添加第三个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。PingUrl

NFLoadBalancerRuleClas sName :

com. netflix.loadbalancer。WeightedResponseTimeRule

总结

因为文章包含的内容实在是太多了,就不给大家做过多的介绍了,需要这份文档来学习的小伙伴,可以转发此文关注小编。

扫码来获取就可以了!

 

以上是关于精通springcloud:高级负载均衡和断路器的主要内容,如果未能解决你的问题,请参考以下文章

#yyds干货盘点# springcloud整合feign实现服务负载均衡,断路器

Spring Cloud——分布式spring应用如何获得重试、负载均衡和断路器的好处

Springcloud整合

SpringCloud升级之路2020.0.x版-32. 改进负载均衡算法

SpringCloud学习笔记

精通springcloud:微服务之间的通信,使用Ribbon执行负载均衡