转载

Ribbon(客户端负载均衡)

Ribbon - 客户端负载均衡

简介

  • Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。它是一个基于HTTP和TCP的客户端负载均衡器。它可以通过在客户端中配置ribbonServerList来设置服务端列表去轮询访问以达到均衡负载的作用。

使用(消费端)

  • 导入依赖

    
1
2
3
4
5
6
7
8
9
10

    
<!--eureka客户端-->
<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>
  • 在消费端添加如下配置,用来从eureka集群中轮询请求可访问的微服务,不用注册到eureka中,配置如下:

    
1
2
3
4
5
6
7
8
9

    
server:
port: 8003
servlet:
context-path: /dept-consumer
eureka: # 配置eureka客户端,不用注册到eureka中
client:
serviceUrl:
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/,http://eureka7001.com:7001/eureka/ # eureka的暴露地址,指向集群中每一个eureka,多个用都好分隔
register-with-eureka: false # 只是消费者,因此不用将自己注册到eureka中
  • 在restTemplate的配置类中添加一个注解@LoadBalanced,配置如下:

    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

    
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
/**
* RestTemplate的配置类
* @author 陈加兵
* @since 2018年12月6日 下午6:10:58
*/
@Configuration
public class RestConfig
@Bean
@LoadBalanced //ribbon实现客户端的负载均衡,默认使用的是轮询的算法
public RestTemplate restTemplate(ClientHttpRequestFactory factory)
return new RestTemplate(factory);
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory()
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setReadTimeout( 5000); //单位为ms
factory.setConnectTimeout( 5000); //单位为ms
return factory;
  • 在主启动类上添加@EnableEurekaClient注解

    
1
2
3
4
5
6
7
8

    
@SpringBootApplication
@EnableEurekaClient
public class EurekaClientApplication
public static void main(String[] args)
SpringApplication.run(EurekaClientApplication.class, args);
  • 消费者的controller端直接使用微服务的名称访问即可,ribbon会自动根据名称在eureka中查询指定的微服务,不需要写明微服务的ip了,如下:

    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

    
@RestController
public class DeptController
@Resource
private RestTemplate restTemplate;
//请求路径直接使用微服务的名称即可EUREKA-PROVIDER,eureka-provider是微服务的项目名称(servlet.context-path)
private final static String URI_PREFIX= "http://EUREKA-PROVIDER/eureka-provider";
/**
* 使用RestTemplate发出get请求
*/
@GetMapping( "/dept/ id ")
public Dept getDept(@PathVariable("id")Integer id) throws RestClientException, URISyntaxException
Map<String, Object> params= new HashMap<String, Object>();
params.put( "id", id);
Dept dept = restTemplate.getForObject(URI_PREFIX+ "/dept/ id ", Dept.class, params);
return dept;
  • 创建两个提供者,提供相同的服务,使用同一个微服务的名称(EUREKA-PROVIDER),这个就相当于是一个集群了,需要改变的就是端口instance-id,配置如下:

    • 第一个服务提供者
    
          
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
          
    server:
    port: 8001
    servlet:
    context-path: /eureka-provider # 访问的项目名称在配置“集群”的时候也是必须一样的,否则不好调用
    eureka:
    client:
    serviceUrl:
    defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/,http://eureka7001.com:7001/eureka/ # eureka的暴露地址,直接注册,使用的是eureka的集群
    instance:
    instance-id: eureka-provider:8001 ## instance-id区别服务
    prefer-ip-address: true ## 访问路径可以显示服务主机的IP地址
    spring:
    application:
    name: eureka-provider #微服务的名称,配置集群的时候必须相同
    • 第二个服务提供者
    
          
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
          
    server:
    port: 8002
    servlet:
    context-path: /eureka-provider # 访问的项目名称在配置“集群”的时候也是必须一样的,否则不好调用
    eureka:
    client:
    serviceUrl:
    defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/,http://eureka7001.com:7001/eureka/ # eureka的暴露地址,直接注册,使用的是eureka的集群
    instance:
    instance-id: eureka-provider:8002 ## instance-id区别服务
    prefer-ip-address: true ## 访问路径可以显示服务主机的IP地址
    spring:
    application:
    name: eureka-provider #微服务的名称,配置集群的时候必须相同
  • 微服务启动,如下图:

  • Ribbon(客户端负载均衡)

  • 此时访问http://localhost:8003/dept/-consumer/dept/1可以发现此时的负载均衡的策略默认使用的是轮询算法

注意

  • 负载均衡是在同一个功能的微服务中根据不同的策略选择不同的微服务,因此这些微服务对外暴露的实例名称要相同(spring.application.name)
  • ribbon是一个客户端的负载均衡,必须要连接eureka,才能在指定的微服务实例中按照策略选择

负载均衡算法

  • RoundRobinRule:轮询,默认的算法
  • RandomRule : 随机算法
  • AvailabilityFilteringRule:会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,还有并发的连接数量超过阈值的服务,然后对剩余的服务列表按照轮询策略进行访问
  • WeightedResponseTimeRule:根据平均响应时间计算所有的权重,响应时间越快服务权重越大被选中的概率越高,刚启动时统计信息不足,则使用轮询策略,等统计信息足够,会自动切换到WeightedResponseTimeRule
  • RetryRule:先按照轮询策略获取服务,如果服务获取失败则在指定时间内会进行重试,获取可用的服务
  • BestAvailableRule:会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
  • ZoneAvoidanceRule:复合判断server所在区域的性能和server的可用性选择服务器

配置负载均衡策略

  • 直接创建一个配置类,注入想要使用的负载均衡算法即可

    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

    
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Ribbon负载均衡算法的配置类
* 1、原理:如果用户没有注入自己的算法,那么ribbon默认使用的是轮询算法,如果注入了,那么将会使用注入的
*/
@Configuration //表明这是一个配置类,相当于配置文件xml
public class RibbonRule
/**
* 配置随机算法,改变默认的轮询算法
* @return
*/
@Bean
public IRule rule()
return new RandomRule(); //直接返回随机算法

自定义负载均衡算法

  • 未完,待续……

超时时间设置

  • 默认超时时间为1000毫秒,如果需要修改超时时间,配置如下:
    • 由于是http请求,因此这里代表的socket的连接时间和读取时间

    
1
2
3

    
ribbon:
ReadTimeout: 5000 # 请求处理时间。
ConnectTimeout: 9000 # 请求连接时间。

重试机制

  • https://blog.csdn.net/akaks0/article/details/80039590
  • 全局配置如下:

    
1
2
3
4

    
ribbon:
OkToRetryOnAllOperations: true #对所有操作都进行重试。
MaxAutoRetriesNextServer: 2 # 切换实例的重试次数。
MaxAutoRetries: 1 # 对当前实例的重试次数。
原文  https://chenjiabing666.github.io/2018/12/25/Ribbon客户端负载均衡/
正文到此结束
Loading...