(1) 相關博文地址:
學習一下 SpringCloud (一)-- 從單體架構到微服務架構、代碼拆分(maven 聚合): https://www.cnblogs.com/l-y-h/p/14105682.html 學習一下 SpringCloud (二)-- 服務注冊中心 Eureka、Zookeeper、Consul、Nacos :https://www.cnblogs.com/l-y-h/p/14193443.html 學習一下 SpringCloud (三)-- 服務調用、負載均衡 Ribbon、OpenFeign : https://www.cnblogs.com/l-y-h/p/14238203.html 學習一下 SpringCloud (四)-- 服務降級、熔斷 Hystrix、Sentinel : https://www.cnblogs.com/l-y-h/p/14364167.html 學習一下 SpringCloud (五)-- 配置中心 Config、消息總線 Bus、鏈路追蹤 Sleuth、配置中心 Nacos : https://www.cnblogs.com/l-y-h/p/14447473.html
(2)代碼地址:
https://github.com/lyh-man/SpringCloudDemo
一、了解一下 SpringCloud Alibaba
1、SpringCloudAlibaba
(1)簡單說明
【說明:】
通過前面幾篇博客的介紹,已對 SpringCloud 部分框架有了一些認識,比如: Eureka、Ribbon、Hystrix、Config、Bus 等。
但這些框架都有類似的問題:進入了維護模式 或者 功能不完善(使用場景有限,無法很好地適應新需求)
注:
模塊置於維護模式意味着 Spring Cloud 團隊不再向模塊添加新功能。僅修復攔截器漏洞和安全問題。
SpringCloud 版本迭代速度挺快的,這就導致了一個問題: 一些舊版本出現的問題還未解決就推出了一個新的版本。
而某模塊進入了維護模式,即不再開發新功能,其使用價值有限,使用人數也就逐漸減少,相當於 打入冷宮,難有翻身余地。
一個舊技術的沒落,必定有一個新技術取而代之。
而 SpringCloudAlibaba 就是這個新技術之一,有必要重點學習一下。
(2)SpringCloudAlibaba
【SpringCloudAlibaba:】 Spring Cloud Alibaba 致力於提供微服務開發的一站式解決方案。 此項目包含開發分布式應用微服務的必需組件,方便開發者通過 Spring Cloud 編程模型輕松使用這些組件來開發分布式應用服務。 依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以將 Spring Cloud 應用接入阿里微服務解決方案,通過阿里中間件來迅速搭建分布式應用系統。 【相關地址:】 https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md https://spring-cloud-alibaba-group.github.io/github-pages/hoxton/en-us/index.html https://github.com/alibaba/spring-cloud-alibaba/wiki 【版本管理:】 當前 Spring Cloud Alibaba 最新版本為 2.2.5.RELEASE。 其推薦對應 Spring Cloud 版本為 Spring Cloud Hoxton.SR8, 其推薦對應 Spring Boot 版本為 2.3.2.RELEASE。 可參考: https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E
(3)引入依賴
使用 SpringCloudAlibaba 與使用 SpringCloud 類似,一般都在父工程的 pom.xml 文件中通過 <dependencyManagement> 標簽進行版本管理。然后在使用其組件時,直接引入相關組件依賴,無需管理版本。
當然直接引入相關組件依賴 並 指定版本號的方式亦可。
【在父工程中管理版本:】 <properties> <spring.cloud.alibaba.version>2.2.5.RELEASE</spring.cloud.alibaba.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring.cloud.alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
2、SpringCloudAlibaba 主要功能 與 實現組件
(1)SpringCloudAlibaba 主要功能 與 實現組件
【功能與實現組件:】 服務限流降級: 基本說明: 默認支持 WebServlet、WebFlux, OpenFeign、RestTemplate、Spring Cloud Gateway, Zuul, Dubbo 和 RocketMQ 限流降級功能的接入, 可以在運行時通過控制台實時修改限流降級規則,還支持查看限流降級 Metrics 監控。 實現組件: Sentinel: 把流量作為切入點,從流量控制、熔斷降級、系統負載保護等多個維度保護服務的穩定性。 服務注冊與發現: 基本說明: 適配 Spring Cloud 服務注冊與發現標准,默認集成了 Ribbon 的支持。 實現組件: Nacos: 一個更易於構建雲原生應用的動態服務發現和服務管理平台。 分布式配置管理: 基本說明: 支持分布式系統中的外部化配置,配置更改時自動刷新。 實現組件: Nacos: 一個更易於構建雲原生應用的配置管理平台。 消息驅動能力: 基本說明: 基於 Spring Cloud Stream 為微服務應用構建消息驅動能力。 實現組件: RocketMQ: 一款開源的分布式消息系統,基於高可用分布式集群技術,提供低延時的、高可靠的消息發布與訂閱服務。 分布式事務: 基本說明: 使用 @GlobalTransactional 注解, 高效並且對業務零侵入地解決分布式事務問題。 實現組件: Seata: 阿里巴巴開源產品,一個易於使用的高性能微服務分布式事務解決方案。 阿里雲對象存儲: 基本說明: 阿里雲提供的海量、安全、低成本、高可靠的雲存儲服務。支持在任何應用、任何時間、任何地點存儲和訪問任意類型的數據。 實現組件: Alibaba Cloud OSS: 阿里雲對象存儲服務(Object Storage Service,簡稱 OSS),是阿里雲提供的海量、安全、低成本、高可靠的雲存儲服務。您可以在任何應用、任何時間、任何地點存儲和訪問任意類型的數據。 分布式任務調度: 基本說明: 提供秒級、精准、高可靠、高可用的定時(基於 Cron 表達式)任務調度服務。同時提供分布式的任務執行模型,如網格任務。網格任務支持海量子任務均勻分配到所有 Worker(schedulerx-client)上執行。 實現組件: Alibaba Cloud SchedulerX: 阿里中間件團隊開發的一款分布式任務調度產品,提供秒級、精准、高可靠、高可用的定時(基於 Cron 表達式)任務調度服務。 阿里雲短信服務: 基本說明: 覆蓋全球的短信服務,友好、高效、智能的互聯化通訊能力,幫助企業迅速搭建客戶觸達通道。 實現組件: Alibaba Cloud SMS: 覆蓋全球的短信服務,友好、高效、智能的互聯化通訊能力,幫助企業迅速搭建客戶觸達通道。
(2)開發中常使用的技術搭配
【開發中使用的技術:】 在平時開發中使用的技術搭配,我一般采用一下方案: SpringCloud: OpenFeign: 聲明式 HTTP 客戶端(即 遠程服務調用)。 Ribbon: 負載均衡(OpenFeign 中已集成,無需單獨引入)。 Gateway: API 網關。 Sleuth: 分布式鏈路追蹤(即 請求調用鏈監控)。 SpringCloudAlibaba: Nacos: 注冊中心 以及 配置中心(即 服務注冊、發現 以及 動態配置管理)。 Sentinel: 服務容錯(即限流、降級、熔斷)。 Seata: 解決分布式事務。 注: 通過前面幾篇博客的學習,知道了 OpenFeign、Ribbon、Sleuth、Sentinel 相關操作。 OpenFeign、Ribbon 相關操作詳見:https://www.cnblogs.com/l-y-h/p/14238203.html Sleuth 相關操作詳見:https://www.cnblogs.com/l-y-h/p/14447473.html#_label4 Sentinel 相關操作詳見:https://www.cnblogs.com/l-y-h/p/14364167.html#_label2 下面將逐個學習 Nacos、Gateway、Seata。
二、服務注冊中心、配置中心 -- Nacos
1、什么是 Nacos?
(1)Nacos
【Nacos:】 Nacos 即 Dynamic Naming and Configuration Service(動態命名與配置服務)。由 Naming 前兩個字母,Configuration 前兩個字母,以及 Service 首字母組成。 Nacos 是一個更易於構建雲原生應用的動態服務發現、配置管理 以及 服務管理平台。 簡單的理解: Nacos 就是 注冊中心 + 配置中心。 即 Nacos = Eureka + Config + Bus。 【相關地址:】 https://nacos.io/zh-cn/index.html https://github.com/alibaba/nacos
(2)如何使用 Nacos
【如何使用 Nacos:】 Nacos 分為 Server、Client,其中 Server 作為注冊中心以及配置中心,可以獨立部署。 而想要使用 Nacos,僅需在 微服務當中引入 client 相關依賴即可。 其中: Server 最新版本為 1.4.1,根據實際情況可以自行選擇版本。 使用注冊中心功能,需要引入 spring-cloud-starter-alibaba-nacos-discovery 依賴。 使用配置中心功能,需要引入 spring-cloud-starter-alibaba-nacos-config 依賴。 注: 下載地址:https://github.com/alibaba/nacos/releases/download/1.4.1/nacos-server-1.4.1.tar.gz
2、安裝 Nacos Server 單機版(Linux 直接下載並啟動、持久化數據到 MySQL 8)
(1)說明:
Nacos 默認使用內嵌數據庫(Derby)實現數據的存儲,一般使用 單機版 Nacos Server 無需額外配置持久化操作,直接啟動即可。
但大型的項目中,Nacos Server 一般采用集群方式部署,若仍使用默認數據庫進行數據存儲,那么各個 Nacos Server 之間的數據一致性就是一個頭疼的問題。 Nacos 支持持久化數據到 MySQL 中,集群中所有節點共享 MySQL 數據源,從而保證數據一致性。
(2)下載、並解壓 nacos-server
【下載:】 wget https://github.com/alibaba/nacos/releases/download/1.4.1/nacos-server-1.4.1.tar.gz 【解壓:】 tar -axvf nacos-server-1.4.1.tar.gz
(3)直接啟動
未進行持久化配置,使用默認的 Derby 進行數據存儲。
【進入解壓后的 bin 目錄:】 cd ./nacos/bin 【以單機模式啟動:】 sh startup.sh -m standalone 注: 通過執行 sh shutdown.sh 可以關閉 Nacos。 【登錄 Nacos:】 默認通過 8848 端口可以訪問 Nacos。 賬號、密碼默認均為 nacos 比如: http://120.26.184.41:8848/nacos
(4)持久化數據到 MySQL 中
Step1:
連接數據庫,並構建數據表。
【構建數據表:】 進入解壓后的 nacos 的 conf 目錄,可以看到有 nacos-mysql.sql 文件。 連接上 MySQL,新建一個數據庫(nacos_config),並執行 nacos-mysql.sql 文件中的 SQL 語句。 注: 可以直接使用官方提供的 nacos-mysql.sql 文件。 https://github.com/alibaba/nacos/blob/master/distribution/conf/nacos-mysql.sql 注: MySQL 請自行安裝,此處不贅述。 可參考如下博客(僅供參考,長時間未更新,可能會出現一些問題): Windows 安裝 MySQL:https://www.cnblogs.com/l-y-h/p/11700113.html Linux 安裝 MySQL:https://www.cnblogs.com/l-y-h/p/12576633.html Docker 安裝 MySQL:https://www.cnblogs.com/l-y-h/p/12622730.html#_label5 Docker Compose 安裝 MySQL:https://www.cnblogs.com/l-y-h/p/12622730.html#_label8_2
Step2:
配置 nacos 與 mysql 連接信息。
【配置數據源信息:】 同樣在 conf 目錄下,有一個 application.properties 文件。 編輯該文件,在文件末尾添加如下數據源信息(根據 MySQL 信息自行修改): spring.datasource.platform=mysql db.num=1 db.url.0=jdbc:mysql://120.26.184.41:3306/nacos_config?useUnicode=true&characterEncoding=utf8 db.user=root db.password=123456
Step3:
重新啟動 nacos,再次登錄nacos (http://120.26.184.41:8848/nacos) ,並新增一個配置文件。
此時在 MySQL 中可以看到相關信息。
3、安裝 Nacos Server 單機版(docker-compose 啟動,持久化數據到 MySQL 8)
(1)說明
若需持久化到 mysql,同樣也得在 mysql 中生成相應的表,相關 SQL 文件可以參考上面 持久化操作(此處省略)。
可以直接使用官方提供的 MySQL 鏡像,nacos/nacos-mysql:8.0.16,其有一個數據庫 nacos_devtest 已包含了相關的表結構。
【nacos-docker 相關鏈接:】 https://nacos.io/zh-cn/docs/quick-start-docker.html https://github.com/nacos-group/nacos-docker 【docker-compose 使用參考鏈接:】 https://www.cnblogs.com/l-y-h/p/12622730.html#_label8_2 【nacos-mysql SQL:】 https://github.com/alibaba/nacos/blob/master/distribution/conf/nacos-mysql.sql
(2)使用已有的 mysql 文件。
簡化操作,直接使用上面的 mysql。
若需啟動新的 mysql,需要手動執行 SQL,用於創建 nacos 所需相關表結構。
注:
https://github.com/alibaba/nacos/blob/master/distribution/conf/nacos-mysql.sql
【docker-compose.yml】 version: '3.7' services: nacos: image: nacos/nacos-server:1.4.1 container_name: nacos restart: always environment: - MODE=standalone - TZ=Asia/Shanghai - SPRING_DATASOURCE_PLATFORM=mysql - MYSQL_SERVICE_HOST=120.26.184.41 - MYSQL_SERVICE_PORT=3306 - MYSQL_SERVICE_DB_NAME=nacos_config - MYSQL_SERVICE_USER=root - MYSQL_SERVICE_PASSWORD=123456 - JVM_XMS=50m - JVM_MMS=50m volumes: - ./standalone-logs/:/home/nacos/logs ports: - 8848:8848
相關參數設置如下(對於高版本 Nacos 參數有些許不同):
NACOS_SERVER_PORT 需要改為 NACOS_APPLICATION_PORT
多個帶有 MASTER 的參數需要去掉 MASTER,比如:MYSQL_MASTER_SERVICE_HOST 需要改為 MYSQL_SERVICE_HOST。
通過 docker-compose up -d 啟動后,訪問 http://120.26.184.41:8848/nacos。
成功登錄后,可以看到之前配置的文件,即啟動 nacos 成功。
(3)使用 nacos 官方提供的 mysql 鏡像進行持久化操作。
注意:
此處使用的 nacos 鏡像為:nacos/nacos-server:1.4.1。
使用的 mysql 鏡像為:nacos/nacos-mysql:8.0.16。
坑:
執行 docker-compose up -d 后,訪問 nacos。若訪問 nacos 失敗時,可以查看日志文件 start.out,若出現 Caused by: java.lang.IllegalStateException: No DataSource set 的問題,可以重新啟動一下容器(docker-compose restart)。若仍然出錯,則將 nacos-mysql:8.0.16 更換為 nacos-mysql:5.7 。
【docker-compose.yml】 version: '3.7' services: mysql: container_name: nacos-mysql image: nacos/nacos-mysql:8.0.16 environment: - MYSQL_ROOT_PASSWORD=root - MYSQL_DATABASE=nacos_devtest - MYSQL_USER=nacos - MYSQL_PASSWORD=nacos volumes: - ./mysql/data:/var/lib/mysql - ./mysql/log:/var/log/mysql ports: - "3307:3306" nacos: image: nacos/nacos-server:1.4.1 container_name: nacos restart: always environment: - MODE=standalone - TZ=Asia/Shanghai - SPRING_DATASOURCE_PLATFORM=mysql - MYSQL_SERVICE_HOST=120.26.184.41 - MYSQL_SERVICE_PORT=3307 - MYSQL_SERVICE_DB_NAME=nacos_devtest - MYSQL_SERVICE_USER=root - MYSQL_SERVICE_PASSWORD=root - JVM_XMS=50m - JVM_MMS=50m volumes: - ./standalone-logs/:/home/nacos/logs depends_on: - mysql ports: - 8848:8848
4、Nacos 作為 服務注冊中心(服務注冊與發現)
(1)說明:
【說明:】 通過前面的操作,已經成功啟動了 Nacos Server,接下來整合 Nacos Client 即可。 此處的 Nacos Server 為注冊中心。 新建三個模塊 nacos_client_7100、nacos_client_7101、nacos_client_7102 用於演示服務提供者。 新建一個模塊 nacos_client_consumer 用於演示服務消費者(使用 OpenFeign 調用服務)。 Nacos 已集成 Ribbon 並提供負載均衡。 注: 此處模塊創建僅 描述 主要流程,不詳細截圖(可參考之前的博客)。 【參考鏈接:】 https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html https://github.com/alibaba/spring-cloud-alibaba/wiki/Nacos-discovery https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/readme-zh.md
(2)新建模塊 nacos_client_7100
Step1:
修改 pom.xml,引入 nacos-discovery 依賴。
【引入 Nacos 依賴:】
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
Step2:
修改 application.yml,配置 nacos。
【application.yml】 server: port: 7100 spring: application: name: nacos-client cloud: nacos: discovery: # 配置 nacos 地址 server-addr: 120.26.184.41:8848
Step3:
編寫一個測試 controller,簡單測試一下是否正常。
【TestController】 package com.lyh.springcloud.nacos_client_7100.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.List; import java.util.Map; @RequestMapping("/nacos") @RestController public class TestController { @Value("${server.port}") private String port; @Value("${spring.application.name}") private String name; @Autowired private DiscoveryClient discoveryClient; @RequestMapping("/info") public String getInfo() { return name + "-" + port; } @GetMapping("/discovery") public Map<String, List<ServiceInstance>> discovery() { // 獲取服務名列表 List<String> servicesList = discoveryClient.getServices(); // 根據服務名 獲取 每個服務名下的 各個服務的信息 Map<String, List<ServiceInstance>> map = new HashMap<>(); servicesList.stream().forEach(service -> { map.put(service, discoveryClient.getInstances(service)); }); return map; } }
Step4:
啟動當前服務。
在啟動類上添加 @EnableDiscoveryClient 注解(不添加貌似也沒啥影響)。
Step5:
訪問 http://120.26.184.41:8848/nacos/
登陸后,選擇 “服務管理” ==》“服務列表”,即可看到當前有哪些服務注冊進來了。
訪問 http://localhost:7100/nacos/discovery
訪問 http://localhost:7100/nacos/info
(3)新建模塊 nacos_client_7101、nacos_client_7102
這兩個模塊與 nacos_client_7100 類似,僅端口號不同(創建過程此處省略)。
啟動服務后,再次查看 nacos 控制台,可以看到出現 3 個實例。
(4)新建模塊 nacos_client_consumer
nacos-discovery 已集成 Ribbon,默認實現負載均衡方式為 輪詢。
Step1:
引入 nacos-discovery 、openfeign 依賴。
【依賴:】
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
Step2:
修改 application.yml 文件。
【application.yml】 server: port: 7200 spring: application: name: nacos-client-consumer cloud: nacos: discovery: # 配置 nacos 地址 server-addr: 120.26.184.41:8848
Step3:
編寫 openfeign 接口,調用 nacos_client 服務。
【ConsumerFeign】 package com.lyh.springcloud.nacos_client_consumer.service; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.RequestMapping; @Component @FeignClient(name = "nacos-client") public interface ConsumerFeign { @RequestMapping("/nacos/info") String getInfo(); }
Step4:
編寫 controller,用於測試。
【TestController】 package com.lyh.springcloud.nacos_client_consumer.controller; import com.lyh.springcloud.nacos_client_consumer.service.ConsumerFeign; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RequestMapping("/consumer") @RestController public class TestController { @Autowired private ConsumerFeign consumerFeign; @RequestMapping("/info") public String getInfo() { return consumerFeign.getInfo(); } }
Step5:
簡單測試一下 負載均衡。
訪問:http://localhost:7200/consumer/info ,默認輪詢調用 nacos-client 服務。
5、Nacos 作為配置中心(自動刷新)
(1)說明
【說明:】 前面使用 Nacos Server 作為注冊中心,此處作為 配置中心。 修改 nacos_client_7100 模塊作為演示。 注: Nacos 作為配置中心時,用法與 Config 很類似。 Config 使用可參考:https://www.cnblogs.com/l-y-h/p/14447473.html#_label1 【參考鏈接:】 https://github.com/alibaba/spring-cloud-alibaba/wiki/Nacos-config https://github.com/alibaba/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/nacos-example/nacos-config-example
(2)修改 nacos_client_7100
Step1:
添加 nacos-config 依賴。
【依賴:】
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
Step2:
添加 bootstrap.yml 文件,並進行配置中心相關設置。
修改 application.yml 文件,修改其環境為 dev。
注:
配置文件默認拼接為:${spring.cloud.nacos.prefix} - ${spring.profiles.active} . ${spring.cloud.nacos.file-extension}
spring.cloud.nacos.prefix 默認為 spring.application.name。
spring.profiles.active 為當前環境(比如:dev、test、prod 等)。
spring.cloud.nacos.file-extension 為配置文件后綴名,一般為:yaml、properties。
下面配置文件,將會讀取配置中心中 nacos-client-config-dev.yml 文件。
【bootstrap.yml】 server: port: 7100 spring: application: name: nacos-client-config cloud: nacos: discovery: # 配置 nacos server 地址(作為注冊中心) server-addr: 120.26.184.41:8848 config: # 配置 nacos server 地址(作為配置中心) server-addr: 120.26.184.41:8848 # 設置配置文件前綴,默認為 ${spring.application.name} prefix: ${spring.application.name} # 設置配置文件后綴名 file-extension: yml 【application.yml】 spring: profiles: active: dev config: info: ${spring.application.name}-${server.port}-${spring.profiles.active}
Step3:
編寫測試 controller,用於測試。
需要添加 @RefreshScope 注解,用於自動刷新。
【TestConfigController】 package com.lyh.springcloud.nacos_client_7100.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RequestMapping("/config") @RestController @RefreshScope public class TestConfigController { @Value("${config.info}") private String configInfo; @GetMapping("/info") public String getInfo() { return configInfo; } }
Step4:
訪問:http://localhost:7100/config/info
初始時,若 Nacos Server 中不存在配置文件,則會先加載本地 配置文件中的 config.info。
在配置中心添加配置文件如下:
再次訪問,則獲取到的是配置中心最新的配置信息。
6、Namespace、Group、DataID
(1)問題與解決:
【問題:】
實際開發中,一個服務可能會對應多個配置環境(dev、test、prod 等)。
那么如何保證服務啟動時 能 讀取到 正確的 配置文件?
一個大型的微服務系統中,存在很多服務,每個服務都有不同的配置環境,
那么能否統一的、有規划的對配置進行管理呢?
【解決:】
Nacos 中 使用 命名空間(Namespace)、Group(分組)、DataID(配置文件 ID)對配置文件進行管理。
(2)Namespace、Group、DataID
【Namespace:】 Namespace 默認為 public。一般用於實現環境隔離,不同的命名空間是相互隔離的。 比如: 現在有三個環境:開發、測試、生產,則可以創建三個命名空間,每個命名空間對應一個環境。 需要切換環境時,只需切換 命名空間 即可。 【Group:】 Group 默認為 DEFAULT_GROUP。通過一個有意義的字符串對 配置集 或者 服務 進行分組。 【DataID:】 DataID 就是每個配置文件的唯一標識。 【簡單理解:】 Namespace、Group、DataID 的關系可以理解成一個 文件系統。 Namespace 為最頂層的目錄,其可以包含多個 Group。 Group 為 二級目錄,其可以包含多個 DataID。 DataID 為 文件名。 Namespace + Group + DataID 組成配置文件的唯一標識。 注: Namespace 可以通過 spring.cloud.nacos.config.namespace 指定(在 bootstrap.yml 中指定,且為 命名空間的 id 值)。 Group 可以通過 spring.cloud.nacos.config.group 指定(在 bootstrap.yml 中指定)。
(3)演示
Step1:
修改 nacos_client_7100 配置文件如下,添加一個分組 TEST_GROUP。
Step2:
訪問配置中心,查看當前配置文件列表。
如下圖所示,僅有一個分組為 DEFAULT_GROUP 的配置文件。
Step3:
訪問:http://localhost:7100/config/info
由於配置中心中不存在 TEST_GROUP 分組的配置文件,所以加載本地配置文件信息。
Step4:
在配置中心添加一個 nacos-client-config-dev.yml 且分組為 TEST_GROUP 的文件。
Step5:
再次訪問 http://localhost:7100/config/info
可以讀取到 分組為 TEST_GROUP 的 nacos-client-config-dev.yml 文件中的信息。
7、nacos 獲取配置的方式(配置共享)
(1)問題與解決
【問題:】 通過前面的使用,已經知道最基本的 配置文件獲取方式為 ${spring.cloud.nacos.prefix} - ${spring.profiles.active} . ${spring.cloud.nacos.file-extension}。 若僅僅這么使用,只能獲取到配置中心的一個配置文件。 當服務部署了集群后,每個服務對應一個配置文件,此時這些配置文件可能會出現很多重復的內容。 服務出現變動時,可能需要修改每個配置文件,增加了無用的工作量。 那么能否拆分配置文件,使部分配置文件可以共享? 能否使服務同時獲取多個配置文件? 【解決:】 nacos 提供了三種獲取配置文件的方式。 方式: A:通過內部相關規則自動生成相關的 Data Id 配置(${spring.cloud.nacos.prefix} - ${spring.profiles.active} . ${spring.cloud.nacos.file-extension})。 B:通過 spring.cloud.nacos.config.extension-configs[n].data-id 的方式支持多個擴展 Data Id 的配置。 C:通過 spring.cloud.nacos.config.shared-configs[n].data-id 支持多個共享 Data Id 的配置。 優先級: A > B > C 注: extension-configs、shared-configs 支持獲取多個配置文件(n 越大優先級越高)。
(2)演示 extension-configs 使用
Step1:
extension-configs 說明:
【extension-configs 說明:】 extension-configs 類型為 List<NacosConfigProperties.Config> Config: dataId String 類型,即配置文件名(比如:config-dev.yml) group String 類型,即分組名,默認為 DEFAULT_GROUP refresh boolean 類型,是否具備自動刷新,默認為 false(修改配置文件不自動刷新)
Step2:
修改 bootstrap.yml 、application.yml如下:
【bootstrap.yml】 server: port: 7100 spring: application: name: nacos-client-config cloud: nacos: discovery: # 配置 nacos server 地址(作為注冊中心) server-addr: 120.26.184.41:8848 config: # 配置 nacos server 地址(作為配置中心) server-addr: 120.26.184.41:8848 # 設置配置文件前綴,默認為 ${spring.application.name} prefix: ${spring.application.name} # 設置配置文件后綴名 file-extension: yml extension-configs[0]: data-id: test-0-dev.yml extension-configs[1]: data-id: test-1-dev.yml extension-configs[2]: data-id: test-2-dev.yml group: DEFAULT_GROUP refresh: true 【application.yml】 spring: profiles: active: dev config: info: ${spring.application.name}-${server.port}-${spring.profiles.active} test-0: test-0 test-1: test-1 test-2: test-2
Step3:
修改 controller,獲取配置信息。
package com.lyh.springcloud.nacos_client_7100.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RequestMapping("/config") @RestController @RefreshScope public class TestConfigController { @Value("${config.info}") private String configInfo; @Value("${config.test-0}") private String test0; @Value("${config.test-1}") private String test1; @Value("${config.test-2}") private String test2; @GetMapping("/test") public String test() { return test0 + " ---- " + test1 + " ---- " + test2; } @GetMapping("/info") public String getInfo() { return configInfo; } }
Step4:
訪問配置中心,查看當前配置列表。
Step5:
訪問:http://localhost:7100/config/test
由於配置列表為空,服務僅加載本地配置文件。
Step6:
添加配置文件。
Step7:
再次訪問:http://localhost:7100/config/test
由於 test-0-dev.yml 以及 test-1-dev.yml 沒有配置自動刷新,所以值沒有正常變化。
而 test-2-dev.yml 配置了自動刷新,其值正常變化。
(3)演示 shared-configs 使用
shared-configs 用法 與 extension-configs 相同,區別是 extension-configs 優先級高於 shared-configs。(此處省略驗證步驟,參考上面 extension-configs 的使用)
【bootstrap.yml】 server: port: 7100 spring: application: name: nacos-client-config cloud: nacos: discovery: # 配置 nacos server 地址(作為注冊中心) server-addr: 120.26.184.41:8848 config: # 配置 nacos server 地址(作為配置中心) server-addr: 120.26.184.41:8848 # 設置配置文件前綴,默認為 ${spring.application.name} prefix: ${spring.application.name} # 設置配置文件后綴名 file-extension: yml shared-configs[0]: data-id: test-0-dev.yml shared-configs[1]: data-id: test-1-dev.yml shared-configs[2]: data-id: test-2-dev.yml group: DEFAULT_GROUP refresh: true
8、docker-compose 部署 Nacos Server(偽集群版)
(1)說明:
集群至少得有 3 個 Nacos Server 節點。節點多的話 可以搞個 Nginx 做個代理。
有條件的可以搞三台 雲服務器 玩玩。沒條件的可以搞三台 虛擬機 玩玩。
想偷懶的可以直接在一台服務器上啟動 三個 Nacos Server 節點(大坑,不建議做)。
注:
此處為了偷懶,使用 docker-compose 一次性啟動 mysql 以及3 個 Nacos 節點,相關的坑我也做了一些說明,鬼知道我為了解決這些坑經歷了什么 (=_=)。
(2)Nacos 常用幾個日志文件(此處以 偽集群版日志 進行舉例)
【判斷 nacos 是否正常啟,一般看下面幾個日志文件:】 日志文件: /home/nacos/logs/start.out nacos 是否正常啟動 /home/nacos/logs/nacos.log nacos 執行過程中是否報錯 /home/nacos/logs/naming-raft.log nacos 選舉是否異常 【對於 start.out 文件:】 若 Nacos 一直未啟動完成,一般會輸出: Nacos is starting... 比如: 2021-03-25 15:11:05,419 INFO Nacos is starting... 若 Nacos 啟動完成,一般會輸出: Nacos started successfully in cluster mode. use external storage 比如: 2021-03-25 15:11:06,811 INFO Nacos started successfully in cluster mode. use external storage 【對於 naming-raft.log 文件:】 若 Nacos 一直未選舉成功,其輸出日志如下: ERROR NACOS-RAFT vote failed: 500, url: http://120.26.184.41:8850/nacos/v1/ns/raft/vote ERROR NACOS-RAFT vote failed: 500, url: http://120.26.184.41:8851/nacos/v1/ns/raft/vote WARN [IS LEADER] no leader is available now! 若選舉成功,輸出日志為: 2021-03-26 09:46:49,896 INFO received approve from peer: {"ip":"120.26.184.41:8850","voteFor":"120.26.184.41:8849","term":5,"leaderDueMs":19506,"heartbeatDueMs":3500,"state":"FOLLOWER"} 2021-03-26 09:46:49,897 INFO 120.26.184.41:8849 has become the LEADER 2021-03-26 09:46:49,898 INFO received approve from peer: {"ip":"120.26.184.41:8851","voteFor":"120.26.184.41:8849","term":5,"leaderDueMs":17941,"heartbeatDueMs":3500,"state":"FOLLOWER"} 【對於 nacos.log 文件:】 當 Nacos 選舉異常時,可能會輸出: java.lang.IllegalStateException: can not find peer: 172.22.0.5:8848 若沒有錯誤日志輸出,輸出如下日志,可以認為啟動正常: 2021-03-26 09:34:08,199 INFO Started Nacos in 94.251 seconds (JVM running for 100.9) 2021-03-26 09:34:08,199 INFO Nacos Log files: /home/nacos/logs 2021-03-26 09:34:08,208 INFO Nacos Log files: /home/nacos/conf 2021-03-26 09:34:08,208 INFO Nacos Log files: /home/nacos/data 2021-03-26 09:34:08,209 INFO Nacos started successfully in cluster mode. use external storage 2021-03-26 09:34:08,873 INFO Initializing Spring DispatcherServlet 'dispatcherServlet' 2021-03-26 09:34:08,873 INFO Initializing Servlet 'dispatcherServlet' 2021-03-26 09:34:08,954 INFO Completed initialization in 81 ms
(3)偽集群版(大坑)
Step1:編寫 docker-compose.yml 文件
與單機版 docker-compose.yml 類似,
多了參數 NACOS_SERVERS、NACOS_APPLICATION_PORT。
修改了 JVM_XMS 、JVM_MMS 等參數。
修改了 nacos-mysql 版本。
修改了 nacos-server 版本。
注意:
添加了 NACOS_APPLICATION_PORT 后,需要修改相應的端口映射 ports。
添加了 NACOS_SERVERS 后,設置多節點可以使用 逗號 或者 空格 隔開。
JVM_XMS 等參數設置過小時,Nacos 可能跑不起來(適量調大一點)。
若你嘗試過一切手段,配置均正常時,Nacos 仍然跑不起來 或者 選舉失敗,而在網上找不到任何解決辦法時,這邊建議你 更換 鏡像版本試一下 (=_=),鬼知道我試了多少次才解決的。
這邊使用的都是官方鏡像,可以自己手動生成鏡像,具體有些什么坑,請自行嘗試!!!
【docker-compose.yml】 version: '3.7' services: mysql: container_name: nacos-cluster-mysql image: nacos/nacos-mysql:5.7 environment: - MYSQL_ROOT_PASSWORD=root - MYSQL_DATABASE=nacos_devtest - MYSQL_USER=nacos - MYSQL_PASSWORD=nacos volumes: - ./mysql/data:/var/lib/mysql - ./mysql/log:/var/log/mysql ports: - "3308:3306" nacos1: image: nacos/nacos-server:1.3.0 container_name: nacos1 restart: always environment: - NACOS_SERVERS=120.26.184.41:8849 120.26.184.41:8850 120.26.184.41:8851 - NACOS_SERVER_IP=120.26.184.41 - NACOS_APPLICATION_PORT=8849 - TZ=Asia/Shanghai - SPRING_DATASOURCE_PLATFORM=mysql - MYSQL_SERVICE_HOST=120.26.184.41 - MYSQL_SERVICE_PORT=3308 - MYSQL_SERVICE_DB_NAME=nacos_devtest - MYSQL_SERVICE_USER=root - MYSQL_SERVICE_PASSWORD=root - JVM_XMS=100m - JVM_MMS=100m volumes: - ./cluster-logs/nacos1:/home/nacos/logs depends_on: - mysql ports: - 8849:8849 nacos2: image: nacos/nacos-server:1.3.0 container_name: nacos2 restart: always environment: - NACOS_SERVERS=120.26.184.41:8849 120.26.184.41:8850 120.26.184.41:8851 - NACOS_SERVER_IP=120.26.184.41 - NACOS_APPLICATION_PORT=8850 - TZ=Asia/Shanghai - SPRING_DATASOURCE_PLATFORM=mysql - MYSQL_SERVICE_HOST=120.26.184.41 - MYSQL_SERVICE_PORT=3308 - MYSQL_SERVICE_DB_NAME=nacos_devtest - MYSQL_SERVICE_USER=root - MYSQL_SERVICE_PASSWORD=root - JVM_XMS=100m - JVM_MMS=100m volumes: - ./cluster-logs/nacos2:/home/nacos/logs depends_on: - mysql ports: - 8850:8850 nacos3: image: nacos/nacos-server:1.3.0 container_name: nacos3 restart: always environment: - NACOS_SERVERS=120.26.184.41:8849 120.26.184.41:8850 120.26.184.41:8851 - NACOS_SERVER_IP=120.26.184.41 - NACOS_APPLICATION_PORT=8851 - TZ=Asia/Shanghai - SPRING_DATASOURCE_PLATFORM=mysql - MYSQL_SERVICE_HOST=120.26.184.41 - MYSQL_SERVICE_PORT=3308 - MYSQL_SERVICE_DB_NAME=nacos_devtest - MYSQL_SERVICE_USER=root - MYSQL_SERVICE_PASSWORD=root - JVM_XMS=100m - JVM_MMS=100m volumes: - ./cluster-logs/nacos3:/home/nacos/logs depends_on: - mysql ports: - 8851:8851 【巨坑:】 想偷懶,卻掉進了個大坑(沒解決),特此記錄一下,有時間再仔細研究。 情景再現: 在阿里雲服務器上,想使用 docker-compose 一次性啟動三個 Nacos Server 以及 mysql,結果一直啟動失敗。 坑一: nacos-mysql:8.0.16 無法啟動,更換成 nacos-mysql:5.7 之后正常啟動。 但若 nacos-mysql:8.0.16 是事先就啟動好的(即不跟隨 Nacos Server 啟動),那么連接是正常的。 為什么會出現這種情況,沒有仔細研究,此處僅簡單記錄一下可能存在的問題。 坑二: 訪問 http://120.26.184.41:8850/nacos,可以成功登錄進去。 但點擊 “集群管理” =》 “節點列表”,依次點擊 “節點元數據”,可以發現其 "state" 均為 "CANDIDATE"。 即 集群中三個節點 並未選舉成功,未成功選舉出 LEADER、FOLLOWER。 坑三: 集群節點 "state" 均為 "FOLLOWER",沒有 "LEADER"。選舉仍然失敗。 出現了 8848 端口,貌似其被選擇為 LEADER。 坑四: 當前覺得你的配置沒有問題了,但是 選舉依然失敗,這邊建議你更換一下鏡像看看。 此處 nacos/nacos-server:1.4.1 選舉總是失敗,更換 nacos/nacos-server:1.3.0 之后沒問題了。 具體原因沒有深入研究,此處僅記錄一下可能存在的問題。
Step2:填坑記錄一:
將 nacos-mysql:8.0.16 鏡像替換為 nacos-mysql:5.7 后,重新啟動即可。
Step3:填坑記錄二:
若在控制台頁面中,看見節點 “state” 均為 “CANDIDATE”。這是選舉出問題了,可以查看 nacos 日志(naming-raft.log、nacos.log)。
【nacos.log 錯誤日志為:(如下兩句語句循環出現)】 java.lang.IllegalStateException: can not find peer: 172.22.0.3:8848 java.lang.IllegalStateException: can not find peer: 172.22.0.5:8848 【naming-raft.log 錯誤日志為:】 ERROR NACOS-RAFT vote failed: 500, url: http://120.26.184.41:8850/nacos/v1/ns/raft/vote ERROR NACOS-RAFT vote failed: 500, url: http://120.26.184.41:8851/nacos/v1/ns/raft/vote WARN [IS LEADER] no leader is available now! 【分析:】 通過 nacos.log 的 ip 地址,可以猜測當前 nacos 讀取到的是內網 IP。 而集群列表中不存在這個 IP,所以無法連接到其余 節點(無法通信),進而選舉失敗。 【解決:】 既然獲取不到 IP 地址,那就手動輸入 IP 地址。 在環境變量中,通過 NACOS_SERVER_IP 指定當前主機的 IP 即可。 比如: - NACOS_SERVER_IP=120.26.184.41
Step4:填坑記錄三
通過上面截圖,可以看到三個節點狀態均從 "CANDIDATE" 變為了 "FOLLOWER",為什么沒有選舉出 "LEADER"?
【查看 naming-raft.log 日志如下:】 2021-03-25 17:45:09,770 INFO received approve from peer: {"ip":"120.26.184.41:8848","voteFor":"120.26.184.41:8848","term":9,"leaderDueMs":18440,"heartbeatDueMs":2000,"state":"FOLLOWER"} 2021-03-25 17:45:09,772 INFO received approve from peer: {"ip":"120.26.184.41:8848","voteFor":"120.26.184.41:8848","term":9,"leaderDueMs":18531,"heartbeatDueMs":5000,"state":"CANDIDATE"} 2021-03-25 17:45:09,788 INFO received approve from peer: {"ip":"120.26.184.41:8848","voteFor":"120.26.184.41:8848","term":9,"leaderDueMs":18671,"heartbeatDueMs":5000,"state":"FOLLOWER"} 2021-03-25 17:45:15,001 WARN [IS LEADER] no leader is available now! 2021-03-25 17:45:28,123 INFO vote 120.26.184.41:8848 as leader, term: 10 【分析:】 通過日志可以看到貌似 120.26.184.41:8848 這個東西被選為了 LEADER, 而實際上 我開放的是 8849、8850、8851 三個端口,但是這三個端口並沒有被訪問。 【解決:】 默認端口號為 8848。既然獲取不到端口,那就手動設置端口。 在環境變量中,通過 NACOS_APPLICATION_PORT 指定當前主機需要訪問的端口即可。 修改 NACOS_APPLICATION_PORT 后,端口映射 ports 也需要修改。 比如: environment: - NACOS_APPLICATION_PORT=8851 ports: - 8851:8851
(4)連接 Nacos 集群
在 Nacos Client 配置文件中,直接通過 server-addr 設置節點地址即可,多個節點之間可使用 逗號 隔開。
若使用 Nginx 做代理,則 server-addr 設置 Nginx 訪問地址即可。
Nginx 在 Nacos 真集群版中使用(請繼續往下看)。
【比如:】 spring: cloud: nacos: discovery: server-addr: 120.26.184.41:8849,120.26.184.41:8850,120.26.184.41:8851 config: server-addr: 120.26.184.41:8849,120.26.184.41:8850,120.26.184.41:8851 【bootstrap.yml】 server: port: 7100 spring: application: name: nacos-client-config cloud: nacos: discovery: # 配置 nacos server 地址(作為注冊中心) # server-addr: 120.26.184.41:8848 server-addr: 120.26.184.41:8849,120.26.184.41:8850,120.26.184.41:8851 config: # 配置 nacos server 地址(作為配置中心) # server-addr: 120.26.184.41:8848 server-addr: 120.26.184.41:8849,120.26.184.41:8850,120.26.184.41:8851 # 設置配置文件前綴,默認為 ${spring.application.name} prefix: ${spring.application.name} # 設置配置文件后綴名 file-extension: yml shared-configs[0]: data-id: test-0-dev.yml shared-configs[1]: data-id: test-1-dev.yml shared-configs[2]: data-id: test-2-dev.yml group: DEFAULT_GROUP refresh: true
9、docker-compose 部署 Nacos Server(真集群版)
(1)說明:
上面使用 docker-compose 演示了偽集群的操作,許多坑已經踩過了。真集群部署就更加簡單了,將上面偽集群版的 docker-compose.yml 文件拆分成 幾個小的 docker-compose.yml 文件,分別在不同的機器上啟動即可(當然 ip 是需要修改的)。
此處創建三個 虛擬機,地址分別為:192.168.157.128、192.168.157.129、192.168.157.130。
在 192.168.157.128 上啟動 mysql、nginx、nacos1。
在 129、130 上分別啟動 nacos2、nacos3。
其中:
使用 nginx 反向代理 nacos1、nacos2、nacos3。通過 nginx 訪問 Nacos Server。
使用 mysql 做配置信息持久化操作。
注:
此處可以使用較高版本的 mysql、nacos。比如:nacos-mysql:8.0.16、nacos-server:1.4.1 。
(2)配置 mysql 以及 nginx。
Step1:
自定義一個 nginx.conf,進行代理配置。
如下所示,主要關注 server 以及 upstream nacos_server。
【nginx.conf】 user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; # 負載均衡 upstream nacos_server { # 默認加權輪詢方式執行負載均衡 # weight 表示服務器權重,默認為 1。 # max_fails 表示 nginx 與 服務器通信失敗 的最大次數。默認為 1。 # fail_timeout 為失敗超時時間。默認 10 秒。在 fail_timeout 時間內,失敗次數達到 max_fails,則 Nginx 認為該服務器不可用。 server 192.168.157.128:8849 weight=1 max_fails=2 fail_timeout=10s; server 192.168.157.129:8850 weight=1 max_fails=2 fail_timeout=10s; server 192.168.157.130:8851 weight=1 max_fails=2 fail_timeout=10s; } server { listen 10080; # 設置監聽端口 server_name 192.168.157.128; # 設置 IP 地址 location / { # 設置代理地址(根據 upstream 的值修改) # 訪問請求 http://192.168.157.128:10080 時,會替換為 http://192.168.157.128:8849/nacos/ proxy_pass http://nacos_server/nacos/; # 下面幾個設置默認即可 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header REMOTE-HOST $remote_addr; add_header X-Cache $upstream_cache_status; add_header Cache-Control no-cache; } } include /etc/nginx/conf.d/*.conf; }
Step2:
編寫 docker-compose.yml 文件,配置 mysql、nginx。
需要將 上面自定義的 conf 文件 掛載到 nginx 的 /etc/nginx/nginx.conf 目錄下。
【docker-compose.yml】 version: '3.7' services: nginx: container_name: nginx image: nginx:latest restart: always ports: - "10080:10080" volumes: - ./nginx.conf:/etc/nginx/nginx.conf - ./logs:/var/log/nginx/ mysql: container_name: nacos-cluster-mysql image: nacos/nacos-mysql:5.7 environment: - MYSQL_ROOT_PASSWORD=root - MYSQL_DATABASE=nacos_devtest - MYSQL_USER=nacos - MYSQL_PASSWORD=nacos volumes: - ./mysql/data:/var/lib/mysql - ./mysql/log:/var/log/mysql ports: - "3308:3306"
(3)配置 nacos1、nacos2、nacos3
【nacos1:】 version: '3.7' services: nacos1: image: nacos/nacos-server:1.3.0 container_name: nacos1 restart: always environment: - NACOS_SERVERS=192.168.157.128:8849 192.168.157.129:8850 192.168.157.130:8851 - NACOS_SERVER_IP=192.168.157.128 - NACOS_APPLICATION_PORT=8849 - TZ=Asia/Shanghai - SPRING_DATASOURCE_PLATFORM=mysql - MYSQL_SERVICE_HOST=192.168.157.128 - MYSQL_SERVICE_PORT=3308 - MYSQL_SERVICE_DB_NAME=nacos_devtest - MYSQL_SERVICE_USER=root - MYSQL_SERVICE_PASSWORD=root - JVM_XMS=100m - JVM_MMS=100m volumes: - ./nacos1:/home/nacos/logs ports: - 8849:8849 【nacos2:】 version: '3.7' services: nacos2: image: nacos/nacos-server:1.3.0 container_name: nacos2 restart: always environment: - NACOS_SERVERS=192.168.157.128:8849 192.168.157.129:8850 192.168.157.130:8851 - NACOS_SERVER_IP=192.168.157.129 - NACOS_APPLICATION_PORT=8850 - TZ=Asia/Shanghai - SPRING_DATASOURCE_PLATFORM=mysql - MYSQL_SERVICE_HOST=192.168.157.128 - MYSQL_SERVICE_PORT=3308 - MYSQL_SERVICE_DB_NAME=nacos_devtest - MYSQL_SERVICE_USER=root - MYSQL_SERVICE_PASSWORD=root - JVM_XMS=100m - JVM_MMS=100m volumes: - ./nacos2:/home/nacos/logs ports: - 8850:8850 【nacos3:】 version: '3.7' services: nacos3: image: nacos/nacos-server:1.3.0 container_name: nacos3 restart: always environment: - NACOS_SERVERS=192.168.157.128:8849 192.168.157.129:8850 192.168.157.130:8851 - NACOS_SERVER_IP=192.168.157.130 - NACOS_APPLICATION_PORT=8851 - TZ=Asia/Shanghai - SPRING_DATASOURCE_PLATFORM=mysql - MYSQL_SERVICE_HOST=192.168.157.128 - MYSQL_SERVICE_PORT=3308 - MYSQL_SERVICE_DB_NAME=nacos_devtest - MYSQL_SERVICE_USER=root - MYSQL_SERVICE_PASSWORD=root - JVM_XMS=100m - JVM_MMS=100m volumes: - ./nacos3:/home/nacos/logs ports: - 8851:8851
(4)啟動
分別啟動 nginx、mysql、nacos1、nacos2、nacos3。
訪問:http://192.168.157.128:10080/ 會自動跳轉到相應的 Nacos 控制台界面。
(5)連接 nacos 集群
若未使用 Nginx 代理時,直接在 Nacos Client 配置文件中,直接通過 server-addr 設置節點地址即可,多個節點之間可使用 逗號 隔開。
spring: cloud: nacos: discovery: # 配置 nacos server 地址(作為注冊中心) server-addr: 192.168.157.128:8849,192.168.157.129:8850,192.168.157.130:8851 config: # 配置 nacos server 地址(作為配置中心) server-addr: 192.168.157.128:8849,192.168.157.129:8850,192.168.157.130:8851
若使用 Nginx 做代理,則 server-addr 設置 Nginx 訪問地址即可。
注:
此處關於 proxy_pass 設置的地址 有個小坑記錄一下。
server{ listen 10080; # 設置監聽端口 server_name 192.168.157.128; # 設置 IP 地址 location / { # 設置代理地址(根據 upstream 的值修改) # 訪問請求 http://192.168.157.128:10080 時,會替換為 http://192.168.157.128:8849/nacos/ proxy_pass http://nacos_server/nacos/; #proxy_pass http://nacos_server/; }
若使用 proxy_pass http://nacos_server/,則在 Nacos Client 中直接配置 Nginx 地址即可。
此時,客戶端正常啟動,可以通過 Nginx 訪問到 Nacos Server 集群,獲取配置文件。
但是直接通過 Nginx 地址(http://192.168.157.128:10080 或者 http://192.168.157.128:10080/nacos),無法跳轉到 Nacos 控制台界面。
spring: cloud: nacos: discovery: server-addr: 192.168.157.128:10080 config: server-addr: 192.168.157.128:10080
若使用 proxy_pass http://nacos_server/nacos/,則通過 Nginx 地址(http://192.168.157.128:10080) 正常跳轉進 Nacos 控制台界面,但若此時 Nacos Client 直接配置 Nginx 地址時,服務啟動會異常,啟動失敗。
報錯信息如下:
【錯誤信息:】 org.springframework.context.ApplicationContextException: Failed to start bean 'webServerStartStop'; nested exception is java.lang.reflect.UndeclaredThrowableException Caused by: java.lang.reflect.UndeclaredThrowableException: null Caused by: com.alibaba.nacos.api.exception.NacosException: failed to req API:/nacos/v1/ns/instance after all servers([192.168.157.128:10080]) tried: ErrCode:404, ErrMsg:<html><body><h1>Whitelabel Error Page</h1><p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p><div id='created'>Fri Mar 26 20:22:33 CST 2021</div><div>There was an unexpected error (type=Not Found, status=404).</div><div>No message available</div></body></html>
三、網關 -- Gateway
1、什么是 Gateway?
(1)什么是 Gateway?
【Gateway:】 Gateway 直譯為 網關,是基於 Spring Boot 2.x、Spring WebFlux、Project Reactor 構建的 API 網關服務。 Gateway 目的是 提供一個簡單的方式進行 路由轉發,用於保護、控制、增強 對於 API 接口的訪問。 簡單理解: Gateway 可以理解為 所有流量(請求)的入口,所有瀏覽器請求 都得通過 Gateway 進行路由,才能訪問到服務提供的 API 接口。可以類比於 Nginx 反向代理進行理解。 Gateway 底層使用的是 Netty 框架。 注: 在 Gateway 之前,會使用 Zuul 作為網關,有興趣的請自行了解。 Zuul 1.x 是基於 Servlet 2.5 的 阻塞 I/O 的 API 網關,不支持長連接。 Zuul 2.x 是基於 Netty 的 非阻塞 I/O 的 API 網關,支持長連接。 SpringCloud 並沒有整合 Zuul 2.x,而是自己開發的一個 Gateway。 Gateway 畢竟是親生的,在微服務中整合起來相對簡單,所以使用較多的還是 Gateway。 【官網地址:】 https://spring.io/projects/spring-cloud-gateway https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/
(2)網關使用場景?
如下圖所示,網關作為所有流量的 入口,根據路由規則 將請求路由到各個微服務上。
若網關部署為 集群時,可以使用 Nginx 對其進行負載均衡。
(3)Gateway 功能
Gateway 基於 Spring Framework 5,Project Reactor、Spring Boot 2.0 構建,其基本功能如下:
能夠匹配任何請求屬性的路由(支持動態路由,可以根據微服務名進行路由)。
可以針對特殊路由指定 Predicates 和 Filter 規則,且 Filter、Predicates 易編寫。
集成 斷路器 功能(Circuit Breaker)。
集成 服務發現 功能(Spring Cloud DiscoveryClient)。
集成 請求限流 功能。
支持 路徑重寫 功能。
2、Gateway 核心概念(Route、Filter、Predicate)
(1)Route(路由)
路由是構建網關的基本模塊,基本構成組件: ID、目標 URL、Predicate 集合、Filter 集合 組成。當 Predicate 為 true 時,匹配該路由。
(2)Predicate(斷言)
可以參考 JDK8 中 java.util.function.Predicate 進行理解。
可以根據 HTTP 請求中的內容(比如:請求頭、請求參數 等)進行匹配,如果匹配結果為 true,則匹配該路由。
(3)Filter(過濾)
指的是 Spring 框架中 GatewayFilter 的實例,根據過濾器,可以在 請求被 路由前 或者 路由后 對請求進行更改。
(4)gateway 工作流程
Gateway 整個工作流程就是 路由轉發 + 過濾器鏈。
客戶端 向 Gateway 發送請求,在 Gateway Handler Mapping 中找到與 請求匹配的 路由(根據 Predicate 匹配 Route),然后將其轉發到 Gateway Web Handler 進行處理。
Handler 通過指定的過濾器鏈后,將請求發送到實際的業務邏輯進行處理,處理完成后返回。同時過濾器也可以對返回數據進行處理。
過濾器 可以在路由處理前 進行 參數校驗、權限校驗、流量監控、協議轉換 等操作。
過濾器 可以在路由處理后 進行 響應內容修改、日志輸出、流量監控等操作。
3、簡單使用一下 Gateway
(1)說明
新建一個子模塊 gateway_7200,通過配置文件的方式,簡單測試一下 路由匹配規則。此處簡單的與 前面使用的 Nacos 一起使用。具體使用規則可參考官方文檔:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/
(2)使用 Gateway
Step1:
引入 Gateway 依賴。Gateway 注冊到 Nacos Server 中。
注:
添加 Gateway 依賴后,需要排除 spring-boot-starter-web 依賴。若不排除,則啟動網關服務時將會出錯。
【依賴:】 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> 【錯誤:】 若出現如下異常,需要移除 spring-boot-starter-web 依賴,否則會與 webflux 的 jar 包沖突導致啟動失敗。 Description: Parameter 0 of method modifyRequestBodyGatewayFilterFactory in org.springframework.cloud.gateway.config.GatewayAutoConfiguration required a bean of type 'org.springframework.http.codec.ServerCodecConfigurer' that could not be found. Action: Consider defining a bean of type 'org.springframework.http.codec.ServerCodecConfigurer' in your configuration.
Step2:
配置 Gateway。
如下所示,配置 Nacos 注冊中心地址為 120.26.184.41:8848。
配置路由規則,此處演示 Path 進行匹配。
注:
若使用 Path 進行路徑匹配時,匹配成功后,真實訪問路徑其實就是 uri + Path。
比如:
當請求為 http://localhost:7200/nacos/info/ 時,其將跳轉到 http://localhost:7101/nacos/info 進行處理。
當請求為 http://localhost:7200/ 時,其將跳轉到 https://www.baidu.com/ 進行處理。
【application.yml】 server: port: 7200 spring: application: name: gateway cloud: nacos: discovery: # 配置 nacos 地址 server-addr: 120.26.184.41:8848 # 網關配置 gateway: # 配置路由規則 routes: # 路由唯一 id 名 - id: gateway_route # 斷言為 true 時,需執行的 路由地址 uri: http://localhost:7101 # 定義斷言,即 地址匹配 規則 predicates: # 當訪問 http://localhost:7200/naocs/info 時,此時斷言匹配成功,根據 uri 將跳轉到 http://localhost:7101/nacos/info - Path=/nacos/info - id: gateway_route2 uri: https://www.baidu.com/ predicates: - Path=/
Step3:
啟動 nacos_client_7101、gateway_7200。
訪問 http://localhost:7200/nacos/info 時,將跳轉到 http://localhost:7101/nacos/info 處理。
訪問 http://localhost:7200/ 時,將跳轉到 https://www.baidu.com/ 處理。
(3)根據微服務名進行 路由(動態路由)
實際開發中,一個服務通常以集群的方式部署,若 uri 配置固定的地址進行跳轉,肯定是不合適的。而 微服務注冊在 注冊中心中,網關 只需要通過 注冊中心 提供的 微服務名 找到真實的 微服務,進行路由即可。
修改的配置如下:
在 uri 中使用 lb://微服務名 進行配置即可。lb 表示負載均衡。
確保能根據 微服務名 進行路由,需配置 spring.cloud.gateway.discovery.locator.enabled=true
注:
若注冊中心為 nacos,僅需設置 uri 為 lb://微服務名 即可根據 微服務名進行 路由跳轉,且實現負載均衡。其他注冊中心 Eureka、Zookeeper、Consul 等此處並未進行嘗試,若不能路由,則配置一下 discovery.locator.enabled=true 應該就行了。
【application.yml】 server: port: 7200 spring: application: name: gateway cloud: nacos: discovery: # 配置 nacos 地址 server-addr: 120.26.184.41:8848 # 網關配置 gateway: routes: - id: gateway_route3 uri: lb://nacos-client predicates: # 配置多個地址時,可以使用 逗號 隔開 - Path=/nacos/info,/nacos/discovery
啟動 nacos_client_7101、nacos_client_7102,微服務名為 nacos-client。
當訪問 http://localhost:7200/nacos/info 時,會路由到 http://localhost:7101/nacos/info 與 http://localhost:7102/nacos/info ,並實現負載均衡(此處默認為 輪詢)。
4、predicates 規則
Gateway 內部有許多 Route Predicate factories,可以與 HTTP 請求的不同屬性進行匹配,多個 Predicate 規則可以組合使用。請求匹配成功后,則根據 uri 進行路由跳轉。
常見的 Predicate 規則如下。
(1)時間相關(Before、After、Between)
Before 表示在 指定時間(datetime) 前的請求 才能匹配路由。
After 表示在 指定時間(datetime) 后的請求 才能匹配路由。
Between 表示在 指定時間段(datetime1,datetime2) 內的請求 才能匹配路由。
注:
時間參數 datetime 為 ZonedDateTime 的數據。
可以使用 System.out.println(ZonedDateTime.now()); 輸出當前地區、時間。
比如:2021-03-31T10:35:43.706+08:00[Asia/Shanghai]
【格式:】 predicates: - After=datetime - Before=datetime - Between=datetime1,datetime2 【舉例:】 predicates: - After=2021-03-31T10:35:43.706+08:00[Asia/Shanghai] - Before=2021-03-31T10:35:43.706+08:00[Asia/Shanghai] - Between=2021-03-31T10:35:43.706+08:00[Asia/Shanghai],2021-03-31T10:40:43.706+08:00[Asia/Shanghai] 【舉例:(如下,在指定時間之后的請求才能 路由。指定時間之前,路由將失敗。)】 server: port: 7200 spring: application: name: gateway cloud: nacos: discovery: # 配置 nacos 地址 server-addr: 120.26.184.41:8848 # 網關配置 gateway: routes: - id: gateway_route3 uri: lb://nacos-client predicates: # 配置多個地址時,可以使用 逗號 隔開 - Path=/nacos/info,/nacos/discovery - After=2021-03-31T10:40:00.706+08:00[Asia/Shanghai]
(2)Cookie 相關
Cookie 規則具備兩個參數,一個是 Cookie 屬性名(name),一個是正則表達式(regexp)。
根據 name 以及 regexp 去匹配路由。帶有指定 cookie 信息的請求才能匹配路由。
有兩種寫法格式。
【格式一:】 predicates: - Cookie=mycookiename,mycookievalue 【格式二:】 predicates: - name: Cookie args: name: mycookiename regexp: mycookievalue 【舉例:當請求 cookie 中攜帶 username 為 jarry 時,才能匹配路由】 server: port: 7200 spring: application: name: gateway cloud: nacos: discovery: # 配置 nacos 地址 server-addr: 120.26.184.41:8848 # 網關配置 gateway: routes: - id: gateway_route3 uri: lb://nacos-client predicates: # 配置多個地址時,可以使用 逗號 隔開 - Path=/nacos/info,/nacos/discovery - After=2021-03-31T10:40:00.706+08:00[Asia/Shanghai] - Cookie=username,jarry # - name: Cookie # args: # name: username # regexp: tom 【通過 curl 模擬請求:】 curl http://localhost:7200/nacos/info --cookie "username=jarry" 路由匹配成功 curl http://localhost:7200/nacos/info --cookie "username=jarry1" 路由匹配失敗
(3)Header、Host、Method、Path、Query、Weight 等
可以自行嘗試,此處不一一舉例。
【Header:】 參數: name、regexp。 與 Cookie 規則類似。 帶有指定請求頭的請求才能匹配路由。 格式: predicates: - Header=X-Request-Id, \d+ 【Host:】 參數: patterns 帶有指定 host 的請求才能匹配路由。 格式: predicates: - Host=**.lyh.com 【Method:】 參數: methods 帶有指定方法的請求才能匹配路由。 格式: predicates: - Method=GET,POST 【Path:】 參數: PathMatcher 帶有指定路徑的請求才能匹配路由。多路徑使用逗號隔開。 格式: predicates: - Path=/red/{segment},/blue/{segment} 【Query:】 參數: param、regexp。 與 Cookie 規則類似。 帶有指定參數的請求才能匹配路由。 格式: predicates: - Query=green 【Weight:】 參數: group、weight。 根據權重進行請求分流,80% 請求匹配到 weight_high,20% 請求匹配到 weight_low。 格式: routes: - id: weight_high uri: https://weighthigh.org predicates: - Weight=group1, 8 - id: weight_low uri: https://weightlow.org predicates: - Weight=group1, 2 【舉例:】 server: port: 7200 spring: application: name: gateway cloud: nacos: discovery: # 配置 nacos 地址 server-addr: 120.26.184.41:8848 # 網關配置 gateway: routes: - id: gateway_route3 uri: lb://nacos-client predicates: # 配置多個地址時,可以使用 逗號 隔開 - Path=/nacos/info,/nacos/discovery - After=2021-03-31T10:40:00.706+08:00[Asia/Shanghai] - Query=green,test. - Method=GET,POST - Host=**.lyh.com - Header=X-Request-Id, \d+ - Cookie=username,jarry 【通過 curl 測試:(發送 GET、POST 請求)】 curl -X POST "http://localhost:7200/nacos/info?green=test1" --cookie "username=jarry" --header "X-Request-Id:123" --header "Host:www.lyh.com curl "http://localhost:7200/nacos/info?green=test1" --cookie "username=jarry" --header "X-Request-Id:123" --header "Host:www.lyh.com
5、Filter 規則
Gateway 內部有許多 GatewayFilter Factories,可以修改 HTTP 請求 以及 HTTP 響應。
僅簡單介紹幾個 Filter,其余請自行參閱官方文檔進行使用。
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories
(1)添加參數(比如:AddRequestParameter)
參數為 name、value。用於在請求末尾追加參數(比如: ?name1=value1&name2=value2)
可以在 predicates 指定變量 segment,並處理。
【格式:】 spring: cloud: gateway: routes: - id: add_request_parameter_route1 uri: https://example.org predicates: - Path=/test/{segment} filters: - AddRequestParameter=foo, bar-{segment} - id: add_request_parameter_route2 uri: https://example.org filters: - AddRequestParameter=red, blue 【舉例:(修改 gateway 配置文件如下)】 server: port: 7200 spring: application: name: gateway cloud: nacos: discovery: # 配置 nacos 地址 server-addr: 120.26.184.41:8848 # 網關配置 gateway: routes: - id: gateway_route4 uri: http://localhost:7101 predicates: - Path=/nacos/test/{username} filters: - AddRequestParameter=password,{username} - AddRequestParameter=email,jarry@163.com 【在 nacos_client_7101 中添加如下代碼:】 @GetMapping("/test/{username}") public String test(@PathVariable String username, @RequestParam(required = false) String password, @RequestParam(required = false) String email, @RequestParam(required = false) Integer age) { username = (username != null ? username : "hello"); password = (password != null ? password : "helloworld"); email = (email != null ? email : "tom@163.com"); age = (age != null ? age : 24); return username + " " + password + " " + email + " " + age; }
當訪問 http://localhost:7200/nacos/test/hello 時,predicates 匹配成功,filters 發揮最用,等同於發送請求 http://localhost:7101/nacos/test/hello?password=hello&email=jarry@163.com
(2)修改路徑(比如:PrefixPath、StripPrefix)
【PrefixPath:】 PrefixPath 用於指定 路徑前綴。 比如: gateway: routes: - id: gateway_route5 uri: http://localhost:7101 predicates: - Path=/info filters: - PrefixPath=/nacos 當訪問 http://localhost:7200/info 時,將跳轉到 http://localhost:7101/nacos/info 【StripPrefix:】 StripPrefix 用於跳過 路徑前綴(數值型)。 比如: gateway: routes: - id: gateway_route5 uri: http://localhost:7101 predicates: - Path=/info/** filters: - StripPrefix=1 當訪問 http://localhost:7200/info/nacos/info 時,將跳轉到 http://localhost:7101/nacos/info
其余 Filter 可自行參考文檔。也可以自定義 Filter。后續有時間再來補充。。。