首先,我們來說一個概念,什麼叫做
負載均衡
負載均衡 ,指的是利用特定方式将流量分攤到多個操作單元的一種手段,對整個系統的吞吐量和處理能力有極大的提升
目前有軟負載與硬負載之分,例如 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
- 也可以通過把項目打成 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 在我們沒有設定的情況下,使用的是輪詢的政策
至于輪詢是個很簡單負載均衡政策,實作起來隻需要在消費端拿到執行個體清單,然後利用取餘或者取模就可以達到輪詢的目的