前言
通常我們如果有一個服務,會部署到多臺服務器上,這些微服務如果都暴露給客戶,是非常難以管理的,我們系統需要有一個唯一的出口,Spring Cloud Gateway 網關是一個服務,是系統的唯一出口。Spring Cloud Gateway 網關封裝了系統內部的微服務,爲客戶端提供一個定製的API。客戶端只需要調用網關接口,就可以調用到實際的微服務,實際的服務對客戶不可見,並且容易擴展服務。
Spring Cloud Gateway 網關可以結合Ribbon完成負載均衡的功能,可以自動檢查微服務的狀況,及時剔除或者加入某個微服務到可用服務列表。此外Spring Cloud Gateway 網關可以完成權限檢查、限流、統計等功能。下面我們將一一完成上面的功能。注意微服務只是提供rest的接口,不會有額外的組件依賴,不需要eureka等。只需要兩個工程,一個是微服務,我們可以部署到多臺服務器,那麼只是訪問的ip不同,在演示的時候,我們在本機演示,修改端口,達到啓動多個微服務的目的,另一個就是網關,主要是 Spring Cloud Gateway 和 Ribbon兩大組件來實現網關和負載均衡等功能。
1、構建兩個工程
這裏不再介紹如何構建兩個微服務步驟,請自行構建,我建立微服務於情況如下:
1.1、搭建兩個微服務,端口爲8072、8073
1.2、在controller控制層編寫測試接口
1.2、訪問地址
2、構建網關微服務
請自行構建網關微服務,我構建的網關微服務名字:esb-gateway,可以使用:https://start.spring.io/
2.1、修改pom.xml文件
<?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 https://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.3.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.modules.scistor</groupId>
<artifactId>esb-gateway</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>esb-gateway</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 網關gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 負載ribbon -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</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>
<!--添加配置跳過測試-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.2、修改application.yml文件
server:
port: 8070
spring:
cloud:
gateway:
# 跨域配置
globalcors:
cors-configurations:
'[/**]':
allowedOrigins: "*"
allowedMethods:
- GET
- POST
- PUT
- DELETE
- OPTIONS
# 路由負載配置
default-filters:
routes:
- id: my_route
uri: lb://load-balanced-service
predicates:
- Path=/crs/**
filters:
- StripPrefix=1
load-balanced-service:
ribbon:
# 負載地址
listOfServers: http://localhost:8072, http://localhost:8073
# 負載輪詢策略
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
# 健康檢查
NFLoadBalancerPingClassName: com.modules.scistor.config.HealthExamination
注意:
listOfServers:配置的微服務的服務器ip端口,多個用,隔開配置。
NFLoadBalancerRuleClassName:使用的負載均衡策略。
負載均衡策略介紹
RoundRobinRule:簡單輪詢服務列表來選擇服務器。它是Ribbon默認的負載均衡規則。
AvailabilityFilteringRule:對以下兩種服務器進行忽略:
(1)在默認情況下,這臺服務器如果3次連接失敗,這臺服務器就會被設置爲“短路”狀態。短路狀態將持續30秒,如果再次連接失敗,短路的持續時間就會幾何級地增加。
注意:可以通過修改配置loadbalancer.<clientName>.connectionFailureCountThreshold來修改連接失敗多少次之後被設置爲短路狀態。默認是3次。
(2)併發數過高的服務器。如果一個服務器的併發連接數過高,配置了AvailabilityFilteringRule規則的客戶端也會將其忽略。併發連接數的上線,可以由客戶端的<clientName>.<clientConfigNameSpace>.ActiveConnectionsLimit屬性進行配置
WeightedResponseTimeRule:爲每一個服務器賦予一個權重值。服務器響應時間越長,這個服務器的權重就越小。這個規則會隨機選擇服務器,這個權重值會影響服務器的選擇。
ZoneAvoidanceRule:以區域可用的服務器爲基礎進行服務器的選擇。使用Zone對服務器進行分類,這個Zone可以理解爲一個機房、一個機架等。
BestAvailableRule:忽略哪些短路的服務器,並選擇併發數較低的服務器。
RandomRule:隨機選擇一個可用的服務器。
Retry:重試機制的選擇邏輯
自定義負載均衡策略
可以自定義負載均衡算法。需求是:每個服務器訪問三次再跳轉到下一個服務器。
(1)負載均衡算法(參考RandomRule)
package com.modules.scistor.config;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import java.util.ArrayList;
import java.util.List;
public class MyRule extends AbstractLoadBalancerRule
{
private volatile int total;
private volatile int index;
List<Server> upList = new ArrayList<>();
public MyRule()
{
}
public Server choose(ILoadBalancer lb, Object key)
{
if (lb == null)
{
return null;
}
else
{
Server server = null;
while (server == null)
{
if (Thread.interrupted())
{
return null;
}
List<Server> allList = lb.getAllServers();
int serverCount = allList.size();
if (serverCount == 0)
{
return null;
}
if (total == 0)
{
upList = lb.getReachableServers();
}
if (total < 3)
{
if (upList.size() != lb.getReachableServers().size())
{
index = 0;
}
server = lb.getReachableServers().get(index);
total++;
}
else
{
total = 0;
index++;
if (index >= lb.getReachableServers().size())
{
index = 0;
}
}
if (server == null)
{
Thread.yield();
}
else
{
if (server.isAlive())
{
return server;
}
server = null;
Thread.yield();
}
}
return server;
}
}
public Server choose(Object key)
{
return this.choose(this.getLoadBalancer(), key);
}
public void initWithNiwsConfig(IClientConfig clientConfig)
{
}
}
(2)修改配置文件
2.3、測試
訪問 http://localhost:8070/crs/health
3、健康監測
3.1、新建一個Config類
package com.modules.scistor.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* @Auther: lc
* @Date: 2020/7/1 11:37
* @Description: 健康檢查配置類
*/
@Configuration
public class HealthConfig {
@Bean
public RestTemplate restTemplate()
{
return new RestTemplate();
}
}
3.2、新建一個健康檢查的類,調用heath接口
package com.modules.scistor.config;
import com.netflix.loadbalancer.IPing;
import com.netflix.loadbalancer.Server;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
/**
* @Auther: lc
* @Date: 2020/7/1 11:39
* @Description: 健康檢查實現
*/
public class HealthExamination implements IPing {
@Autowired
private RestTemplate restTemplate;
@Override
public boolean isAlive(Server server) {
String url = "http://" + server.getId() + "/health";
try
{
ResponseEntity<String> heath = restTemplate.getForEntity(url, String.class);
if (heath.getStatusCode() == HttpStatus.OK)
{
System.out.println("ping " + url + " success and response is " + heath.getBody());
return true;
}
System.out.println("ping " + url + " error and response is " + heath.getBody());
return false;
}
catch (Exception e)
{
System.out.println("ping " + url + " failed");
return false;
}
}
}
上面代碼繼承IPing接口,判斷服務是否可用。我們在微服務中增加heath接口,在gateway中調用該接口,如果返回正常則認爲微服務可用。
3.3、配置文件修改
3.4、項目結構
至此使用 Spring Cloud Gateway + Ribbon 負載均衡項目實戰結束,全文完。