SpringCloud微服务框架Ribbon负载均衡

园码生活

共 14248字,需浏览 29分钟

 · 2021-04-03

Ribbon相关概念

它是基于实现一套客户端的负载均衡工具

官方资料

Ribbon初步配置

在microservicecloud-consumer-dept-8080添加pom依赖

 <!-- 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>

修改config类 添加 @LoadBalanced注解

package com.yang.springcloud.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;

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

在启动类添加  @EnableEurekaClient注解

package com.yang.springcloud;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;


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

修改controller层,添加 private static final String REST_URL_PREFIX = "http://MICROSERVICECLOUD-DEPT";

package com.yang.springcloud.controller;


import com.yang.entity.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController
public class DeptController_Consumer {

//    private static final String REST_URL_PREFIX = "http://localhost:8001";
private static final String REST_URL_PREFIX = "http://MICROSERVICECLOUD-DEPT";
    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping(value="/consumer/dept/add")
    public boolean add(Dept dept)
    
{
        return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add", dept, Boolean.class);
    }

    @RequestMapping(value="/consumer/dept/get/{id}")
    public Dept get(@PathVariable("id") Long id)
    
{
        return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id, Dept.class);
    }

    @SuppressWarnings("unchecked")
    @RequestMapping(value="/consumer/dept/list")
    public List<Dept> list()
    
{
        return restTemplate.getForObject(REST_URL_PREFIX+"/dept/list", List.class);
    }

}

Ribbon负载均衡

参考microservicecloud-provider-dept-8001,新建两份,分别命名为8002,8003 数据库脚本

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());
 
SELECT * FROM dept;

新建8002/8003数据库,各自微服务分别连各自的数据库

server:
  port: 8002
  
mybatis:
  config-location: classpath:mybatis/mybatis.cfg.xml        # mybatis配置文件所在路径
  type-aliases-package: com.yang.entity    # 所有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: root
    dbcp2:
      min-idle: 5                                           # 数据库连接池的最小维持连接数
      initial-size: 5                                       # 初始化连接数
      max-total: 5                                          # 最大连接数
      max-wait-millis: 200                                  # 等待连接获取的最大超时时间

eureka:
  client: #客户端注册进eureka服务列表内
    service-url: 
#      defaultZone: http://localhost:7001/eureka
       defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: microservicecloud-dept8002
    prefer-ip-address: true     #访问路径可以显示IP地址     
 
info: 
  app.name: atguigu-microservicecloud
  company.name: www.atguigu.com
  build.artifactId: $project.artifactId$
  build.version: $project.version$

自定义轮询



import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RoundRobinRule;

@Configuration
public class MySelfRule
{
 @Bean
 public IRule myRule()
 
{
  //return new RandomRule();// Ribbon默认是轮询,我自定义为随机
  //return new RoundRobinRule();// Ribbon默认是轮询,我自定义为随机
  
  return new RandomRule_ZY();// 我自定义为每台机器5次
 }
}

自定义轮询算法

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_ZY 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) {
    /*
     * No servers. End regardless of pass, because subsequent passes only get more
     * restrictive.
     */

    return null;
   }

//   int index = rand.nextInt(serverCount);// java.util.Random().nextInt(3);
//   server = upList.get(index);

   
//   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) {
    /*
     * 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 clientConfig)
 
{
  // TODO Auto-generated method stub

 }

}


   

如果你觉得这篇内容对你挺有启发,我想邀请你帮我三个小忙:

  • 点个【在看】,或者分享转发,让更多的人也能看到这篇内容

  • 关注公众号【园码生活】,不定期分享原创&精品技术文章。

  • 公众号内回复:【 1 】。加我的微信。


欢迎评论区留下你的精彩评论~          
         

觉得文章不错可以分享到朋友圈让更多的小伙伴看到哦~

客官!在看一下呗          


浏览 12
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报