springcloud-Ribbon 基于客服端的负载均衡工具(四)


概念

Ribbon是什么?

  • Spring Cloud Ribbon 是基于Netflix Ribbon 实现的一套客户端负载均衡的工具。
  • 简单的说,Ribbon 是 Netflix 发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将 Netflix 的中间层服务连接在一起。
  • Ribbon 的客户端组件提供一系列完整的配置项,如:连接超时、重试等。简单的说,就是在配置文件中列出 LoadBalancer (简称LB:负载均衡) 后面所有的及其,Ribbon 会自动的帮助你基于某种规则 (如简单轮询,随机连接等等) 去连接这些机器。我们也容易使用 Ribbon 实现自定义的负载均衡算法!

Ribbon能干嘛?

ribbon

  • LB,即负载均衡 (LoadBalancer) ,在微服务或分布式集群中经常用的一种应用。
  • 负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA (高用)。
  • 常见的负载均衡软件有 Nginx、Lvs 等等。
  • Dubbo、SpringCloud 中均给我们提供了负载均衡,SpringCloud 的负载均衡算法可以自定义。
  • 负载均衡简单分类:
    1. 集中式LB
      即在服务的提供方和消费方之间使用独立的LB设施,如Nginx(反向代理服务器),由该设施负责把访问请求通过某种策略转发至服务的提供方!
    2. 进程式 LB
      将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选出一个合适的服务器。
  • Ribbon 就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址!

集成Ribbon

通过简单的整合eureka和Ribbon,客服端通过微服务名称就可以调用服务

Eureka

为了测试简单我们使用单个Eureka,不使用Eureka集群。详细配置见

Provider

provider模块的代码见

修改consumer

consumer模块其它详细代码见

  1. pom.xml

     org.springframework.cloud
     spring-cloud-starter-eureka
     1.4.6.RELEASE
 
 
     org.springframework.cloud
     spring-cloud-starter-ribbon
     1.4.6.RELEASE
 
  1. application.yml
eureka:
  client:
    register-with-eureka: false # 不向 Eureka注册自己
    service-url:
      defaultZone: http://localhost:7001/eureka/
  instance:
    instance-id: consumer #用于修改eureka中实例的status描述(不写eureka会提供默认的描述)
  1. config @LoadBalanced
package com.dong.consumer.config;

@Configuration
//@Configuration ... 相当于spring中的配置文件 applicationContext.xml文件
public class ConfigBean {
    @Bean
    @LoadBalanced //配置负载均衡实现RestTemplate
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}
  1. 主启动类 @EnableEurekaClient
package com.dong.consumer;

@SpringBootApplication
@EnableEurekaClient
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
}
  1. controller 修改访问前缀
//Ribbon:我们这里的地址,应该是一个变量,通过服务名来访问
//private static final String REST_URL_PREFIX = "http://localhost:8001";
private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";

ribbon调用

  1. 测试 因为端口是80默认端口,所以可以省略端口号进行访问
访问:http://localhost/consumer/dept/get/2
结果:{"deptno":2,"dname":"人事部","db_source":null}

访问:http://localhost/consumer/dept/list
结果:略(可以访问到全部数据)

负载均衡

数据库

新建两个数据库springcloud1和springcloud2。数据库中的表的创建语句和springcloud数据库一样

CREATE TABLE `dept` (
	`deptno` BIGINT NOT NULL AUTO_INCREMENT COMMENT '部门编号',
	`dname` VARCHAR(60) NOT NULL COMMENT '部门名字',
	`db_source` VARCHAR(60) NOT NULL COMMENT '数据库名字',
	PRIMARY KEY (`deptno`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
	
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());

springcloud-provider-8001

具体代码:见上面

下面两个提供者和springcloud-provider-8001大致内容一样,让其连接的数据库不一样,分别连接创建的三个数据库。

实现负载均衡的条件就是provider注册到eureka的服务名称要一样

springcloud-provider-8002

  1. pom.xml
 
        
            org.springframework.boot
            spring-boot-starter-actuator
        
        
            org.springframework.cloud
            spring-cloud-starter-eureka
            1.4.6.RELEASE
        
        
        
            com.dong
            springcloud-common
            1.0-SNAPSHOT
        
        
        
            junit
            junit
        
        
            mysql
            mysql-connector-java
        
        
            com.alibaba
            druid
        
        
        
            ch.qos.logback
            logback-core
        
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
        
        
        
            org.springframework.boot
            spring-boot-test
        
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
        
            org.springframework.boot
            spring-boot-starter-jetty
        
        
        
            org.springframework.boot
            spring-boot-devtools
        
   
  1. application
server:
  port: 8002

#mybatis配置
mybatis:
  configuration:
    #开启驼峰命名
    map-underscore-to-camel-case: true
  type-aliases-package: com.dong.common.pojo
  mapper-locations: classpath:mapper/*.xml

#spring的配置
spring:
  application:
    name: springcloud-provider-dept
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource  #数据源
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springcloud2?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&allowMultiQueries=true
    username: root
    password: 123456

logging:
  level:
    com.dong.provider.dao: debug

# Eureka配置:配置服务注册中心地址
eureka:
  client:
    service-url:
      #defaultZone: http://localhost:7001/eureka/
      # 然而现在服务发布要发布到3个注册中心上面去
      defaultZone: http://localhost:7001/eureka/
  instance:
    instance-id: springcloud-provider2 #修改Eureka上的默认描述信息

# info配置
info:
  # 项目的名称
  app.name: springcloud
  # 公司的名称
  company.name: 狂神说
  1. 启动类
package com.dong.provider2;

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

  1. 其余代码和springcloud-provider-8001一样,只需要修改一些路径即可

springcloud-provider-8003

  1. pom.xml 和springcloud-provider-8002一样
  2. application 和 springcloud-provider-8002一样,只改url连接的数据库名称为springcloud3,instance-id和端口号
 server:
  port: 8003
 
 url: jdbc:mysql://localhost:3306/springcloud2?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&allowMultiQueries=true
 
# Eureka配置:配置服务注册中心地址
eureka:
  client:
    service-url:
      #defaultZone: http://localhost:7001/eureka/
      # 然而现在服务发布要发布到3个注册中心上面去
      defaultZone: http://localhost:7001/eureka/
  instance:
    instance-id: springcloud-provider3 #修改Eureka上的默认描述信息
  1. 启动类
package com.dong.provider3;

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

  1. 其余代码和springcloud-provider-8001一样,只需要修改一些路径即可

注意

consumer也使用上面的代码 三个provider微服务名称都是SPRINGCLOUD-PROVIDER-DEPT,所以通过下面代码结合ribbon才能实现负载均衡的功能

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

Eureka使用的是7001,我又将它改为了单Eeureka,hostname改为localhost,前面集群案例修改过这个值。

instance:
    hostname: localhost

启动三个provider,Eureka和consumer进行测试

consumer ,Eureka

测试

输入:http://localhost:7001/

负载均衡注册

输入:http://localhost/consumer/dept/list 多次访问

第一次:
[{"deptno":1,"dname":"开发部","dbSource":"springcloud"},{"deptno":2,"dname":"人事部","dbSource":"springcloud"},{"deptno":3,"dname":"财务部","dbSource":"springcloud"},{"deptno":4,"dname":"市场部","dbSource":"springcloud"},{"deptno":5,"dname":"运维部","dbSource":"springcloud"},{"deptno":6,"dname":"“管理部”","dbSource":"springcloud"},{"deptno":7,"dname":"销售部","dbSource":"springcloud"}]

第二次:
[{"deptno":1,"dname":"开发部","dbSource":"springcloud2"},{"deptno":2,"dname":"人事部","dbSource":"springcloud2"},{"deptno":3,"dname":"财务部","dbSource":"springcloud2"},{"deptno":4,"dname":"市场部","dbSource":"springcloud2"},{"deptno":5,"dname":"运维部","dbSource":"springcloud2"}]

第三次:
[{"deptno":1,"dname":"开发部","dbSource":"springcloud3"},{"deptno":2,"dname":"人事部","dbSource":"springcloud3"},{"deptno":3,"dname":"财务部","dbSource":"springcloud3"},{"deptno":4,"dname":"市场部","dbSource":"springcloud3"},{"deptno":5,"dname":"运维部","dbSource":"springcloud3"}]

我们发现上面三次访问结果依此是从数据库springcloud,springcloud2和springcloud3中读取到的数据。说明通过ribbon实现负载均衡已经成功。且ribbon默认是通过轮询的方式实现负载均衡的。

参考教程:https://www.kuangstudy.com/