什么是负载均衡

当一台服务器的单位时间内的访问量越大时,服务器压力就越大,大到超过自身承受能力时,服务器就会崩溃。为了避免服务器崩溃,让用户有更好的体验,我们通过负载均衡的方式来分担服务器压力。

我们可以建立很多很多服务器,组成一个服务器集群,当用户访问网站时,先访问一个中间服务器,在让这个中间服务器在服务器集群中选择一个压力较小的服务器,然后将该访问请求引入该服务器。如此以来,用户的每次访问,都会保证服务器集群中的每个服务器压力趋于平衡,分担了服务器压力,避免了服务器崩溃的情况。

Ribbon

  Spring Cloud Ribbons是基于Netflix Ribbon实现的一套客户端负载均衡的工具。

  Spring Cloud Ribbon虽然只是一个工具类框架,它不像服务注册中心、配置中心、API网关那样需要独立部署,但是它几乎存在于每一个Spring Cloud构建的微服务和基础设施中。因为微服务间的调用,API网关的请求转发等内容,实际上都是通过Ribbon来实现的,包括后续我们将要介绍的Feign,它也是基于Ribbon实现的工具。所以,对Spring Cloud Ribbon的理解和使用,对于我们使用Spring Cloud来构建微服务非常重要。浅谈SpringCloud (三)   Ribbon负载均衡-LMLPHP

 SpringCloud使用Ribbon

1.修改客户端的pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springclouddemo</artifactId>
        <groupId>com.aomeibox</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>customer-order</artifactId>

    <name>customer-order</name>
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>1.4.0.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <!-- Ribbon 相关-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
            <version>1.1.0.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
        </dependency>

    </dependencies>

</project>

2.修改客户端的MyConfig类

package com.aomeibox.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

/**
 * Created by jl on 2018/12/27.
 */
@Configuration
public class MyConfig {

    @Bean
    @LoadBalanced  //负载均衡工具
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

3.修改客户端的controller,通过在Eureka中注册的ApplicaitonName进行访问

package com.aomeibox.con;

import com.aomeibox.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

/**
 * Created by leo on 2018/12/24.
 */
@RestController
public class OrderController {

    @Autowired
    private RestTemplate template;//spring提供的一个用于访问rest接口的模板对象
    private static final String url = "http://PROVIDER-USER";

//    @Autowired
//    private EurekaClient eurekaClient;

    @GetMapping("/order/{id}")
    public User getUser(@PathVariable Integer id){

//        InstanceInfo eureka = eurekaClient.getNextServerFromEureka("PROVIDER-USER", false);

        //访问提供者获取数据
//        User user = template.getForObject(eureka.getHomePageUrl()+"/user/"+ id, User.class);//通过访问rest 获取到json数据,然后转换成User对象

        User user = template.getForObject(url+"/user/"+ id, User.class);

        return user;
    }
}

4.运行项目

 浅谈SpringCloud (三)   Ribbon负载均衡-LMLPHP

Ribbon负载均衡策略

使用负载均衡带来的好处很明显:

  • 当集群里的1台或者多台服务器down的时候,剩余的没有down的服务器可以保证服务的继续使用
  • 使用了更多的机器保证了机器的良性使用,不会由于某一高峰时刻导致系统cpu急剧上升

负载均衡有好几种实现策略,常见的有:

  • 随机 (RandomRuler)
  • 轮询 (RoundRobinRuler)   (默认)
  • 一致性哈希 (ConsistentHashRuler)
  • 哈希 (HashRuler)
  • 加权(WeightedRuler)

   RoundRobinRule轮询策略表示每次都取下一个服务器,比如一共有5台服务器,第1次取第1台,第2次取第2台,第3次取第3台,以此类推。

   WeightedResponseTimeRule继承了RoundRobinRule,开始的时候还没有权重列表,采用父类的轮询方式,有一个默认每30秒更新一次权重列表的定时任务,该定时任务会根据实例的响应时间来更新权重列表,choose方法做的事情就是,用一个(0,1)的随机double数乘以最大的权重得到randomWeight,然后遍历权重列表,找出第一个比randomWeight大的实例下标,然后返回该实例。

   BestAvailableRule策略用来选取最少并发量请求的服务器。

如果需要改变轮训的策略,需要修改自己的配置类。

package com.aomeibox.config;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

/**
 * Created by leo on 2018/12/27.
 */
@Configuration
public class MyConfig {//@Configuration + 本类  = applicationContext.xml文件

    @Bean
    @LoadBalanced  //负载均衡工具
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

    @Bean
    public IRule myRule(){
        return new RandomRule();//随机策略
    }

}

自定义负载均衡策略

1.主启动类新增注解。注意,自己编写的Rule类,不能和主启动类放在同一个包下

package com.aomeibox;

import com.aomei.MySelfRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;

/**
 *
 * 消费者
 */
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "PROVIDER-USER",configuration = MySelfRule.class)//MySelfRule.class不能在本类的包或者子包下
public class CustomerOrder
{
    public static void main( String[] args )
    {
        SpringApplication.run(CustomerOrder.class);
    }
}

2.新增MyRule类。

package com.aomei;

import com.netflix.loadbalancer.BestAvailableRule;
import com.netflix.loadbalancer.IRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Created by leo on 2018/12/29.
 */
@Configuration
public class MySelfRule {

    @Bean
    public IRule myRule(){
        return new BestAvailableRule();
    }
}

Feign负载均衡

  上述的Ribbon功能很强大,可以自定义算法。

  Feign 是一个声明web服务客户端,这便得编写web服务客户端更容易,使用Feign 创建一个接口并对它进行注解,它具有可插拔的注解支持包括Feign注解与JAX-RS注解,Feign还支持可插拔的编码器与解码器,Spring Cloud 增加了对 Spring MVC的注解,Spring Web 默认使用了HttpMessageConverters, Spring Cloud 集成 Ribbon 和 Eureka 提供的负载均衡的HTTP客户端 Feign。

  上述大部分,我们通常是以微服务的ApplicaitonName进行访问的。但是在开发编程过程中,我们通常是面向接口编程。因此出现了Feign。Feign可以使用接口+注解,调用其他项目的接口。

@FeignClient("provider-user")
public interface UserClient {

    @RequestMapping(method = RequestMethod.GET, value = "/getuser")
    public User getuserinfo();

    @RequestMapping(method = RequestMethod.GET, value = "/getuser")
    public String getuserinfostr();

    @RequestMapping(method = RequestMethod.GET, value = "/info")
    public  String  info();

}
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class FeignApplication {

    public static void main(String[] args) {
        SpringApplication.run(FeignApplication.class, args);
    }

} 
@RestController
public class UserController {

    @Autowired
    UserClient userClient;

    @RequestMapping(value = "/getuserinfo", method = RequestMethod.GET)
    public User getuserinfo() {
        return userClient.getuserinfo();
    }

    @RequestMapping(value = "/getuserinfostr", method = RequestMethod.GET)
    public String getuserinfostr() {
        return userClient.getuserinfostr();
    }

    @RequestMapping(value = "/info", method = RequestMethod.GET)
    public String info() {
        return userClient.info();
    }


}
12-29 21:34