首先,我们来说一个概念,什么叫做
负载均衡
负载均衡 ,指的是利用特定方式将流量分摊到多个操作单元的一种手段,对整个系统的吞吐量和处理能力有极大的提升
目前有软负载与硬负载之分,例如 nginx 和 F5
有客户端负载均衡和服务端负载均衡之分, 如 ribbon 和 nginx
客户端负载均衡是指,从实例库中选取一个实例进行流量导入
在微服务中,实例库一般存储在 Eureka .Consul,Zookeeper等 这样的注册中心,此时客户端负载局衡器如RIbbon等IPC组件
客户端负载均衡
讲了这么多负载均衡,我们来看一个简单的
入门案例
为了测试Ribbon的负载均衡功能,需要有一个服务提供者,并且开启多个实例
在每个实例中需要有一个标识来识别每次的调用是否打到了不同的实例上
这里使用同一份代码,使用不同的端口启动来模拟多个实例
由于服务都要注册到注册中心,我们需要先
创建一个注册中心
这里不再赘述了
创建一个提供服务的 service-provider
- 添加eureka注册客户端
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
- 在启动主类上开启注册的注解,都是相同的套路
@SpringBootApplication
@EnableDiscoveryClient
public class ServiceProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceProviderApplication.class, args);
}
}
application.yml
我们配置如下内容
server:
port: 8080
spring:
application:
name: service
eureka:
client:
service-url:
defaultZone: http://localhost:8762/eureka/
instance:
prefer-ip-address: true
默认情况下eureka 注册会以实例名注册,这里通过eureka.instance.prefer-ip-address: true
来保证 Eureka Server 相互注册时 hostname 使用 IP 地址,同时使用 IP 地址作为eureka.client.service-url.defaultZone
的配置值。
还一个注意的点是这里注册中心的端口改成了 8762
- 然后再添加一个controller 用于测试
/**
*@Description
*@author apdoer
*@CreateDate 2019/5/22-23:17
*@Version 1.0
*===============================
**/
@RestController
public class DemoController {
@GetMapping("/demo")
public String demo(Integer a, Integer b, HttpServletRequest request){
return "访问到==>"+ request.getServerPort()+"端口的实例";
}
}
很简单,没什么好说的,接下来我们把服务分别以8080,8081,8082 启动,这里启动的方式有很多种
- 你可以打开Edit Configuration,把single instance only去掉,在jvm那一栏指定 -Dserverport=8080
当然这一步也很重要- 点击左上角的加号,选中compound 然后把刚才几个命令加进来,去个名字,apply
- 点击左上角的加号,选中compound 然后把刚才几个命令加进来,去个名字,apply
- 也可以通过把项目打成 jar 包,通过java --jar来指定端口执行,这样的话就要提供三份不同的配置文件用于指定,这里用工具提供的,
可以看到,服务实例已经启动了三个
接下来我们创建服务消费方
创建server-consumer
一样的套路,引入eureka client依赖,这里用到 ribbon 所有再引入ribbon 依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.apdoer</groupId>
<artifactId>service-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>service-consumer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- 启动主类开启eureka 客户端注册,ribbon呢,这里是没有的
- 配置文件我们这样配,没啥好说了,常规套路
server:
port: 8888
spring:
application:
name: service-consumer
eureka:
client:
service-url:
defaultZone: http://localhost:8762/eureka/
instance:
prefer-ip-address: true
- 接下来我们创建一个应用负载均衡的RestTemplate,可以在类上用@Configuration,来托管bean,也可以直接写在启动主类
@SpringBootApplication
@EnableDiscoveryClient
public class ServiceConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceConsumerApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
- 创建一个controller 注入restTemplate,并进行调用
/**
*@Description
*@author apdoer
*@CreateDate 2019/5/23-0:03
*@Version 1.0
*===============================
**/
@RestController
public class TestControlller {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/test")
public String hello(){
return restTemplate.getForObject("http://service-provider/demo",String.class);
}
}
这里一切从简,介绍的是ribbon ,至于RestTemplate的详解,在别的地方专门有说到
结果
访问localhost:8888/test,连续刷新,我们可以看到
交替出现
总结
本文主要讲了以下几点
ribbon springcloud提供的一种客户端负载均衡器
ribbon的工作方式是,从注册中心拉取服务实例列表,通过客户端负载均衡策略,访问请求打到具体的服务实例上,ribbon 提供了多种的负载均衡策略和自定义配置
ribbon 在我们没有设置的情况下,使用的是轮询的策略
至于轮询是个很简单负载均衡策略,实现起来只需要在消费端拿到实例列表,然后利用取余或者取模就可以达到轮询的目的