(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
(2)代碼地址:
https://github.com/lyh-man/SpringCloudDemo
一、引入配置中心
1、問題 與 解決
【問題:】 通過前面幾篇博客介紹,完成了基本項目創建、服務注冊中心、服務調用、負載均衡、服務降級 以及 服務熔斷。 即 各個模塊 已經能正常通信、共同對外提供服務了,且有了一定的容錯能力。 對於一個復雜的分布式系統來說,可能存在數十個模塊,每個模塊都有不同的配置信息。 而這就帶來了一個問題 -- 如何修改配置信息? 【如何修改配置信息:】 一般修改配置信息后,都得重新啟動一下服務以應用新的配置。 在開發階段,頻繁修改配置信息、啟動服務是很正常的,但是對於一個正在運行的系統,每次修改配置信息,都得重新啟動一下服務,這期間的損失必然是很大的。 舉個例子: 游戲中的停服維護,你玩某個游戲玩得正嗨,結果接到通知需停服 3 天進行維護,那豈不很蛋疼,瞬間失去了玩游戲的興趣。 對於一個復雜的分布式系統來說,可能存在數十個模塊,若一個模塊一個模塊的進行 修改、重啟服務,這將是一個非常繁瑣、且易出錯的工作。 所以需要一款軟件,用來 集中式的管理 配置信息、並實現動態修改配置信息。 【解決:】 集中式管理配置信息、動態修改配置信息。 注: 集中式管理,類似於 Eureka 服務注冊中心進行理解,即可以在某個地方進行配置信息的處理(可以查看到所有的微服務的配置信息)。 動態修改,即不需要重啟微服務,修改后可以直接應用到正在運行的系統上。 相關技術: Config Nacos(推薦使用)
二、配置中心 -- Config
1、Config 是什么?
(1)Config 是什么?
【Config:】 SpringCloud Config 為分布式系統提供了集中式的外部配置支持。 分為 服務器端(Config Server) 以及 客戶端(Config Client)。 Config Server: 服務端也稱為 分布式配置中心,屬於一個獨立的 微服務應用。 其用於連接配置服務器,並向客戶端提供配置信息。 即使用 Config Server 可以集中管理所有環境的配置信息,其默認使用 Git 實現集中化管理的功能。 注: 使用 Git 管理配置信息,便於進行版本控制(可以使用 Git 客戶端工具進行操作)。 Config Client: 客戶端綁定指定的服務端,從配置中心獲取配置信息。 【官網地址:】 https://spring.io/projects/spring-cloud-config https://docs.spring.io/spring-cloud-config/docs/current/reference/html/
(2)Config 功能
【功能:】
集中式的管理配置文件。
可以指定環境進行配置。比如:dev、test、prod、release 等。
運行期間動態修改配置(在配置中心修改后,微服務從配置中心獲取配置信息,微服務無需重啟)。
配置信息以 Rest 接口的形式對外暴露。
2、搭建配置中心(Config Server)
(1)建立一個 Git 倉庫
Config Server 默認使用 Git 實現集中化管理配置信息,即 使用 Git 存儲配置信息,
所以需要建立一個 Git 倉庫,用於存儲配置信息。
如下:
進入 碼雲 (或者 Github) 中,創建一個名為 SpringCloudConfig 的 Git 倉庫。
倉庫地址為:https://gitee.com/lyh-man/spring-cloud-config.git
(2)新建一個子工程 config_server_9100,作為 Config Server
Step1:
修改 父工程、當前工程 pom.xml 文件,並引入相關依賴。
此處以 Eureka 作為服務注冊中心,需要引入相關依賴。
【依賴:】
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
Step2:
修改配置文件。
【application.yml】 server: port: 9100 spring: application: name: config_server cloud: config: # 獲取配置文件的分支,默認為 master label: master server: git: # git 倉庫地址 uri: https://gitee.com/lyh-man/spring-cloud-config.git # 配置文件搜索路徑 search-paths: - SpringCloudConfig eureka: instance: appname: config_server # 優先級比 spring.application.name 高 instance-id: ${eureka.instance.appname} # 設置當前實例 ID client: register-with-eureka: true # 默認為 true,注冊到 注冊中心 fetch-registry: true # 默認為 true,從注冊中心 獲取 注冊信息 service-url: # 指向 注冊中心 地址,也即 eureka_server_7000 的地址。 defaultZone: http://localhost:7000/eureka
Step3:
在 config_server_9100 啟動類上添加 @EnableConfigServer 注解。
Step4:
啟動 eureka_server_7000 以及 config_server_9100。
新增一個文件 config-dev.yml,並提交到 master 分支,內容如下:
【config-dev.yml:】 server: port: 9100 spring: application: name: config_server cloud: config: # 獲取配置文件的分支,默認為 master label: master server: git: # git 倉庫地址 uri: https://gitee.com/lyh-man/spring-cloud-config.git # 配置文件搜索路徑 search-paths: - SpringCloudConfig eureka: instance: appname: config_server # 優先級比 spring.application.name 高 instance-id: ${eureka.instance.appname} # 設置當前實例 ID client: register-with-eureka: true # 默認為 true,注冊到 注冊中心 fetch-registry: true # 默認為 true,從注冊中心 獲取 注冊信息 service-url: # 指向 注冊中心 地址,也即 eureka_server_7000 的地址。 defaultZone: http://localhost:7000/eureka
此時訪問:http://localhost:9100/master/config-dev.yml,即可獲取到 master 分支下的 config-dev.yml 文件內容。
3、獲取 Git 中配置文件的常見 HTTP 格式
(1)格式說明
【三個參數:】 label: 分支名 application: 應用名(服務名) profile: 環境 注: 提交到 Git 的配置文件名 一般由 application 與 profile 組成。 其命名風格一般為: application-profile.yml 或者 application-profile.properties。 比如: config-dev.yml 、config-prod.yml 等。 【HTTP 格式:】 /{label}/{application}-{profile}.yml 或者 /{label}/{application}-{profile}.properties /{application}/{profile}/{label} 比如: /master/config-dev.yml 等價於 /config/dev/master 注: master 可以省略,默認為 master,即 也等價於 /config-dev.yml
4、搭建客戶端(Config Client)
(1)新建一個子工程 config_client_9200,作為 Config Client
Step1:
修改 父工程、當前工程 pom.xml 文件,並引入相關依賴。
此處以 Eureka 作為服務注冊中心,需要引入相關依賴。
【依賴:】
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
Step2:
修改配置文件(bootstrap.yml)。
【注意:】 Config Client 配置文件是 bootstrap.yml,而非 application.yml。 注: bootstrap.yml 優先級比 application.yml 高(即 bootstrap.yml 先加載)。 Config Client 啟動后,會根據 bootstrap.yml 配置的 Config Server 信息與 Config Server 進行綁定, 從而獲取到 Config Server 中存儲在 Git 的配置信息。 【bootstrap.yml】 server: port: 9200 spring: application: name: config_client cloud: # 綁定配置中心,即 http://localhost:9100/master/config-dev.yml config: # 分支名稱 label: master # 配置文件的名稱 name: config # 后綴名 profile: dev # config server 配置中心地址 uri: http://localhost:9100 eureka: instance: appname: config_client # 優先級比 spring.application.name 高 instance-id: ${eureka.instance.appname} # 設置當前實例 ID client: register-with-eureka: true # 默認為 true,注冊到 注冊中心 fetch-registry: true # 默認為 true,從注冊中心 獲取 注冊信息 service-url: # 指向 注冊中心 地址,也即 eureka_server_7000 的地址。 defaultZone: http://localhost:7000/eureka
Step3:
編寫 TestController 進行測試,
其中使用 @Value 注解用於 引入 Git 中存儲的配置文件中的內容。
注:
初始啟動服務時,若 config client 綁定 config server 失敗,即獲取不到 Git 中的配置信息時,@Value 將會導致服務啟動失敗。
【TestController】 package com.lyh.springcloud.config_client_9200.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/config") public class TestController { @Value("${config.info}") private String info; @GetMapping("/getInfo") public String getInfoAndMessage() { String result = ""; if (info != null) { return "success " + info + "\n"; } return "error"; } }
Step4:
修改 Git 倉庫中 config-dev.yml 文件如下:
【config-dev.yml:】
config:
info: helloworld!!!
Step5:
測試。啟動 eureka_server_7000、config_server_9100、config_client_9200。
前面 bootstrap.yml 配置的是 獲取 http://localhost:9100/master/config-dev.yml 中的內容。
config client 成功啟動后,即可獲取 config-dev.yml 內容,從而 @Value 注入成功,成功返回。
注:
若 config client 啟動時,可能由於 @Value 注入失敗,從而導致 服務將啟動失敗。
可能原因:
config server 配置錯誤,config client 不能正常綁定 config server。
config server 正常,但是 config-dev.yml 文件不存在。
config-dev.yml 文件存在,但其中並不存在 config.info。
5、存在的問題(刷新問題)
(1)問題
【問題:】 通過上面 config server 以及 config client 搭建, config client 已經能成功通過 config server 獲取到 Git 存儲的配置信息。 但是存在一個問題: 在 config client 以及 config server 服務均啟動后,再去修改 Git 中的配置文件, 此時會發現 config server 能正常獲取最新的 配置信息,但是 config client 獲取的仍是原來的值。 只有重啟 config client 服務后才能正常獲取到最新的配置信息。 重啟肯定是不可取的方案,那么如何解決呢? 【解決方案一:】 引入 actuator,借助其進行刷新,重新加載。 缺點: 需要手動觸發 POST 請求,訪問 refresh 端口(http://localhost:9200/actuator/refresh)。 當然可以寫個腳本,定時發送請求,進行刷新。 【解決方案二:】 方案一對於每個微服務可能都需要執行一次或多次 POST 請求,用於刷新配置信息。 實現起來還是有點麻煩的, 那么是否存在一種機制,使其一次通知,處處生效? 這里就需要使用一下消息總線 SpringCloud Bus(后續介紹,此處暫時略過)。
(2)解決方案一(使用 actuator):
Step1:
引入 actuator 依賴。
【依賴:】
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Step2:
配置暴露端口,主要是 refresh,其余的隨意(可以直接用 * 表示所有)。
# 暴露監控端點 management: endpoints: web: exposure: # include: "refresh" include: "*"
Step3:
在 TestController 上添加 @RefreshScope 注解。
@RestController @RequestMapping("/config") @RefreshScope public class TestController { @Value("${config.info}") private String info; @GetMapping("/getInfo") public String getInfoAndMessage() { String result = ""; if (info != null) { return "success " + info + "\n"; } return "error"; } }
Step4:
重新啟動 config client,此時獲取到的是最新的配置信息。
再次修改 config-dev.yml 內容如下:
config:
info: refresh
此時 config server 訪問到的是最新的配置信息
但 config client 獲取的仍為上一次的配置信息
使用 Postman 發送 POST 請求 http://localhost:9200/actuator/refresh 后,
config client 再次獲取的為最新的配置信息。
三、引入消息總線
1、問題與解決
【問題:】
前面使用 Spring Cloud Config 作為配置中心時,留了一個坑:
更新 Git 存儲的配置文件后, Config Client 並不能實時的獲取到最新的配置,
Config Client 需要重啟服務 或者 借助 actuator 刷新配置,從而獲取到最新的配置文件信息。
而微服務中,Config Client 數量將會越來越多,若每個 Config Client 都需要重啟 或者 發送 refresh 請求,其伴隨的影響還是有一些的。
那么能否實現自動刷新? 即修改完 Git 的配置文件后,Config Client 自動刷新獲取最新的配置。
【解決:】
使用 Spring Cloud Bus 配合 Spring Cloud Config 可以實現配置的 自動刷新功能。
四、消息總線 -- Bus
1、Bus 是什么?
(1)Bus 是什么?
【Spring Cloud Bus 是什么:】 Spring Cloud Bus 是將 輕量級消息系統 鏈接到 分布式系統節點 的框架,整合了 事件處理機制 和 消息中間件的功能。 其能 管理、傳播 需要在分布式系統中傳遞的消息,可用於 廣播狀態變化(比如: 配置修改)、事件推送等,也可以作為微服務應用間的通信通道。 【Bus 支持的 消息系統:】 Spring Cloud Bus 目前支持兩種消息系統: RabbitMQ 和 Kafka。 使用時需要引入對應的依賴: spring-cloud-starter-bus-amqp 或 spring-cloud-starter-bus-kafka。 【理解一下消息總線:】 消息總線 可以理解為 一個消息中心(RabbitMQ、Kafka),系統中所有微服務實例 連接到 總線上, 微服務實例可以向消息中心發送消息 或者 接收消息(監聽消息中心的消息), 消息中心 產生的消息被 所有微服務實例 監聽並消費。 比如: 微服務實例 A 發送一條消息到總線上,其余微服務實例 可以監聽到 這個消息,並進行相應處理。 【官網地址:】 https://spring.io/projects/spring-cloud-bus https://docs.spring.io/spring-cloud-bus/docs/current/reference/html/
(2)如何實現?
方式一:
客戶端 Config Client 刷新。
【基本流程:】 Step1: 更新 Git Repository 中的配置文件。 Step2: 向客戶端 Config Client C 發送 POST 請求: /actuator/busrefresh, 此時 Config Client C 根據 Config Server 獲取最新的配置文件。 並且 Config Client C 向 消息總線 Bus 發送一條消息(即 表示需要 刷新)。 Step3: Bus 接收消息后,將消息通知給其他 客戶端實例(Config Client A、Config Client B)。 Step4: 其他客戶端實例 接收到信息后,即相當於刷新,根據 Config Server 獲取最新的配置文件。 至此,所有客戶端實例均可獲得最新的配置信息。 【問題:】 一般不使用 客戶端刷新, 因為 客戶端本身屬於 業務模塊,刷新功能並不屬於其業務功能,會破壞了其職責單一性。
方式二:
服務端 Config Server 刷新。
【基本流程:】 Step1: 更新 Git Repository 中的配置文件。 Step2: 向服務端 Config Server 發送 POST 請求: /actuator/busrefresh, 並且 Config Server 向 消息總線 Bus 發送一條消息(即 表示需要 刷新)。 Step3: Bus 接收消息后,將消息通知給所有客戶端實例(Config Client A、Config Client B、Config Client C)。 Step4: 客戶端實例 接收到信息后,即相當於刷新,根據 Config Server 獲取最新的配置文件。 至此,所有客戶端實例均可獲得最新的配置信息。
2、使用 RabbitMQ 作為消息中間件
(1)使用 docker-compose 在 CentOS7 上構建基本環境
docker-compose 基本使用可參照:https://www.cnblogs.com/l-y-h/p/12622730.html#_label8_2
【構建 docker-compose.yml 如下:】 # 指定 compose 文件版本,與 docker 兼容,高版本的 docker 一般使用 3.x。 version: '3.7' # 定義需要管理的 所有服務 信息 services: # 此處指的是服務的名稱 rabbitmq: # 指定鏡像路徑(可以是遠程倉庫鏡像 或者 本地鏡像) image: rabbitmq:3.8.3-management # 指定容器的名稱(等同於 docker run --name) container_name: rabbitmq # 定義容器重啟策略,no 表示任何情況下都不重啟(默認),always 表示總是重新啟動。 restart: always hostname: myRabbitmq # 定義 宿主機 與 容器的端口映射 ports: - 15672:15672 - 5672:5672 # 定義 宿主機 與 容器的數據卷映射 volumes: - /usr/mydata/rabbitmq/data:/var/lib/rabbitmq # 設置環境變量 environment: # 設置 RabbitMQ 登陸用戶為 root,登陸密碼為 root(若未配置,默認為 guest) - RABBITMQ_DEFAULT_USER=root - RABBITMQ_DEFAULT_PASS=root
(2)啟動 RabbitMQ
通過 docker-compose up -d 啟動 RabbitMQ 后,可以通過 15672 端口號訪問其 Web 頁面。
注:
若為雲服務器,需要配置安全組規則,開放 15672、5672 端口。
15672 是 RabbitMQ 可視化 web 界面訪問端口。
5672 是 RabbitMQ 訪問端口。
3、Config 整合 Bus
(1)Config Server 整合 Bus(RabbitMQ)
此處采用方案二,在 服務端進行 刷新,所以 Config Server 需要引入 actuator 依賴。
Step1:
在 config_server_9100 中引入 RabbitMQ 以及 actuator 依賴。
【依賴:】
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Step2:
在配置文件中,添加 RabbitMQ 配置,並暴露 Bus 刷新的端口(busrefresh)。
通過 /actuator/bus-refresh 訪問 busrefresh。
【application.yml:】 spring: # rabbitmq 配置 rabbitmq: username: root password: root host: 120.26.184.41 port: 5672 # 暴露監控端點(busrefresh,或者直接寫 *) management: endpoints: web: exposure: # include: "*" include: "busrefresh"
(2)Config Client 整合 Bus(RabbitMQ)
Step1:
config_client_9200 同樣需要引入 RabbitMQ 依賴。
【依賴:】
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
Step2:
在配置文件中,添加 RabbitMQ 配置。
【bootstrap.yml:】 spring: # RabbitMQ 相關配置 rabbitmq: username: root password: root host: 120.26.184.41 port: 5672
(3)新增一個 Config Client
新增一個與 config_client_9200 類似的 config_client_9201,模擬多實例刷新。
構建步驟與 config_client_9200 相同,僅修改 端口號即可。
為了與 config_client_9200 區別,config_client_9201 中不引入 actuator 依賴。
(4)測試。
分別啟動:eureka_server_7000、config_server_9100、config_client_9200、config_client_9201。
Step1:
初始訪問配置文件情況如下:
http://localhost:9100/master/config-dev.yml http://localhost:9200/config/getInfo http://localhost:9201/config/getInfo
Step2:
修改配置文件后,再次獲取配置文件如下:
http://localhost:9100/master/config-dev.yml http://localhost:9200/config/getInfo http://localhost:9201/config/getInfo
Step3:
向 Config Server 發送 POST 請求 /actuator/bus-refresh,再次獲取配置文件:
POST 請求: http://localhost:9100/actuator/bus-refresh http://localhost:9100/master/config-dev.yml http://localhost:9200/config/getInfo http://localhost:9201/config/getInfo
Step4(方案一:客戶端刷新,僅供參考):
再次修改配置文件,此次給 9200 發送 POST 請求。
由於 9200 配置了 actuator,且暴露端點為 *,可以執行 refresh、bus-refresh。
當發送的 POST 請求為 refersh 時,此時只會更新自己的配置文件,9201 不會更改。
POST 請求: http://localhost:9200/actuator/refresh http://localhost:9100/master/config-dev.yml http://localhost:9200/config/getInfo http://localhost:9201/config/getInfo
當發送的 POST 請求為 bus-refresh 時,9201 配置文件也會修改。
POST 請求: http://localhost:9200/actuator/bus-refresh http://localhost:9100/master/config-dev.yml http://localhost:9200/config/getInfo http://localhost:9201/config/getInfo
Step5:
指定端點進行更新,在 POST 請求后加上需要加上相關 微服務實例的信息,
一般為: spring.application.name:server.port
比如:
config_client:9201 表示僅指定 config_cliet_9201 這個微服務進行更新。
config_client:** 表示 config_client 相關所有微服務進行更新。
POST 請求: http://localhost:9100/actuator/bus-refresh/config_client:9201 http://localhost:9100/master/config-dev.yml http://localhost:9200/config/getInfo http://localhost:9201/config/getInfo
五、分布式鏈路追蹤
1、問題 與 解決
【問題:】
在一個復雜的微服務系統中,一個客戶端發送的請求 可能會經過 多個服務節點,這些服務節點協同工作產生最終的請求結果。
此時可以將請求經過的微服務 看成一條 服務調用鏈路(分布式服務調用鏈路),
鏈路中任何一個服務出現了 高延遲 或者 錯誤 都將引起 整個請求失敗。
當某個請求失敗,如何確定是哪個服務出現了問題?
逐行看日志肯定是不可取的方法,是否存在簡便的工具幫助我們快速定位錯誤服務?
【解決:】
采用 SpringCloud Sleuth,追蹤並展示服務調用鏈路。
2、分布式鏈路追蹤 -- Sleuth
(1)Sleuth 是什么?
【什么是 Sleuth:】 Spring Cloud Sleuth 提供了一套完整的分布式服務追蹤解決方案,兼容 Zipkin。 在一個復雜的微服務系統中,若某時處理了多個請求,那么僅通過 日志 很難判斷出 一個請求 需要被哪些微服務關聯, 一般解決方法是 對於每個請求都傳遞一個唯一的 ID,並根據 ID 查找其日志。 而 Sleuth 可以與 日志框架(Logback、SLF4J) 輕松集成,並通過獨特的標識符來使用 日志跟蹤,從而便於分析服務調用鏈路。 Sleuth 在分布式系統中追蹤 一個請求的處理過程(數據采集、數據傳輸、數據存儲、數據分析、數據可視化),通過可視化界面,可以便於監控微服務調用鏈路。 【官網地址:】 https://spring.io/projects/spring-cloud-sleuth https://docs.spring.io/spring-cloud-sleuth/docs/current/reference/html/getting-started.html
(2)下載、啟動 Zipkin Server
Zipkin 用於可視化界面,下載 jar 包直接啟動即可。
【下載地址:】 http://dl.bintray.com/openzipkin/maven/io/zipkin/java/zipkin-server/ 比如: http://dl.bintray.com/openzipkin/maven/io/zipkin/java/zipkin-server/2.12.9/zipkin-server-2.12.9-exec.jar
通過 java -jar zipkin-server-2.12.9-exec.jar 可以直接啟動。
通過 9411 端口即可進入可視化 Web 界面。
比如:http://120.26.184.41:9411/
3、簡單整合 Sleuth
(1)說明
【說明:】
此處使用 eureka_server_7000、config_server_9100、config_client_9200、config_client_9201 進行演示。
其中:
為了演示鏈路調用,請求經過 config_client_9201,調用 config_client_9200,再調用 config_server_9100。
使用 openfeign 進行服務遠程調用。
(2)改造 config_server_9100
Step1:
引入 sleuth 依賴,並修改配置文件。
【依賴:】 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency> 【bootstrap.yml:】 spring: zipkin: base-url: http://120.26.184.41:9411 sleuth: # 采樣率范圍為 0 ~ 1,1 表示 全部采集 sampler: probability: 1
Step2:
編寫業務代碼。
【SleuthController】 package com.lyh.springcloud.config_server_9100.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RequestMapping("/sleuth") @RestController public class SleuthController { @Value("${server.port}") private String port; @GetMapping("/getInfo") public String getInfo() { return port; } }
(3)改造 config_client_9200
Step1:
引入 openfeign、sleuth 依賴,並修改配置文件。
【依賴:】 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency> 【bootstrap.yml】 spring: zipkin: base-url: http://120.26.184.41:9411 sleuth: # 采樣率范圍為 0 ~ 1,1 表示 全部采集 sampler: probability: 1
Step2:
編寫業務代碼,
config_client_9200 遠程調用 config_server 服務。
在啟動類上添加 @EnableFeignClients 注解。
【SleuthService:】 package com.lyh.springcloud.config_client_9200.service; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.GetMapping; @FeignClient(value = "CONFIG-SERVER") @Component public interface SleuthService { @GetMapping("/sleuth/getInfo") String getInfo(); } 【SleuthController】 package com.lyh.springcloud.config_client_9200.controller; import com.lyh.springcloud.config_client_9200.service.SleuthService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/sleuth") public class SleuthController { @Autowired private SleuthService sleuthService; @Value("${server.port}") private String port; @GetMapping("/getInfo") public String getInfo() { return sleuthService.getInfo() + "current port : " + port; } }
(4)改造 config_client_9201
config_client_9201 與 config_client_9200 修改代碼類似,只是 config_client_9201 遠程調用的是 config_client_9200 服務。
(5)測試
依次啟動 eureka_server_7000、config_server_9100、config_client_9200、config_client_9201 服務,並調用其方法。
(6)演示服務調用錯誤
如下圖,在 config_client_9200 中模擬錯誤調用,並再次發送請求給 config_client_9201。
4、鏈路標識、日志整合
(1)鏈路標識
通過上面的截圖,每個鏈路點開后,均有三個 ID:traceID,spanID,parentID。
【ID:】
traceID 表示請求鏈路的唯一標識,當前鏈路中,每個服務節點均包含同一個 traceID,表示屬於當前鏈路。
spanID 表示每個服務節點的 ID,用於區分鏈路中的每個請求。
parentID 表示當前請求的父服務 ID,即用於關聯鏈路中的請求。
(2)日志整合
如下圖,在 config_client_9200 中打印日志,並再次發送請求給 config_client_9201。
日志輸出格式為:[application name, traceId, spanId, export]。
注:
application name 表示應用名。
export 布爾類型,表示是否將信息輸出到 zipkin 進行收集與展示。
【SleuthController:】 package com.lyh.springcloud.config_client_9200.controller; import com.lyh.springcloud.config_client_9200.service.SleuthService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/sleuth") public class SleuthController { @Autowired private SleuthService sleuthService; private final Logger logger = LoggerFactory.getLogger(SleuthController.class); @Value("${server.port}") private String port; @GetMapping("/getInfo") public String getInfo() { logger.info("test"); return sleuthService.getInfo() + "current port : " + port; } }
六、配置中心 Nacos
參考:https://www.cnblogs.com/l-y-h/p/14604209.html#_label1