什么是Ribbon?

Ribbon是一个客户端的负载均衡。

我举个例子就明白了,我去超市买东西付钱,收银台有3个,一个收银台有10个人排队,一个收银台有5个人排队,一个收银台有2个人排队。只要我不是傻子,我就知道我该去2个人排队的那个收银台。

我是客户,我知道选择人最少的收银台。这就是客户端的负载均衡。这就是Ribbon

提一句,负载均衡有两种方式:

  1. 集中式:这个就是有一个硬件,比如F5,提供者和消费者之间通过硬件负载均衡,缺点是硬件一般都很贵
  2. 进程内:这个是软件的形式,把负载均衡的逻辑放到消费方,让消费方根据逻辑去选择一台合适的服务器。

Ribbon的配置

Maven引入

由于Ribbon是客户端的负载均衡,我们在consumer项目里面引入Maven配置

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

开启注解

注解这有两个地方需要标注,我们的consumer是使用restTemplate来访问的,在获取restTemplate的方法上开启负载均衡注解,@LoadBalanced

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

顺便,consumer里面的Controller里面,访问的地址我们原来写的是localhost,既然是微服务,我们肯定使用服务名称了,改一下

//    private static final String REST_URL_PREFIX="http://localhost:8001";
private static final String REST_URL_PREFIX="http://PROVIDER-DEPT";

第二个注解就是主方法那里,加一个@EnableEurekaClient

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

再次重启启动eureka7001,eureka7002,eureka7003和provider,consumer,你会发现还是完全ok的。

Ribbon负载均衡

上面说了,Ribbon是客户端的负载均衡,所以我们要加在consumer项目上,Ribbon默认的负载均衡方式的轮询。我们可以新建两个provider来测试一下

新建provider8002和8003

新建项目就不多说了,记得把8001的yml,Mybatis,代码啥的复制过去。如下

server:
port: 8002 mybatis:
config-location: classpath:mybatis/mybatis.cfg.xml #mybatis配置文件所在路径
type-aliases-package: com.vae.springcloud.entity #所有Entity别名类所在包
mapper-locations: classpath:mybatis/mapper/**/*.xml #mapper映射文件 spring:
application:
name: provider-dept
datasource:
# type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/vae?serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123
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: provider-8002 #这个是修改Eureka界面的Status名称
prefer-ip-address: true #这个是设置鼠标放在status上的时候,出现的提示,设置ip地址显示 info:
app.name: provider-8001
company.name: www.vae.com
build.artifactId: $project.artifactId$
build.version: $project.version$
server:
port: 8003 mybatis:
config-location: classpath:mybatis/mybatis.cfg.xml #mybatis配置文件所在路径
type-aliases-package: com.vae.springcloud.entity #所有Entity别名类所在包
mapper-locations: classpath:mybatis/mapper/**/*.xml #mapper映射文件 spring:
application:
name: provider-dept
datasource:
# type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/jj?serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123
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: provider-8003 #这个是修改Eureka界面的Status名称
prefer-ip-address: true #这个是设置鼠标放在status上的时候,出现的提示,设置ip地址显示 info:
app.name: provider-8001
company.name: www.vae.com
build.artifactId: $project.artifactId$
build.version: $project.version$

看到没,yml文件,我只修改了端口号、数据库和instance-id状态id。因为每一个微服务都可以都一个独立的数据库,所以,三个provider的数据库我分别使用的是shuyunquan,vae,jj三个数据库,当然,表结构都是一样的没改

代码直接复制就行,没什么需要改的。

现在我们启动eureka7001,eureka7002,eureka7003,provider8001,provider8002,provider8003和consumer。算一下7个项目了,运行之后,你可以通过consumer访问试试,结果每次刷新都换了数据库,这刚好表明了Ribbon的默认负载均衡方式是轮询。

Ribbon核心组件IRule

Ribbon的核心组件IRule作用是定义以什么样的方式去负载均衡,比如轮询,比如随机。要想使用IRule,我们需要写一个类。

注意:IRule组件的类不能在有@ComponentScan组件的类的包以及子包下存在,主方法的@SpringBootApplication注解里面有@ComponentScan注解,所以,我们不能在主方法的所在包或者子包下新建IRule组件

我们在vae包下新建myrule包,包下新建MySelfRule类,代码如下:

package com.vae.myrule;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; @Configuration
public class MySelfRule { @Bean
public IRule myRule(){
return new RandomRule(); //这个是负载均衡的随机访问
// return new RoundRobinRule(); 这个是负载均衡的默认的轮询访问
}
}

看一下项目目录图

Ribbon自定义

上面讲的都太简单了,完全体现不出技术含量,所以Ribbon负载均衡的方式只有轮询和随机这还不够,我们要学会自定义负载均衡的方式,先看一张图

要想自定义Ribbon负载均衡,我们要自己写个类,首先要继承AbstractLoadBalancerRule这个类,然后剩下的代码嘛,你可以去Ribbon的官方GitHub看看,Ribbon官方随机代码,把这里面的方法复制出来,我们看看里面的内容都是啥,我们只摘取方法

package com.vae.myrule;

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server; import java.util.List;
import java.util.concurrent.ThreadLocalRandom; public class RandomRule extends AbstractLoadBalancerRule { public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
}
Server server = null; while (server == null) {
//线程是否中断,中断返回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 = chooseRandomInt(serverCount);
server = upList.get(index); 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; } protected int chooseRandomInt(int serverCount) {
return ThreadLocalRandom.current().nextInt(serverCount);
} @Override
public Server choose(Object key) {
return choose(getLoadBalancer(), key);
} @Override
public void initWithNiwsConfig(IClientConfig iClientConfig) { }
}

可以看到啊,大概就是这样子的,initWithNiwsConfig方法是我们继承了AbstractLoadBalancerRule实现的,上面的方法中,很容易看出choose方法才是真正有内容的,我们现在就可以对这个随机算法进行修改了,比如,我想修改为每个服务访问5次,然后再随机的访问下一个服务。肯定是修改choose方法了

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; }

可以看到,我就定义了两个变量,自定义算法这个是很主观的,你需要什么样的方式来负载均衡就自己改代码就好了。

SpringCloud笔记四:Ribbon的更多相关文章

  1. C#可扩展编程之MEF学习笔记(四):见证奇迹的时刻

    前面三篇讲了MEF的基础和基本到导入导出方法,下面就是见证MEF真正魅力所在的时刻.如果没有看过前面的文章,请到我的博客首页查看. 前面我们都是在一个项目中写了一个类来测试的,但实际开发中,我们往往要 ...

  2. 《MFC游戏开发》笔记四 键盘响应和鼠标响应:让人物动起来

    本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/9327377 作者:七十一雾央 新浪微博:http:// ...

  3. IOS学习笔记(四)之UITextField和UITextView控件学习

    IOS学习笔记(四)之UITextField和UITextView控件学习(博客地址:http://blog.csdn.net/developer_jiangqq) Author:hmjiangqq ...

  4. java之jvm学习笔记四(安全管理器)

    java之jvm学习笔记四(安全管理器) 前面已经简述了java的安全模型的两个组成部分(类装载器,class文件校验器),接下来学习的是java安全模型的另外一个重要组成部分安全管理器. 安全管理器 ...

  5. Java学习笔记四---打包成双击可运行的jar文件

    写笔记四前的脑回路是这样的: 前面的学习笔记二,提到3个环境变量,其中java_home好理解,就是jdk安装路径:classpath指向类文件的搜索路径:path指向可执行程序的搜索路径.这里的类文 ...

  6. Java加密与解密笔记(四) 高级应用

    术语列表: CA:证书颁发认证机构(Certificate Authority) PEM:隐私增强邮件(Privacy Enhanced Mail),是OpenSSL使用的一种密钥文件. PKI:公钥 ...

  7. SpringCloud学习之Ribbon

    一.负载均衡与Ribbon 负载均衡,在集群中是很常见的一个“名词”,顾名思义是根据一定的算法将请求分摊至对应的服务节点上,常见的算法有如下几种: 轮询法:所有请求被依次分发到每台应用服务器上,每台服 ...

  8. Learning ROS for Robotics Programming Second Edition学习笔记(四) indigo devices

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...

  9. Typescript 学习笔记四:回忆ES5 中的类

    中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...

随机推荐

  1. c/c++ 网络编程 bind函数

    网络编程 bind函数 bind的作用是确定端口号. 正常处理都是先bind,然后listen 如果不bind,直接listen,会是什么结果? 内核会自动随机分配一个端口号 例子: #include ...

  2. Python爬虫之pyquery库的基本使用

    # 字符串初始化 html = ''' <div> <ul> <li class = "item-0">first item</li> ...

  3. IDF-简单题目writeup

    1. 被改错的密码 原题: 从前有一个熊孩子入侵了一个网站的[数据库],找到了管理员密码,手一抖在[数据库]中修改了一下,现在的密码变成了ca9cc444e64c8116a30la00559c042b ...

  4. 《生命》第五集:Birds (鸟类)

    看了前四集之后意犹未尽,今天终于有时间来看第五集了. 本集讲的是鸟类,一个在恐龙开始繁荣的时代才开始有的物种. 鸟类和其他动物最不同的地方,就是羽毛,能隔热,保暖,最重要的是:能帮助他们飞行. 在秘鲁 ...

  5. 【Linux基础】查看硬件信息-硬盘

     一.基础知识 1.磁盘分区 磁盘的分区主要分为基本分区(primary partion)和扩充分区(extension partion)两种,基本分区和扩充分区的数目之和不能大于四个.且基本分区可以 ...

  6. Redis学习笔记(5)——Redis数据持久化

    出处http://www.cnblogs.com/xiaoxi/p/7065328.html 一.概述 Redis的强大性能很大程度上都是因为所有数据都是存储在内存中的,然而当Redis重启后,所有存 ...

  7. LCA-RMQ+欧拉序

    还是那一道洛谷的板子题来说吧 传送门 其实好几天之前就写了 结果dr实在是太弱了 没有那么多的精力 于是就一直咕咕咕了 哎 今天终于补上来了 LCA概念传送门 RMQ传送门 这个算法是基于RMQ和欧拉 ...

  8. Android/Linux Thermal框架分析及其Governor对比

    图表 1 Thermal框架 随着SoC性能的快速提升,功耗也极大提高,带来的负面影响是SoC的温度提高很快,甚至有可能造成物理损坏.同时功耗浪费也降低了电池寿命. 从上图可知,Thermal框架可以 ...

  9. python处理Windows平台上路径有空格

    最近在采集windows上中间件的时候,遇到了文件路径有空格的问题. 例如:Aapche的安装路径为D:\Program Files\Apache Software Foundation\Apache ...

  10. [2019BUAA软工助教]第0次个人作业

    [2019BUAA软工助教]第0次个人作业 一.前言 我认为人生就是一次次地从<存在>到<光明>. 二.软件工程师的成长 博客索引 同学们在上这门课的时候基本都是大三,觉得在大 ...