转自:https://blog.csdn.net/pengjunlee/article/details/86594934

服务器端负载均衡
负载均衡是我们处理高并发、缓解网络压力和进行服务器扩容的重要手段之一,但是一般情况下我们所说的负载均衡通常都是指服务器端负载均衡,服务器端负载均衡又分为两种,一种是硬件负载均衡,还有一种是软件负载均衡。

硬件负载均衡主要通过在服务器节点之前安装专门用于负载均衡的设备,常见的如:F5。

软件负载均衡则主要是在服务器上安装一些具有负载均衡功能的软件来完成请求分发进而实现负载均衡,常见的如:LVS 、 Nginx 、Haproxy。

无论是硬件负载均衡还是软件负载均衡,它的工作原理都不外乎下面这张图:

客户端负载均衡
而微服务的出现,则为负载均衡的实现提供了另外一种思路:把负载均衡的功能以库的方式集成到服务的消费方,而不再是由一台指定的负载均衡设备集中提供。这种方案称为软负载均衡(Soft Load Balancing)或者客户端负载均衡。常见的如:Spring Cloud中的 Ribbon。

Ribbon是一个基于HTTP和TCP的客户端负载均衡器,当我们将Ribbon和Eureka一起使用时,Ribbon会到Eureka注册中心去获取服务端列表,然后进行轮询访问以到达负载均衡的作用,客户端负载均衡也需要心跳机制去维护服务端清单的有效性,当然这个过程需要配合服务注册中心一起完成。

服务器端负载均衡 VS 客户端负载均衡的特点如下:

服务器端负载均衡 客户端先发送请求到负载均衡服务器,然后由负载均衡服务器通过负载均衡算法,在众多可用的服务器之中选择一个来处理请求。

客户端负载均衡 客户端自己维护一个可用服务器地址列表,在发送请求前先通过负载均衡算法选择一个将用来处理本次请求的服务器,然后再直接将请求发送至该服务器。

接下来我们将延续上一章的Eureka注册中心,继续搭建一个基于Ribbon的客户端负载均衡示例。

Ribbon负载均衡示例搭建
创建服务提供者
引入依赖
新建一个 Maven 工程,取名 message-service 用来提供消息服务,在其 pom.xml 文件中引入依赖,内容如下:

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version>
</parent> <properties>
<spring-cloud.version>Finchley.SR2</spring-cloud.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Eureka-Client 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies> <dependencyManagement>
<dependencies>
<!-- SpringCloud 版本控制依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

添加配置

  application.yml 添加配置如下:

spring:
application:
name: message-service
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/

  

服务提供者
创建一个 MessageController 控制器对外提供一个http接口服务。

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; @RestController
@RequestMapping("/api/v1/msg")
public class MessageController { @Value("${server.port}")
private String port; /**
* 返回一条消息
*/
@GetMapping("/get")
public String getMsg() {
return "This message is sent from port: " + port;
}
}

创建启动类

import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication
@EnableEurekaClient
public class MessageApplication { public static void main(String[] args) {
new SpringApplicationBuilder(MessageApplication.class).web(WebApplicationType.SERVLET).run(args);
} }

启动服务
右键-->Run As --> Run Configurations...,分别使用 8771、8772、8773 三个端口各启动一个MessageApplication应用。

-Dserver.port=8771
-Dserver.port=8772
-Dserver.port=8773

启动完成后,浏览器输入:http://localhost:8761/ 效果图如下:

服务消费者
引入Ribbon依赖
新建一个 Maven 工程,取名 message-center 用来调用消息服务,在其 pom.xml 文件中引入依赖,内容如下:

	<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version>
</parent> <properties>
<spring-cloud.version>Finchley.SR2</spring-cloud.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Eureka-Client 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency> <!-- Ribbon 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
</dependencies> <dependencyManagement>
<dependencies>
<!-- SpringCloud 版本控制依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

添加配置
application.yml 添加配置如下:

server:
port: 8781
spring:
application:
name: message-center
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/

使用Ribbon客户端
方式一:

在启动类中向Spring容器中注入一个带有@LoadBalanced注解的RestTemplate Bean。

import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate; @SpringBootApplication
@EnableEurekaClient
public class MessageCenterApplication { @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { new SpringApplicationBuilder(MessageCenterApplication.class).web(WebApplicationType.SERVLET).run(args); } }

在调用那些需要做负载均衡的服务时,使用上面注入的RestTemplate Bean进行调用即可。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate; @RestController
@RequestMapping("/api/v1/center")
public class MessageCenterController { @Autowired
private RestTemplate restTemplate; @GetMapping("/msg/get")
public Object getMsg() { String msg = restTemplate.getForObject("http://message-service/api/v1/msg/get", String.class);
return msg; } }

方式二:

直接使用 LoadBalancerClient 中的负载均衡策略获取一个可用的服务地址,然后再进行请求。

import java.net.URI;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate; @RestController
@RequestMapping("/api/v1/center")
public class MessageCenterController { @Autowired
private LoadBalancerClient loadBalancer; @GetMapping("/msg/get")
public Object getMsg() { ServiceInstance instance = loadBalancer.choose("message-service");
URI url = URI.create(String.format("http://%s:%s/api/v1/msg/get", instance.getHost(), instance.getPort()));
RestTemplate restTemplate = new RestTemplate();
String msg = restTemplate.getForObject(url, String.class);
return msg; } }

待应用启动之后,连续三次请求地址 http://localhost:8781/api/v1/center/msg/get ,返回的结果如图所示:

切换Ribbon负载均衡策略
Ribbon本身提供了下面几种负载均衡策略:

RoundRobinRule: 轮询策略,Ribbon以轮询的方式选择服务器,这个是默认值。所以示例中所启动的两个服务会被循环访问;

RandomRule: 随机策略,也就是说Ribbon会随机从服务器列表中选择一个进行访问;

BestAvailableRule: 最大可用策略,即先过滤出故障服务器后,选择一个当前并发请求数最小的;

WeightedResponseTimeRule: 带有加权的轮询策略,对各个服务器响应时间进行加权处理,然后在采用轮询的方式来获取相应的服务器;

AvailabilityFilteringRule: 可用过滤策略,先过滤出故障的或并发请求大于阈值的一部分服务实例,然后再以线性轮询的方式从过滤后的实例清单中选出一个;

ZoneAvoidanceRule: 区域感知策略,先使用主过滤条件(区域负载器,选择最优区域)对所有实例过滤并返回过滤后的实例清单,依次使用次过滤条件列表中的过滤条件对主过滤条件的结果进行过滤,判断最小过滤数(默认1)和最小过滤百分比(默认0),最后对满足条件的服务器则使用RoundRobinRule(轮询方式)选择一个服务器实例。

我们可以将上例中的message-service的负载均衡策略设置为随机访问RandomRule,application.yml配置如下:

message-service:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

当然,我们也可以通过继承ClientConfigEnabledRoundRobinRule,来实现自己的负载均衡策略。

自定义Ribbon客户端
您可以使用外部属性按照 <clientName>.<nameSpace>.<propertyName>=<value> 的格式对Ribbon客户端的某些特性进行配置,这与使用Netflix API类似。当然,你也可以在Springboot配置文件中进行配置。所有的配置项均以静态字段的形式定义在 CommonClientConfigKey 类(Ribbon核心的一部分)中。

SpringCloud还允许你在RibbonClientConfiguration的基础之上使用@RibbonClient声明一些额外配置,从而实现对Ribbon客户端的完全控制,如下例所示:

import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.netflix.ribbon.ZonePreferenceServerListFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import com.netflix.loadbalancer.IPing;
import com.netflix.loadbalancer.PingUrl;
import com.pengjunlee.TestConfiguration.MessageConfiguration; @Configuration
@RibbonClient(name = "message-service", configuration = MessageConfiguration.class)
public class TestConfiguration { @Configuration
protected static class MessageConfiguration {
@Bean
public ZonePreferenceServerListFilter serverListFilter() {
ZonePreferenceServerListFilter filter = new ZonePreferenceServerListFilter();
filter.setZone("myTestZone");
return filter;
} @Bean
public IPing ribbonPing() {
return new PingUrl();
}
}
}

  

在这个例子中,这个Ribbon客户端将由RibbonClientConfiguration和MessageConfiguration中的组件一起组成(后者会覆盖前者的配置)。

注意:本例中,MessageConfiguration必须用@Configuration注解标注,但是它不应该被包含在Spring的组件扫描路径之中,否则它将被所有的Ribbon客户端共享。如果你使用@ComponentScan(或者@SpringBootApplication),那么你应该采取措施来避免它被包含到扫描范围之中。

下表列出了 Spring Cloud Netflix 缺省为Ribbon提供的所有 Bean:

创建这些类型的一个Bean 并将它写到 @RibbonClient 声明的配置中,这样你就能够对这些Bean中的每一个进行重写。例如上面的 MessageConfiguration 中利用PingUrl替代了NoOpPing并提供了一个自定义的serverListFilter。

自定义Ribbon客户端的默认配置
通过@RibbonClients注解可以为所有的Ribbon客户端提供一个默认的配置。例如

import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.BestAvailableRule;
import com.netflix.loadbalancer.ConfigurationBasedServerList;
import com.netflix.loadbalancer.IPing;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.PingUrl;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ServerList;
import com.netflix.loadbalancer.ServerListSubsetFilter; @RibbonClients(defaultConfiguration = DefaultRibbonConfig.class)
public class RibbonClientDefaultConfigurationTestsConfig { public static class BazServiceList extends ConfigurationBasedServerList {
public BazServiceList(IClientConfig config) {
super.initWithNiwsConfig(config);
}
}
} @Configuration
class DefaultRibbonConfig { @Bean
public IRule ribbonRule() {
return new BestAvailableRule();
} @Bean
public IPing ribbonPing() {
return new PingUrl();
} @Bean
public ServerList<Server> ribbonServerList(IClientConfig config) {
return new RibbonClientDefaultConfigurationTestsConfig.BazServiceList(config);
} @Bean
public ServerListSubsetFilter serverListFilter() {
ServerListSubsetFilter filter = new ServerListSubsetFilter();
return filter;
} }

  

通过配置属性自定义Ribbon客户端
Spring Cloud Netflix 从1.2.0版本开始支持通过配置属性自定义Ribbon客户端,这可以让你在应用启动时根据不同的环境来改变Ribbon的行为。

支持配置的属性列表如下:

<clientName>.ribbon.NFLoadBalancerClassName: 需实现 ILoadBalancer
<clientName>.ribbon.NFLoadBalancerRuleClassName: 需实现 IRule
<clientName>.ribbon.NFLoadBalancerPingClassName: 需实现 IPing
<clientName>.ribbon.NIWSServerListClassName: 需实现 ServerList
<clientName>.ribbon.NIWSServerListFilterClassName: 需实现 ServerListFilter

  

注意:通过配置属性定义的类与上述@RibbonClient配置类中定义的Bean以及Spring Cloud Netflix

提供的缺省配置相比具有更高的优先级。

例如对 message-service 服务的 IRule 属性进行修改,可以在application.yml中进行如下配置:

message-service:
ribbon:
NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule

  

脱离Eureka使用Ribbon
Eureka提供了一种抽象的发现远程服务的便捷的方式,这样你就不必在客户端中硬编码服务地址列表,但是如果你不用Eureka,也可以继续使用Ribbon和Feign。假设在不使用Eureka,你用@RibbonClient声明了一个"stores"服务,这个时候Ribbon Client 默认会引用一个配置好的服务列表,你可以在application.yml中对它进行配置:

stores:
ribbon:
listOfServers: example.com,google.com

  

在Ribbon中禁用Eureka
通过将 ribbon.eureka.enabled 属性设置为 false 可以在Ribbon中禁用Eureka。

ribbon:
eureka:
enabled: false

  

Ribbon缓存配置
对于每一个Ribbon客户端,Spring Cloud都会维护一个与其相应的应用上下文,这个应用上下文会在相应服务第一次被请求时进行懒加载。你可以使用饥饿加载来取代懒加载,通过指定那些需要饥饿加载Ribbon客户端名称,在应用启动时就对其应用上下文进行加载。

ribbon:
eager-load:
enabled: true
clients: client1, client2, client3

  

参考文章
https://www.jianshu.com/p/d32ae141f680

https://blog.csdn.net/u014401141/article/details/78676296

https://cloud.spring.io/spring-cloud-static/spring-cloud-netflix/2.0.2.RELEASE/single/spring-cloud-netflix.html#spring-cloud-ribbon 

原文链接:https://blog.csdn.net/pengjunlee/article/details/86594934

【springcloud】客户端负载均衡(Ribbon)的更多相关文章

  1. 客户端负载均衡Ribbon

    客户端负载均衡Ribbon 一.Ribbon是什么 二.Ribbon实现客户端负载均衡 三.Ribbon负载均衡策略 四.Rest请求模板类解读 4.1 RestTemplate的GET请求 第一种: ...

  2. SpringCloud开发学习总结(四)—— 客户端负载均衡Ribbon

    通过上一章<SpringCloud开发学习总结(三)—— 服务治理Eureka>,我们已经搭建起微服务架构中的核心组件——服务注册中心(包括单点模式和高可用模式).同时还注册了一个服务,命 ...

  3. 五、springcloud之客户端负载均衡Ribbon

    一.简介 在微服务架构中,业务都会被拆分成一个独立的服务,服务与服务的通讯是基于http restful的.Spring cloud有两种服务调用方式: 一种是ribbon+restTemplate, ...

  4. SpringCloud 客户端负载均衡:Ribbon

    目录 Ribbon 介绍 开启客户端负载均衡,简化 RestTemplate 调用 负载均衡策略 Ribbon 介绍 Ribbon 是 Netflix 提供的一个基于 Http 和 TCP 的客户端负 ...

  5. 客户端负载均衡Ribbon之二:Loadbalance的源码

    Load Balance负载均衡是用于解决一台机器(一个进程)无法解决所有请求而产生的一种算法. 像nginx可以使用负载均衡分配流量,ribbon为客户端提供负载均衡,dubbo服务调用里的负载均衡 ...

  6. 服务注册发现Eureka之三:Spring Cloud Ribbon实现客户端负载均衡(客户端负载均衡Ribbon之三:使用Ribbon实现客户端的均衡负载)

    在使用RestTemplate来消费spring boot的Restful服务示例中,我们提到,调用spring boot服务的时候,需要将服务的URL写死或者是写在配置文件中,但这两种方式,无论哪一 ...

  7. 0403-服务注册与发现-客户端负载均衡-Ribbon的基本使用

    一.概述 问题1.上一篇文章已说明如何注册微服务,但是调用方如何调用,以及如何防止硬编码.即电影微服务调用用户微服务 问题2.用户微服务多个节点,调用服务方如何负载均衡 二.实现负载均衡方式 2.1. ...

  8. 客户端负载均衡Ribbon之源码解析

    什么是负载均衡器? 假设有一个分布式系统,该系统由在不同计算机上运行的许多服务组成.但是,当用户数量很大时,通常会为服务创建多个副本.每个副本都在另一台计算机上运行.此时,出现 "Load ...

  9. Spring Cloud第四篇 | 客户端负载均衡Ribbon

    ​ 本文是Spring Cloud专栏的第四篇文章,了解前三篇文章内容有助于更好的理解本文: ​Spring Cloud第一篇 | Spring Cloud前言及其常用组件介绍概览 Spring Cl ...

随机推荐

  1. 团队开发day10

    项目整合成功,测试功能基本达到,目标完成!

  2. Easyui动态添加控件无法渲染 $.parser.parse()无效

    本文链接:https://blog.csdn.net/huangbaokang/article/details/78367553动态添加easyui控件<input class="ea ...

  3. 42 张图带你撸完 MySQL 优化

    Hey guys,这里是程序员cxuan,欢迎你阅读我最新一期的文章,这篇文章是 MySQL 调优的汇总版,我加了一下日常开发过程中的调优经验,希望对各位小伙伴们有所帮助.下面开始正文. 一般传统互联 ...

  4. odoo中接口开发

    文章参考:https://blog.csdn.net/qq_33472765/article/details/81913627案例0000001接口调用请求说明:https请求方式:GET(请使用ht ...

  5. CentOS7下OpenLDAP部署

    OpenLDAP作为开源的LDAP服务,可用于搭建统一认证平台,在很多企业内部应用比较广泛,本文将介绍在CentOS7下OpenLDAP的部署. 环境: CentOS 7.4 OpenLDAP 2.4 ...

  6. Axure RP 9 Enterprise/Pro/Team for Mac/Windows安装破解版激活教程

    Axure RP 9.0 是一款功能强大的.操作方便.专业可靠的快速原型设计工具.一款能够在这里体验最简单的设计方式,这里有着全新的升级的软件界面,更加的时尚,更加的丰富,专为每一个用户提供了便捷的设 ...

  7. onclick="return doAlert()" onclick="return false"

    return false不是取bai消事件冒泡,而是取消"du浏览器默认行为".比如一个链接zhi<a href="http://zhidao.baidu.com& ...

  8. PS Lite - 源码解读

    PostOffice 类 /** * \brief 系统的中心. */ class Postoffice { public: /** * \brief 返回单例对象. */ static Postof ...

  9. ASP.NET Core下FreeSql的仓储事务

    ASP.NET Core下FreeSql的仓储事务 第一步:配置 Startup.cs 注入 引入包 dotnet add package FreeSql dotnet add package Fre ...

  10. Python 和 C/C++ 拓展程序如何性能优化?看这一篇文就够

    作者:王璐璐 | 旷视 MegEngine 架构师 一. 背景 在 MegEngine imperative runtime 的早期开发中,我们面临着一些的性能优化问题.除了一些已知需要重构的地方(早 ...