springcloud-Ribbon 基于客服端的负载均衡工具(四)
概念
Ribbon是什么?
- Spring Cloud Ribbon 是基于Netflix Ribbon 实现的一套客户端负载均衡的工具。
- 简单的说,Ribbon 是 Netflix 发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将 Netflix 的中间层服务连接在一起。
- Ribbon 的客户端组件提供一系列完整的配置项,如:连接超时、重试等。简单的说,就是在配置文件中列出 LoadBalancer (简称LB:负载均衡) 后面所有的及其,Ribbon 会自动的帮助你基于某种规则 (如简单轮询,随机连接等等) 去连接这些机器。我们也容易使用 Ribbon 实现自定义的负载均衡算法!
Ribbon能干嘛?
- LB,即负载均衡 (LoadBalancer) ,在微服务或分布式集群中经常用的一种应用。
- 负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA (高用)。
- 常见的负载均衡软件有 Nginx、Lvs 等等。
- Dubbo、SpringCloud 中均给我们提供了负载均衡,SpringCloud 的负载均衡算法可以自定义。
- 负载均衡简单分类:
- 集中式LB
即在服务的提供方和消费方之间使用独立的LB设施,如Nginx(反向代理服务器),由该设施负责把访问请求通过某种策略转发至服务的提供方! - 进程式 LB
将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选出一个合适的服务器。
- 集中式LB
- Ribbon 就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址!
集成Ribbon
通过简单的整合eureka和Ribbon,客服端通过微服务名称就可以调用服务
Eureka
为了测试简单我们使用单个Eureka,不使用Eureka集群。详细配置见
Provider
provider模块的代码见
修改consumer
consumer模块其它详细代码见
- pom.xml
org.springframework.cloud
spring-cloud-starter-eureka
1.4.6.RELEASE
org.springframework.cloud
spring-cloud-starter-ribbon
1.4.6.RELEASE
- application.yml
eureka:
client:
register-with-eureka: false # 不向 Eureka注册自己
service-url:
defaultZone: http://localhost:7001/eureka/
instance:
instance-id: consumer #用于修改eureka中实例的status描述(不写eureka会提供默认的描述)
- config @LoadBalanced
package com.dong.consumer.config;
@Configuration
//@Configuration ... 相当于spring中的配置文件 applicationContext.xml文件
public class ConfigBean {
@Bean
@LoadBalanced //配置负载均衡实现RestTemplate
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
- 主启动类 @EnableEurekaClient
package com.dong.consumer;
@SpringBootApplication
@EnableEurekaClient
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
- controller 修改访问前缀
//Ribbon:我们这里的地址,应该是一个变量,通过服务名来访问
//private static final String REST_URL_PREFIX = "http://localhost:8001";
private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";
- 测试 因为端口是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
- 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
- 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: 狂神说
- 启动类
package com.dong.provider2;
@SpringBootApplication
@EnableEurekaClient
public class ProviderTwoApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderTwoApplication.class, args);
}
}
- 其余代码和springcloud-provider-8001一样,只需要修改一些路径即可
springcloud-provider-8003
- pom.xml 和springcloud-provider-8002一样
- 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上的默认描述信息
- 启动类
package com.dong.provider3;
@SpringBootApplication
@EnableEurekaClient
public class ProviderThreeApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderThreeApplication.class, args);
}
}
- 其余代码和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/