(springCloud-4 负载均衡Ribbon)

本文详细介绍了Spring Cloud Ribbon作为客户端负载均衡器的作用,讲解了Ribbon的基本配置,包括基于RestTemplate的系统通讯和默认轮询策略。接着探讨了Ribbon的各种内置负载均衡策略,如轮询、随机、过滤故障服务等。最后,文章演示了如何自定义负载均衡策略,以实现每台服务按顺序轮询执行3次的目标。

1.什么是Ribbon

Ribbon是客户端的一个负载均衡的工具;就是将请求尽量平均分配到各个系统上,分摊系统处理的压力,保证服务稳定的一种方式,其均衡策略 有轮询(默认),随机,过滤故障服务,自定义 等多种算法;

2,Ribbon的基本配置的学习(基于RestTemplate的系统通讯和Bribbon默认均衡策略 轮询)

在这里插入图片描述
一,之前好的搭建集群服务 springCloud服务搭建 集群服务搭建
在这里插入图片描述
二,在consumer 8001的服务引入Ribbon的依赖(完整pom)

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.zt.frank</groupId>
	<artifactId>zt-frank-consumer-service</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>zt-frank-consumer-service</name>
	<description>zt-frank-consumer-service</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.17</version>
		</dependency>
		<!-- actuator  健康检查 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<!-- 负载均衡ribbon -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
			<version>2.0.0.RELEASE</version>
		</dependency>
		<!--eureka -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
			<version>2.0.0.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-config-server</artifactId>
			<version>2.0.2.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

三,application.yml文件配置

app:
  id: zt-frank-consumer-service-8001
  name: zt-frank-consumer-service-8001

server:
  port: 8001
spring:
  application:
    name: zt-frank-consumer-service-8001

#eureka注册中心的地址
eureka:
  client:
    register-with-eureka: false #是否向服务注册中心注册自己(这里不要向注册中兴注册)
    service-url:
      #defaultZone: http://localhost:6001/eureka/
      defaultZone: http://eureka6001.com:6001/eureka/,http://eureka6002.com:6002/eureka/,http://eureka6003.com:6003/eureka/  #集群配置,将此服务同时注册到600160026003的服务中

四,编写RestTemplate的bean(注意:加上@LoadBalanced使用Ribbon的负载均衡)

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;
@Configuration
public class RestTemplateConfig {

    @Bean
    @LoadBalanced  //访问7001,7002服务带上负载均衡的机制
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

五,8001端请求7001 或者7002代码的编写(这里请求的URL是7001,7002的yml文件spring.application.name的值而且两个服务的值需要一样,注意转大写如下图)
在这里插入图片描述
下面是:8001服务用resetTemplate方式请求7001,7002服务的controller代码

@RestController
@RequestMapping("/con")
public class ConsumerTestController {

    private static Logger logger = Logger.getLogger(ConsumerTestController.class);

   //这个就是需要负载均衡的服务7001,7002 的http://+spring.application.name的值 (注意转大写)
    private final static String TEMPLATE_RIBBON_TEST ="http://ZT-FRANK-CONFIG-SERVICE";

    @Autowired
    private RestTemplate restTemplate;

    /**
     *  restTemplate  Ribbon负载均衡测试
     * @param str
     * @return
     */
	    @PostMapping("/ribbonTest")
	    public String restTemplateRibbonTest(@RequestParam String str){
	        logger.info("start-restTemplateRibbonTest:"+str);
	        String res = restTemplate.postForObject(TEMPLATE_RIBBON_TEST+"/config/health", str, String.class);
	        logger.info("end-restTemplateRibbonTest");
	        return res;
	    }
    }

六,测试,分别启动上述六个服务,并用postmen 调用8001服务的测试接口,并由Ribbon来决定调用7001,还是7002端口下的接口

7001的接口:

@Controller
@RequestMapping("/config")
public class Test {

    private static Logger logger = Logger.getLogger(Test.class);
    @PostMapping("/health")
    @ResponseBody
    public String test(){
        logger.info("+++++++++++++++++++++++++++++++请求成功TEST_7001+++++++++++++++++++++++++++++++++++");
        return "UP7001";
    }
}

7002的接口:

@Controller
@RequestMapping("/config")
public class Test {

    private static Logger logger = Logger.getLogger(Test.class);
    @PostMapping("/health")
    @ResponseBody
    public String test(){
        logger.info("+++++++++++++++++++++++++++++++请求成功TEST_7002+++++++++++++++++++++++++++++++++++");
        return "UP7002";
    }
}

测试:
在这里插入图片描述
在这里插入图片描述
测试显示7001和7002的接口通过8001服务来调用都是可以请求通的,而且8001调用7001,7002服务的顺序在没有额外配置的情况下是轮询的;

3.Ribbon负载均衡策略以及核心组件

第一种:

RiboonRobinRule
按照顺序执行

第二种:

RandomRule
随机

第三种:

AvailablilityFilteringRule
过滤掉多次访问故障发生熔断处于跳闸的服务,以及访问量超过阈值的服务,然后将剩下的服务列表进行轮询访问

第四种:

WeightedResponseTimeRule
根据服务平均响应时间计算,服务响应越快权重越大(但是服务刚启动服务信息统计不全,会使用轮询的策列,当服务信息足够了,就会使用这个策列)

第五种:

RetryRule 会按照默认轮询的策略进行服务访问,如果服务获取失败,会在指定的时间,进行重试,获取可用服务;

第六种:

BestAvailableRule 会过滤掉处于熔断跳闸状态的服务,然后选择一个并发量最小的一个服务

第七种:

ZoneAvoidanceRule 复合判断server所在区域的性能,来选择服务

部分配置

@Configuration
public class ConfigBean {
    /**
     * RestTemplate 的bean
     * @return
     */
    @Bean
    @LoadBalanced  //访问7001,7002服务带上负载均衡的机制
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }

    /**
     * Riboon负载均衡随机的策列
     * @return
     */
    @Bean
    public IRule myRandomRule(){
        return new RandomRule();
    }

    /**
     * Riboon负载均衡会过滤掉处于熔断跳闸状态的服务,然后选择一个并发量最小的一个服务
     * @return
     */
   //@Bean
   // public IRule myBestAvailableRule(){
   //     return new BestAvailableRule();
   // }
}

4,自定义负载均衡(实现目标:每台服务按顺序轮询执行3次)

第一步:
去除之前配置Ribbon提供的负载均衡配置bean
第二步:
在主启动类上添加@RibbonClient 注解,如下图:

@SpringBootApplication
@EnableEurekaClient
/**
 * 自定义负载均衡策列:
 * 		name:需要被负载均衡的7001,7002的服务yml文件下spring.application.name的值;
 * 		configuration:自定义策略的类;
 * 注意:
 * 		自定义Rule 配置类不能在@ComponentScan(注意:@SpringBootApplication就包含这个注解了)注解所扫描的当前包以及子包下面,
 * 		不然自定义的Ribbon配置规则就会被所有Ribbon客户端所共享,达不到特殊指定的规则
 */
@RibbonClient(name="ZT-FRANK-CONFIG-SERVICE" ,configuration = MyRule.class)
public class ZtFrankConsumerServiceApplication8001 {
	
	private static Logger logger = Logger.getLogger(ZtFrankConsumerServiceApplication8001.class);

	public static void main(String[] args) {	
		SpringApplication.run(ZtFrankConsumerServiceApplication8001.class, args);
		logger.info("*********ZtFrankConsumerServiceApplication80启动成功*********");
	}

}

第三步;新建包和MyRule , MyCustomRule类

MyRule :
在这里插入图片描述
MyCustomRule:

package com.zt.frank.zt.frank.rule;

import java.util.List;
import java.util.Random;

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;

/**
 * 自定义规则:
 * 实现目标:每台服务按顺序轮询执行3次
 * @author tao.zhang
 *
 */
public class MyCustomRule extends AbstractLoadBalancerRule{
	
	//轮询执行3次
	int total = 0;
	//当前机器号 7001 7002
	int curenIndex = 0;
	
    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        }
        Server server = null;

        while (server == null) {
            if (Thread.interrupted()) {
                return null;
            }
            //获取可用的服务
            List<Server> upList = lb.getReachableServers();
            //获取所有的服务
            List<Server> allList = lb.getAllServers();

            int serverCount = allList.size();
            if (serverCount == 0) {
                return null;
            }

            /**
             * 自定义规则
             */
            if(total<3){
            	server = upList.get(curenIndex);
            	total++;
            }else{
            	total = 0;
            	curenIndex++;
            	if(curenIndex>=upList.size()){
            		curenIndex = 0;
            	}
            }
            

            if (server == null) {
                /*
                 * The only time this should happen is if the server list were
                 * somehow trimmed. This is a transient condition. Retry after
                 * yielding.
                 */
                Thread.yield();
                continue;
            }

            if (server.isAlive()) {
                return (server);
            }

            // Shouldn't actually happen.. but must be transient or a bug.
            server = null;
            Thread.yield();
        }

        return server;

    }

	@Override
	public Server choose(Object key) {
		return choose(getLoadBalancer(), key);
	}

	@Override
	public void initWithNiwsConfig(IClientConfig arg0) {
		// TODO Auto-generated method stub
		
	}
	
	
}

第四步:
配置完成,测试:。。。。。。。略;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值