spring cloud 项目搭建 :2、ribbon客户端负载均衡

写在前面

1、ribbon介绍

1、轮询:用户获取资源时,从几个服务中轮询获取
2、随机:随机获取
3、加强轮询:在轮询的基础上设置一个权重值,根据权重轮询
4、hash算法:根据hash值选择,该算法无法解决热点请求,会把某个时间段的请求路由到某个单机上,造成雪崩
5、最小连接数:把请求分配给活动连接数最小的后端服务器
6、最短响应时间:通过ping或者正常的响应时间来分配
7、加权最小连接数:对性能较好的后端服务器设置较高的权重,承担更多的链接负载。

1.1、在消费者模块添加ribbon

添加依赖

		<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-ribbon -->
		<dependency>
    		<groupId>org.springframework.cloud</groupId>
    		<artifactId>spring-cloud-starter-ribbon</artifactId>
   			<version>1.4.6.RELEASE</version>
		</dependency>
		<!--erueka的依赖也需要-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

yml里面添加配置(配置eureka的注册中心地址)

 server.port: 80
# eureka配置
eureka:
  client:
    register-with-eureka: false # 服务消费者,不需要往注册中心注册
    service-url:
      defaultZone: http://127.0.0.1:7001/eureka/,http://127.0.0.2:7002/eureka/,http://127.0.0.3:7003/eureka/

向启动类添加注解@EnableEurekaClient
在这里插入图片描述
向RestTemplate上添加注解@LoadBalanced
在这里插入图片描述
修改访问链接(修改成通过服务名访问)

private static final String URL_PREFIX = “http://SPRINGCLOUD-PROVIDER-DEPT”;

在这里插入图片描述

1.2、测试

启动注册中心、服务提供者、服务消费者
访问:http://127.0.0.1/consumer/dept/get
在这里插入图片描述

2、模拟集群环境

建三个服务提供者

2.1、建库建表

让三个服务提供者分别使用不同的数据
新建库test2、test3,并插入数据

create database test2;
use test2;
CREATE TABLE `dept` (
  `deptno` bigint(20) NOT NULL AUTO_INCREMENT,
  `dname` varchar(60) CHARACTER SET utf8mb4 DEFAULT NULL,
  `db_source` varchar(60) CHARACTER SET utf8mb4 DEFAULT NULL,
  PRIMARY KEY (`deptno`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COMMENT='部门表';

INSERT INTO `dept` VALUES ('1', '开发部', database());
INSERT INTO `dept` VALUES ('2', '财务部', database());
INSERT INTO `dept` VALUES ('3', '市场部', database());
INSERT INTO `dept` VALUES ('4', '人事部', database());
INSERT INTO `dept` VALUES ('5', '运维部', database());
INSERT INTO `dept` VALUES ('6', '销售部', database());


create database test3;
use test3;
CREATE TABLE `dept` (
  `deptno` bigint(20) NOT NULL AUTO_INCREMENT,
  `dname` varchar(60) CHARACTER SET utf8mb4 DEFAULT NULL,
  `db_source` varchar(60) CHARACTER SET utf8mb4 DEFAULT NULL,
  PRIMARY KEY (`deptno`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COMMENT='部门表';

INSERT INTO `dept` VALUES ('1', '开发部', database());
INSERT INTO `dept` VALUES ('2', '财务部', database());
INSERT INTO `dept` VALUES ('3', '市场部', database());
INSERT INTO `dept` VALUES ('4', '人事部', database());
INSERT INTO `dept` VALUES ('5', '运维部', database());
INSERT INTO `dept` VALUES ('6', '销售部', database());

2.2、新建模块

新建如下两个模块(maven)
在这里插入图片描述
往这两个模块的pom.xml加入依赖

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
        </dependency>
        <!-- 你们会发现springboot的依赖都没引入,直接引入mybatis的stater,springboot的依赖就自动引进来了-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--  jetty,和tomcat一样是一个web容器,Jetty相比与Tomcat是轻量级的-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
        <!-- 热部署工具:写完代码等待一会就部署上去了,不用手动重启 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>

        <!-- 导入我们自己的模块 -->
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>

        <!-- eureka -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <!-- actuator完善监控信息 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

把springcloud-provider-dept-8001模块的application.yml复制进这两个模块,只需要修改下面几个个地方
在这里插入图片描述
接下来将mapper.xml、java文件复制进去,为了方便区分,我们在启动类上加上端口号
在这里插入图片描述

2.3、启动

启动三个eureka注册中心、三个服务提供者、一个服务消费者
在这里插入图片描述
访问:http://127.0.0.1:7001/
在这里插入图片描述
访问:http://127.0.0.1/consumer/dept/get
在这里插入图片描述
通过多次测试发现,ribbon默认的负载均衡应该是轮询

3、自定义负载均衡

3.1、使用已经定义好的一些负载均衡

使用系统里预置的一些负载均衡策略

// RoundRobinRule 默认,轮询
// RandomRule 随机
// AvailabilityFilteringRule 会过滤掉,跳闸,访问故障的服务,对剩下的进行轮询
// RetryRule 会先按照轮询获取服务,如果服务获取失败,则会在指定的时间内进行、重试

在这里插入图片描述

随机策略: 使用某个服务的时候,ribbon会随机选择一个

3.2、自己写一个负载均衡策略

注意:自己写的负载均衡策略必须@Configuration,但注意它不在主应用程序上下文的@ComponentScan中,否则将由所有@RibbonClients共享。解决方式:将它放在 springboot主启动的上级目录中,如下图

!在这里插入图片描述

加载自定义的ribbon

@RibbonClient(name = “SPRINGCLOUD-PROVIDER-DEPT”,configuration = CustomRule.class)

在这里插入图片描述
上面写的那个MyRule返回的只是系统的随机负载均衡策略,
接下来我们根据随机负载均衡策略里面的代码自己写一个CustomRule
在这里插入图片描述

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.*;
import org.springframework.context.annotation.Configuration;

import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

public class CustomRule extends AbstractLoadBalancerRule {
    // 每个服务访问5个,完了之后再访问下一个

    private int total = 0;              // 被调用的字数
    private int currentIndex = 0;       // 当前是谁在提供服务


    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        } else {
            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<5){
                    server = upList.get(currentIndex);
                    total++;
                }else {
                    total = 0;
                    currentIndex++;
                    if(currentIndex>upList.size())  currentIndex = 0;
                    server = upList.get(currentIndex);
                }

                if (server == null) {
                    Thread.yield();
                } else {
                    if (server.isAlive()) {
                        return server;
                    }

                    server = null;
                    Thread.yield();
                }
            }

            return server;
        }
    }

    protected int chooseRandomInt(int serverCount) {
        return ThreadLocalRandom.current().nextInt(serverCount);
    }

    public Server choose(Object key) {
        return this.choose(this.getLoadBalancer(), key);
    }

    public void initWithNiwsConfig(IClientConfig clientConfig) {
    }
}

使用自定义策略
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值