1、gateway相關介紹
在微服務架構中,系統往往由多個微服務組成,而這些服務可能部署在不同機房、不同地區、不同域名下。這種情況下,使用者端(例如瀏覽器、手機、軟體工具等)想要直接請求這些服務,就需要知道它們具體的地址資訊,例如 IP 地址、埠號等。這種使用者端直接請求服務的方式存在很多的複雜問題。如:需要維護大量的服務地址、存在跨域請求的問題、每個微服務需要獨立認證等。所以我們可以通過 API 閘道器(gateway)來解決這些問題。所有使用者端請求都發生到閘道器,由閘道器統一轉發到不同的地址。閘道器還可以 處理一些非業務功能的邏輯,例如許可權驗證、監控、快取等。本篇主要講解通過閘道器統一請求轉發到不同微服務。
2、建立閘道器服務
首先建立maven專案新建閘道器模組:
pom匯入閘道器相關依賴:
<dependencies> <!--Eureka Client--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!--特別注意:在 gateway 閘道器服務中不能引入 spring-boot-starter-web 的依賴,否則會報錯--> <!-- Spring cloud gateway 閘道器依賴--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>
<!-- LoadBalancer -->
<!-- 引入spring-cloud-loadbalancer -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!--ribbon Spring Cloud Ribbon 在高版本移除了 -->
<!-- <dependency>-->
<!-- <groupId>org.springframework.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>-->
<!-- <version>2.2.5.RELEASE</version>-->
<!-- </dependency>-->
</dependencies>
建立springboot啟動類:
@SpringBootApplication @EnableEurekaClient public class GateWayApplication { public static void main(String[] args) { SpringApplication.run(GateWayApplication.class,args); } }
啟動類建立成功後,在resources資源目錄下建立application.yml檔案,用來設定gateway。首先設定伺服器埠和服務名稱:
server: port: 8081 spring: application: name: gateway-server-one
在把閘道器註冊到註冊中心:
#使用者端註冊 eureka: instance: instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port} #localhost hostname: localhost client: register-with-eureka: true #是否向註冊中心註冊自己 預設為true fetch-registry: true #是否需要檢索服務 預設為true service-url: defaultZone: http://eternity:1234qwer@localhost:4405/eureka/
設定好之後,可以啟動閘道器。檢視閘道器服務是否可以正常啟動以及是否在註冊中心註冊成功,如果註冊成功然後在開始設定閘道器引數。
可以看到服務啟動成功,我們看看註冊中心是否成功:
eureka中心已經有了,說明啟動成功。
3、設定gateway路由
spring: application: name: gateway-server-one cloud: loadbalancer: ribbon: enabled: false #使用LoadBalancer, Ribbon 在高版本移除了 切換到ReactiveLoadBalancerClientFilter gateway: discovery: locator: #路由存取方式:http://Gateway_HOST:Gateway_PORT/大寫的serviceId/**,其中微服務應用名預設大寫存取。 enabled: true #開啟通過名稱找到伺服器功能 lower-case-service-id: true #使用小寫service-id routes: - id: hibernate-server-one-route #路由的ID,沒有固定規則,但要求唯一,建議與服務名對應 uri: http://localhost:8800 #匹配後提供服務的路由地址 predicates: #以下是斷言條件,必選全部符合條件 - Path=/admin/user/** #斷言,路徑相匹配的進行路由 - Method=GET #只能時 GET 請求時,才能存取 - id: xxl-job-server-one-route # uri: http://localhost:8801 #可以設定為服務名 uri: lb://XXL-JOB-SERVER-MODEL #可以設定為服務名 predicates: - Path=/admin/user/** #斷言,路徑相匹配的進行路由, 注意:Path 中 P 為大寫 - After=2022-06-06T03:29:37.318-07:00 # [Asia/Shanghai] # after來進行設定,後面新增一個時間,就是指在什麼時間之後這個服務才可以被存取,否則將無法被存取到 # - After=2030-01-20T17:42:47.789-07:00 # [America/Denver]
設定成功後再次啟動閘道器,檢視伺服器是否轉發成功。
通過閘道器gateway請求路徑存取查詢使用者資訊:
http://localhost:8081/admin/user/
通過postman測試介面,查詢成功。
4、gateway負載均衡
通過在組態檔中設定路徑的uri為註冊中心伺服器名稱,可以實現gateway負載均衡。存取時通過服務名稱去查詢服務名下面的多個範例,根據設定的策略實現轉發到不同範例服務。
uri: lb://XXL-JOB-SERVER-MODEL #可以設定為服務名
在通過服務名稱轉發的過程中,有可能轉發失敗。報找不到服務,介面報錯:
檢視閘道器控制檯發現也報錯:
java.net.UnknownHostException: failed to resolve 'xxl-job-server-model' after 4 queries at io.netty.resolver.dns.DnsResolveContext.finishResolve(DnsResolveContext.java:1013) ~[netty-resolver-dns-4.1.58.Final.jar:4.1.58.Final] Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: Error has been observed at the following site(s): |_ checkpoint ⇢ org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ HTTP POST "/admin/user/" [ExceptionHandlingWebHandler] Stack trace: at io.netty.resolver.dns.DnsResolveContext.finishResolve(DnsResolveContext.java:1013) ~[netty-resolver-dns-4.1.58.Final.jar:4.1.58.Final] at io.netty.resolver.dns.DnsResolveContext.tryToFinishResolve(DnsResolveContext.java:966) ~[netty-resolver-dns-4.1.58.Final.jar:4.1.58.Final] at io.netty.resolver.dns.DnsResolveContext.query(DnsResolveContext.java:414) ~[netty-resolver-dns-4.1.58.Final.jar:4.1.58.Final]
沒有找到服務名,剛開始以為是設定路由的服務名和註冊中心的服務名不一致。經過查詢發現是一致。最後查詢發現是使用者端微服務註冊到註冊中心的hostname設定錯誤,需要設定和註冊中心一致的hostname。不然閘道器通過服務名找不到相關地址:
檢視eureka服務註冊地址:
所以需要設定使用者端hostname:
hostname: localhost
再次重新執行系統,發現報錯問題已經解決。