Spring Cloud — Ribbon 负载均衡

版本控制

  • Spring Cloud 基于 Hoxton.RELEASE
  • Spring Boot 基于 2.2.5.RELEASE

介绍

一般来说,为了服务的高可用,在生产环境中,每个微服务通常都会部署多个实例。因此服务消费者需要将请求合理的分摊到多个服务提供者实力上。Spring cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡工具

Nginx & Ribbon

Nginx

Nginx是服务端负载均衡。Nginx存在于服务的前端。客户端所有的请求都会交给Nginx服务器,然后由Nginx实现请求的分发。属于服务端负载均衡。

Ribbon

Ribbon是客户端负载均衡。它可以存在于多个客户端中。在SpringCloud中,Ribbon可以配合Eureka使用,在调用接口时,会从Eureka Server中获取服务列表,并基于指定的负载策略请求其中的一个实例。

LoadBalancerClient

LoadBalancerClientRibbon的核心组件。它是定义客户端负载均衡的接口。

  • 定义了几个方法:
    • execute()方法:用于执行请求;
    • econstructURI()方法:重构URI。整合Eureka后可以直接通过服务名去访问其他服务,如:http://api/restTemplate/ 其中api是其他服务在Eureka中注册的服务名称,在实际调用的时候需要将服务名api转为换具体的IP和端口的形式;
  • 继承了ServiceInstanceChooser接口:
    • 定义了choose()方法,用来从LoadBalancer中获取指定服务的一个实例;
  • 实现类为RibbonLoadBalancerClient

可以调用choose方法来获取服务实例:

ServiceInstance instance = loadBalancerClient.choose("serviceId");

RibbonLoadBalancerClientchoose()方法中,通过负载均衡器ILoadBalancer去获取实例信息:

	protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
		if (loadBalancer == null) {
			return null;
		}
		// 获取服务实例
		return loadBalancer.chooseServer(hint != null ? hint : "default");
	}

ILoadBalancer

定义负载均衡具体操作的接口。维护服务实例信息;

public interface ILoadBalancer {

	/**
	 * 初始化服务列表
	 */
	public void addServers(List<Server> newServers);
	
	/**
	 * 从负载均衡中获取一个服务实例
	 */
	public Server chooseServer(Object key);
	
	/**
	 * 标记指定服务已下线
	 */
	public void markServerDown(Server server);

	/**
	 * 获取可用的服务列表
     */
    public List<Server> getReachableServers();

    /**
     * 获取所有已知服务器,包括可用和不可用的
     */
	public List<Server> getAllServers();
}

IRule

具体定义负载均衡策略的接口。ILoadBalancer会根据IRule的规则去选择一个符合条件的服务实例

public interface IRule{

    public Server choose(Object key);
    
    public void setLoadBalancer(ILoadBalancer lb);
    
    public ILoadBalancer getLoadBalancer();    
}

IRule默认实现了一些策略,具体可以查看接口实现类:

  • RoundRobinRule:轮询方式(默认规则);
  • RandomRule:随机访问;
  • RetryRule:在轮询方式上加入重试机制;
  • BestAvailableRule:请求数最小的;
  • WeightedResponseTimeRule:根据响应时间加权

如果有特殊的需要可以自定义负载策略,只需要实现IRule`接口

捋一捋

整理一下负载均衡获取实例的流程:

  • loadBalancerClient调用choose方法;
  • ILoadBalancer调用chooseServer方法;
  • IRule调用choose方法;

实战

Ribbon的引入很简单,这里我们通过RestTemplate + Ribbon来实现服务的负载均衡。一个访问第三方RESTful API接口的网络请求框架,封装了常用的请求。首先创建一个Ribbon服务

pom
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
    </dependency>
yml文件
server:
  port: 8081
spring:
  application:
    name: ribbon
eureka:
  instance:
    # 以IP地址注册到服务中心,相互注册使用IP地址
    prefer-ip-address: true
    instance-id: ${spring.cloud.client.ipaddress}:${server.port}
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
# 配置 Ribbon 饥饿加载
ribbon:
  eager-load:
    enabled: true
    clients: api

Ribbon默认是懒加载的,只有当第一次请求时才回去创建ILoadBalancer,这就导致第一次请求时消耗更多时间,可能会出现请求超时的情况。通过ribbon.eager-load.enabled=trueribbon.eager-load.clients=server1,server2的形式配置饥饿加载模式,在项目启动时就创建对应的ILoadBalancer

config
@Configuration
public class RibbonConfig {

    /**
     * 通过RestTemplate来进行通信
     * 注解:@LoadBalanced 开启负载均衡
     */
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
    
    @Bean
    public IRule myRule() {
        // 随机方式,默认轮询:RoundRobinRule;也可以使用自己实现的
        return new RandomRule();
    }
}

通过@LoadBalanced注解表示在RestTemplate中使用Ribbon负载均衡;

默认的负载策略为轮询,如果需要实现其他的负载策略,只需要引入对应的IRule实例;

访问接口
@RestController
@RequestMapping("/ribbon")
public class RibbonController {

    private final RestTemplate restTemplate;

    private final LoadBalancerClient loadBalancerClient;

    public RibbonController(RestTemplate restTemplate, LoadBalancerClient loadBalancerClient) {
        this.restTemplate = restTemplate;
        this.loadBalancerClient = loadBalancerClient;
    }

    /**
     * LoadBalancerClient 从 Eureka Client 获取服务注册列表信息的,并进行缓存
     * 调用choose()方法时,会根据负载策略选择一个实例
     */
    @GetMapping("/loadBalancer")
    public String loadBalancerTest() {
        ServiceInstance instance = loadBalancerClient.choose("api");
        return instance.getHost() + ":" + instance.getPort();
    }

    /**
     * 整合Eureka后可以直接通过微服务名称进行访问
     */
    @GetMapping("/restTemplate/{msg}")
    public String restTemplateTest(@PathVariable String msg) {
        return restTemplate.getForObject("http://api/api/restTemplate/" + msg, String.class);
    }
}
API服务

新建一个API服务,注册到Eureka服务,创建对外接口类:

@RestController
@RequestMapping("/api")
public class AipController {

    @Value("${server.port}")
    private String port;

    @GetMapping("/restTemplate/{msg}")
    public String forRestTemplate(@PathVariable String msg) {
        System.out.printf("get message %s with restTemplate\n", msg);
        return "[restTemplate] from port: " + port;
    }
}
测试

启动Eureka服务,启动Ribbon服务,通过修改API服务端口号,多次启动服务。调用Ribbon服务的接口查看返回数据

访问源码

所有代码均上传至Github

>>>>>> Ribbon 负载均衡 <<<<<<

日常求赞

创作不易,如果各位觉得有帮助,求点赞 支持


求关注

微信公众号: 俞大仙

俞大仙

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值