JavaEE进阶知识学习-----SpringCloud(六)Ribbon负载均衡

Ribbon负载均衡

Ribbon概述

Spring Cloude Ribbon是基于Netfilx Ribbon实现的一套客户端 负载均衡的工具,简单说,Ribbon是Netfilix发布的开源项目,主要功能就是提供 客户端的软件负载均衡算法,将Netfilix的中间层服务连接在一起,Ribbon客户端组件提供了一系列完善的配置项如连接超时,重试等,简单说,就是在配置文件中列出Load Balance后面的所有机器,Ribbon会自动的帮助你基于某种算法规则(简单轮询,随机连接等)去连接这些机器,也可以使用Ribbon自定义负载均衡算法。LB,即负载均衡,在微服务或者分布式集群中常用的一种应用。负载均衡就是将用户的请求平摊的分配到多个服务上,从而达到HA,常见的负载均衡软件有Nginx,LVS,硬件F5等

Ribbon配置初步

由于Ribbon是客户端的负载均衡工具,所以我们需要修改的是客户端项目microservicecloud-consumer-dept-80

POM.xml文件

<!-- Ribbon相关 -->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

修改application.yml文件,添加Eureka的服务注册地址

server:
  port: 80
eureka:
  client:
    register-with-eureka: false #自己不能注册
    service-url: 
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/  

修改客户端配置类

由于客户端使用restTemplate访问服务端中的数据接口,restTemplate配置在服务端的配置类中,所以修改如下

@Configuration
public class ConfigBean {
    @Bean
    @LoadBalanced
    public RestTemplate geRestTemplate(){
        return new RestTemplate();
    }
}

修改客户端主程序启动类

@SpringBootApplication
@EnableEurekaClient
public class DeptConsumer80_App {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumer80_App.class, args);
    }
}

修改客户端访问类DeptController_Consumer.java

private static final String REST_URL_PREFIX = "http://MICROSERVICECLOUD-DEPT";

测试

启动7001,7002,7003三个服务注册中心,启动8001服务提供者,启动80客户端,使用http://localhost/consumer/dept/list可以渠道对应的数据,在DeptController_Consumer使用的是http://MICROSERVICECLOUD-DEPT服务名称来调用服务的接口,相比之前的http://localhost:8001,Ribbon和Eureka整合后,Consumer可以直接通过服务名称来调用服务,而不再关心地址和端口号。

Ribbon负载均衡

目前只有一个microservicecloud-provider-dept-8001服务提供者,为了实现Ribbon的负载均衡,所以我们需要多个服务提供者实例,新建microservicecloud-provider-dept-8002,microservicecloud-provider-dept-8003两个Module。参考8001的pom.xml文件修改8002,8003的pom.xml文件。拷贝8001中的所以类和配置文件mybatis和application.yml文件,将主启动类修改为对应的名字

microservicecloud-provider-dept-8002服务提供者

使用的数据库SQL语句

DROP DATABASE IF EXISTS cloudDB02 ;

CREATE DATABASE cloudDB02 CHARACTER SET UTF8 ;

USE cloudDB02 ;

CREATE TABLE dept (
  deptno BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
  dname VARCHAR (60),
  db_source VARCHAR (60)
) ;

INSERT INTO dept(dname,db_source) VALUES('开发部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES('人事部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES('财务部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES('市场部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES('运维部',DATABASE());

Application.yml文件

server:
  port: 8002
  
mybatis:
  config-location: classpath:mybatis/mybatis.cfg.xml        # mybatis配置文件所在路径
  type-aliases-package: com.luo.springcloud.entities        # 所有Entity别名类所在包
  mapper-locations:
  - classpath:mybatis/mapper/**/*.xml                       # mapper映射文件
    
spring:
   application:
    name: microservicecloud-dept 
   datasource:
    type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
    driver-class-name: org.gjt.mm.mysql.Driver              # mysql驱动包
    url: jdbc:mysql://localhost:3306/cloudDB02              # 数据库名称
    username: root
    password: 1234
    dbcp2:
      min-idle: 5                                           # 数据库连接池的最小维持连接数
      initial-size: 5                                       # 初始化连接数
      max-total: 5                                          # 最大连接数
      max-wait-millis: 200      

microservicecloud-provider-dept-8003服务提供者

使用的数据库SQL语句

DROP DATABASE IF EXISTS cloudDB03 ;

CREATE DATABASE cloudDB03 CHARACTER SET UTF8 ;

USE cloudDB03 ;

CREATE TABLE dept (
  deptno BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
  dname VARCHAR (60),
  db_source VARCHAR (60)
) ;

INSERT INTO dept(dname,db_source) VALUES('开发部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES('人事部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES('财务部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES('市场部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES('运维部',DATABASE());

Application.yml文件

server:
  port: 8003
  
mybatis:
  config-location: classpath:mybatis/mybatis.cfg.xml        # mybatis配置文件所在路径
  type-aliases-package: com.luo.springcloud.entities        # 所有Entity别名类所在包
  mapper-locations:
  - classpath:mybatis/mapper/**/*.xml                       # mapper映射文件
    
spring:
   application:
    name: microservicecloud-dept 
   datasource:
    type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
    driver-class-name: org.gjt.mm.mysql.Driver              # mysql驱动包
    url: jdbc:mysql://localhost:3306/cloudDB03              # 数据库名称
    username: root
    password: 1234
    dbcp2:
      min-idle: 5                                           # 数据库连接池的最小维持连接数
      initial-size: 5                                       # 初始化连接数
      max-total: 5                                          # 最大连接数
      max-wait-millis: 200      

微服务提供者说明

三个微服务提供者连接不同的数据库,因此在application.yml文件中,我们需要修改端口号和连接的数据库,注意的是三个微服务提供者的微服务名字保持一样,也就是如下的配置信息

spring:
   application:
    name: microservicecloud-dept 

负载均衡自测

访问连接http://localhost:8001/dept/listhttp://localhost:8002/dept/listhttp://localhost:8003/dept/list得到不同数据库数据,当我们启动服务注册中心7001,7002,7003,再启动80客户端,这个时候访问localhost/consumer/dept/list,每次刷新就会得到不同数据库的数据。这就是Ribbon默认的轮询算法的负载均衡。

Ribbon核心组件IRule

Ribbon负载均衡算法

Ribbon默认提供的是轮询的负载均衡算法,完整了还有如下

RoundRobinRule 轮询
RandomRule 随机
AvaliabilityFilteringRule 会先过滤由于多次访问故障而处于断路器跳闸的状态的服务和并发的连接数量超过阈值的服务,然后对剩余的服务列表按照轮询策略
WeightedResponseTimeRule 根据平均响应时间计算所有服务的权重,响应时间越快服务权重越大
RetryRule 先按照RoundRobinRule策略获取服务,如果获取服务失败会在指定时间内重试
BestAvailableRule 会先过滤掉由于多次访问故障二处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
ZoneAvoidanceRule 默认规则,复合判断server所在的区域的性能和server的可用性选择服务器

Ribbon负载均衡算法使用方法

在客户端的配置类ConfigBean.java中添加IRule的实现

@Configuration
public class ConfigBean {
    @Bean
    @LoadBalanced
    public RestTemplate geRestTemplate(){
        return new RestTemplate();
    }
    @Bean
    public IRule myRule(){
        return new RandomRule();
    }
}

Ribbon自定义

如果不使用Ribbon默认的七种负载均衡算法,这个时候就需要使用自定义负载均衡算法

客户端主启动类使用注解@RibbonClient

@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name="MICROSERVICECLOUD-DEPT",configuration=MySelfRule.class)
public class DeptConsumer80_App {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumer80_App.class, args);
    }
}

特此说明

RibbonClient注解中的MySelfRule类使我们自定义负载均衡算法的类,但是,这个自定义配置类不能放在@ComponentScan所扫描的当前包下以及子包下,否则我们这个自定义的配置类会被所有的Ribbon客户端所共享,也就说,达不到我们特殊化定制的目的。举例说明,自定义配置类不能放在项目主启动类所有的包以及子包下,因为主启动类使用注解@SpringBootApplication,这个注解点进去使用@ComponentScan注解

自定义负载均衡算法

轮询算法中每一个服务轮询一次,现在需求是每一个服务调用五次后在轮询下一个服务

自定义配置类

package com.luo.myrule;

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

@Configuration
public class MySelfRule {
    @Bean
    public IRule myRule(){
        return new RandomRule_lky();
    }
}

自定义算法类

package com.luo.myrule;

import java.util.List;

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

public class RandomRule_lky extends AbstractLoadBalancerRule{
    // total = 0 // 当total==5以后,我们指针才能往下走,
    // index = 0 // 当前对外提供服务的服务器地址,
    // total需要重新置为零,但是已经达到过一个5次,我们的index = 1
    // 分析:我们5次,但是微服务只有8001 8002 8003 三台,OK?
    private int total = 0;          // 总共被调用的次数,目前要求每台被调用5次
    private int currentIndex = 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;
            }
//          private int total = 0;          // 总共被调用的次数,目前要求每台被调用5次
//          private int currentIndex = 0;   // 当前提供服务的机器号
            if(total < 5)
            {
                server = upList.get(currentIndex);
                total++;
            }else {
                total = 0;
                currentIndex++;
                if(currentIndex >= upList.size())
                {
                  currentIndex = 0;
                }
            }           
            if (server == null) {
                Thread.yield();
                continue;
            }
            if (server.isAlive()) {
                return (server);
            }
            server = null;
            Thread.yield();
        }
        return server;
    }
    @Override
    public Server choose(Object key){
        return choose(getLoadBalancer(), key);
    }
    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig){}
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,757评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,478评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,540评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,593评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,903评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,329评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,659评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,383评论 0 195
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,055评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,337评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,864评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,227评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,820评论 3 231
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,999评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,750评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,365评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,260评论 2 258

推荐阅读更多精彩内容