简介
什么是负载均衡
负载均衡是高可用网络基础架构的关键组件,通常用于将工作负载分布到多个服务器来提高网站、应用、数据库或其他服务的性能和可靠性。
一个没有负载均衡的 web 架构类似下面这样:
上述图例中,用户通过网络访问 Web 服务器,如果服务器宕机了,那么整个系统都无法使用。另外如果有很多用户同时访问该服务器,由于服务器的性能有限,用户可能会遇到加载缓慢或根本无法连接的情况。
如果此时在后端增加一个负载均衡器和至少一个额外的 Web 服务器,则可以缓解该故障。一般来说,后端服务器会采用 A(一致性) 原则,提供相同的数据内容,以便于用户无论访问到哪台服务器得到一致的数据。
如上图所示,多台服务器提供服务,用户发送请求到负载均衡器,经由负载均衡器转发给任一服务器,这样加大了系统的负载能力,还提升了性能。
负载均衡的分类
目前业界主流的负载均衡方案可分为两类:
集中式负载均衡:即在 consumer 和 provider 中间使用独立的负载均衡设施(可以是硬件,如F5,也可以是软件,如:Nginx),由该设施把访问请求通过某种策略转发到 provider。
进程内负载均衡:将负载均衡的逻辑集成到 consumer,consumer 从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择一个合适的 provider。
关于负载均衡分类想要深入了解的同学,可以参考负载均衡技术原理及分类
Ribbon 属于后者,它只是一个类库,集成在 consumer 中,consumer 通过它来获得合适的 provider 地址。
两种负载均衡方式架构图
Ribbon
Spring Cloud Ribbon 是一个基于 Http 和 TCP 的客户端负载均衡工具,它是基于Netflix Ribbon实现的。它不像服务注册中心、配置中心、API 网关那样独立部署,但是它几乎存在于每个微服务的基础设施中。理解 Ribbon 对于我们使用 Spring Cloud 来讲非常的重要,因为负载均衡是对系统的高可用、网络压力的缓解和处理能力扩容的重要手段之一。
Ribbon 可以基于某种负载均衡算法,如轮询(默认)、随机、加权轮询、加权随机等自动帮助服务消费者调用接口, 甚至包含自定义的负载均衡算法。
在 Spring Cloud 中,有两种服务调用方式,一种是 Ribbon+RestTemplate,另一种是 Feign。
当 Ribbon 与 Eureka 配合使用时,Ribbon 可自动从 Eureka Server 获取服务提供者地址列表,并基于负载均衡算法,请求其中一个服务提供者实例。
实现
我们继续复用前两节讲到的项目,在此基础上进行扩展,首先我们回忆一下之前的项目。
父模块:
- springcloud-api:【封装的实体类接口】
- springcloud-provider-dept-8001:【服务提供者】
- springcloud-consumer-dept-80:【服务消费者】
- springcloud-config-eureka-7001:【服务注册中心7001】
- springcloud-config-eureka-7002:【服务注册中心7002】
- springcloud-config-eureka-7003:【服务注册中心7003】
单个服务提供者
接下来我们针对 springcloud-consumer-dept-80 项目进行修改。
1、导入依赖
<!--ribbon依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> <version>1.4.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.4.6.RELEASE</version> </dependency> 复制代码
2、修改 application.yml
server: port: 80 #eureka配置 eureka: client: register-with-eureka: false service-url: defaultZone: http://eureka7001:7001/eureka/,http://eureka7002:7002/eureka/,http://eureka7003:7003/eureka/ 复制代码
3、配置负载均衡
@Configuration public class MyConfig { //配置负载均衡实现RestTemplate @Bean @LoadBalanced public RestTemplate getRestTemplate(){ return new RestTemplate(); } } 复制代码
4、修改 DeptConsumerController 文件中的服务调用名称
// private static final String REST_URL_PREFIX = "http://localhost:8001"; //通过服务名进行调用 private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT"; 复制代码
上述代码中的 SPRINGCLOUD-PROVIDER-DEPT 为服务提供者在注册中心注册的名称,如下图所示:
5、入口类上增加注解@EnableEurekaClient
@SpringBootApplication @EnableEurekaClient public class DeptConsumer_80 { public static void main(String[] args) { SpringApplication.run(DeptConsumer_80.class,args); } } 复制代码
6、启动3个服务注册中心项目,以及服务提供者和服务消费者,访问 http://localhost/consumer/dept/list,页面正常显示数据。
多个服务提供者
新建两个数据库,分别为 db01 和 db02,以及同样的 dept 表,SQL 语句如下:
CREATE DATABASE `db01`; USE `db01`; CREATE TABLE `dept` ( `deptId` bigint(20) NOT NULL AUTO_INCREMENT, `dpName` varchar(60) NOT NULL, `dbSource` varchar(60) NOT NULL, PRIMARY KEY (`deptId`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; insert into dept (dpname, dbsource) values ('开发部',DATABASE()); insert into dept (dpname, dbsource) values ('人事部',DATABASE()); insert into dept (dpname, dbsource) values ('财务部',DATABASE()); insert into dept (dpname, dbsource) values ('市场部',DATABASE()); insert into dept (dpname, dbsource) values ('后勤部',DATABASE()); 复制代码
数据库建立完毕,我们再来新建两个服务提供者,复制 springcloud-provider-dept-8001 项目,修改名称为 springcloud-provider-dept-8002 和 springcloud-provider-dept-8003,注意修改项目中配置文件、入口类和 mapper 映射文件。
每个服务提供者对应连接一个数据库,示例如下:
server: port: 8002 spring: datasource: username: root password: mysql521695 url: jdbc:mysql://localhost:3306/db01?useUnicode=true&useSSL=true&serverTimezone=UTC&characterEncoding=utf-8 type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver application: name: springcloud-provider-dept mybatis: type-aliases-package: com.msdn.pojo mapper-locations: classpath:mybatis/mapper/*.xml #Eureka配置 eureka: client: service-url: defaultZone: http://eureka7001:7001/eureka/,http://eureka7002:7002/eureka/,http://eureka7003:7003/eureka/ instance: instance-id: springcloud-provider-dept-8002 # 修改eureka上的默认描述信息 prefer-ip-address: true # true,可以显示服务的IP地址 #info配置 info: app.name: hresh-springcloud company.name: blog.csdn.net/Herishwater 复制代码
目前项目结构如下:
启动3个注册中心,3个服务提供者,最后启动服务消费者,首先访问 http://eureka7001:7001/,页面内容如下:
然后再访问 http://localhost/consumer/dept/list,不断刷新该页面,可以看到查询到的数据在变化。