3. 微服務調用及運行過程
3.1 為什么分析微服務過程調用
在實際的項目中,微服務之間涉及到業務代碼的部分,調用邏輯非常復雜,對於工程師而言,熟悉組件之間的調用關系,方便以后業務模塊開發,集群部署與自動化編排過程中有非常大的幫助(基礎),並且能夠非常清楚哪些應用應該對外,哪些可以不用對外以及服務是怎樣存活。
- 在微服務中涉及的組件:注冊中心,配置中心,服務提供者,服務消費者,路由網關
3.1.1 本案例涉及的服務有以下幾種
注冊中心服務(nacos),配置中心服務(nacos),服務提供者(passport),服務消費者(restTemplate,Feign),路由網關服務(Spring Cloud Gateway)
3.2 組件服務調用基本流程
- 客戶端瀏覽器輸入url
- 訪問網關負載均衡(7層,可以是nginx/haproxy)通過負載均衡分發請求到spring cloud gateway網關
- 網關在即受到來自負載均衡的請求之后,根據url地址匹配到服務名稱,調用后台的restTemplate服務
- restTemplate在接收到來自網關的請求以后,通過注冊中心查詢到服務列表,將請求服務列表中的服務,最后返回結果。
3.3 組件內部接口調用流程
負載均衡->網關->消費者->服務提供者
3.4 微服務實戰(單機部署)
3.4.1 運行微服務
安裝java環境
將java安裝包(jdk1.8.0_192.tar.gz)傳到主機/usr/local/下並解壓縮
編輯環境變量/etc/profile
vim /etc/prolfie
export JAVA_HOME=/usr/local/jdk1.8.0_192
export JRE_HOME=/${JAVA_HOME}/jre
export PATH=${JAVA_HOME}/bin:$PATH
#應用
source /etc/profile
3.4.2 安裝nacos(單機)
下載注冊中心nacos
wget https://github.com/alibaba/nacos/releases/download/1.1.4/nacos-server-1.1.4.tar.gz
tar zxvf nacos-server-1.1.4.tar.gz
cd nacos/bin
sh startup.sh -m standalone
登陸訪問頁面
http://192.168.68.152:8848/nacos
username:nacos
password:nacos
導入配置文件
nacos_config_provider.zip ----> provider-passport-config.yaml
nacos_config_gateway.zip ----> spring-cloud-gateway.yaml
可以從頁面修改配置文件中注冊中心的IP地址
spring-cloud-gateway.yaml
server-addr: 192.168.68.152:8848
file-extension: yaml
config:
server-addr: 192.168.68.152:8848
provider-passport-config.yaml
server-addr: 192.168.68.152:8848
生產使用集群模式(至少3個節點)
- 安裝mysql5.7.25(主從)
- 導入數據庫(nacos-mysql.sql)
- 修改配置文件(application.properties cluster.conf)
- 啟動(sh startup.sh)
3.4.3 安裝redis
yum install epel-release -y
yum install redis -y
#修改密碼
vim /etc/redis.conf
requirepass 123456
bind 0.0.0.0
#開機啟動
systemctl enable redis
systemctl restart redis
systemctl status redis
查看端口監聽
[root@localhost ~]# netstat -lantup | grep 6379
tcp 0 0 0.0.0.0:6379 0.0.0.0:* LISTEN 12850/redis-server
修改配置文件spring-cloud-gateway.yaml
redis:
host: 192.168.68.152
port: 6379
password: 123456
3.4.4 后台服務provider-passport
上傳測試包
mkdir springcloud && cd springcloud
[root@localhost springcloud]# ll
total 449792
-rw-r--r-- 1 root root 91330721 Aug 26 10:18 consumer-feign-passport-0.0.1-SNAPSHOT.jar
-rw-r--r-- 1 root root 90430214 Aug 26 10:28 consumer-passport-0.0.1-SNAPSHOT.jar
-rw-r--r-- 1 root root 105609972 Aug 26 12:27 gateway-0.0.1-SNAPSHOT.jar
-rw-r--r-- 1 root root 49134278 Aug 26 10:27 monitor-0.0.1-SNAPSHOT.jar
-rw-r--r-- 1 root root 33651884 Aug 26 10:24 passport-demo-0.0.1-SNAPSHOT.jar
-rw-r--r-- 1 root root 90419589 Aug 26 12:14 provider-passport-0.0.1-SNAPSHOT.jar
3.4.4.1 運行provide passport
java -Dspring.cloud.nacos.discovery.server-addr=192.168.68.152:8848 \
-Dspring.cloud.nacos.config.server-addr=192.168.68.152:8848 \
-jar provider-passport-0.0.1-SNAPSHOT.jar
3.4.4.2 服務注冊
從頁面查看我們剛才啟動的passport服務已經注冊到注冊中心
3.4.4.3 訪問后台服務接口
http://192.168.68.152:8086/v1/auth/login
返回json內容如下:
{
msg: "demo passport api",
api: "/v1/auth/login",
type: "passportProvider",
status: 200
}
http://192.168.68.152:8086/passport
返回json內容如下:
{
msg: "后台服務passport",
api: "/passport",
type: "autoNacosConfig",
status: 200
}
2.4.4.4 驗證配置中心修改配置功能
通過nacos頁面修改配置文件provider-passport-config.yaml的內容后,再次調用后台服務接口,可以看出我們通過配置中心修改配置以后並不需要重啟服務,配置即時生效。
#修改msg字段
data:
msg: '后台服務passport-修改配置測試'
再次調用接口http://192.168.68.152:8086/passport
{
msg: "后台服務passport-修改配置測試",
api: "/passport",
type: "autoNacosConfig",
status: 200
}
注意:並不是所有的配置可以在不重啟服務的情況下生效,比如數據庫。
查看passport服務日志可以看到配置變更以后重新生效的過程
如果能夠使用nacos注冊到注冊中心則使用臨時實例,否則使用永久實例
類型 | 服務端 | 客戶端 |
---|---|---|
主動發送 | 配置文件發送,統一更新 | 發送心跳 |
被動接受 | 心跳信息 | 配置文件 |
客戶端:
2020-08-27 09:50:24.077 INFO 20140 --- [ing.beat.sender] com.alibaba.nacos.client.naming : [BEAT] [] [] send beat to server: {"cluster":"DEFAULT","dom":"provider-passport","ip":"192.168.68.152","metadata":{"preserved.register.source":"SPRING_CLOUD","content":"/"},"port":8086,"weight":1.0}
企業部署nacos注冊中心部署的建議:
- 幾個環境幾個注冊中心(開發環境1台機器1個注冊中心,生產環境3台機器(集群)1個注冊中心,測試環境1台機器1個注冊中心),幾個環境幾個配置文件(比如passport-config-dev.yaml,passport-config-test.yaml,passport-config-prod.yaml)
- 1個配置中心,不同的ns(不建議)
- tomcat瓶頸優化的方法:1.橫向擴展,增加容器的數量。2.代碼優化修改並發連接數。
3.4.5 運行消費者consumer-feign-passport服務
3.4.5.1 運行消費者feign服務
java -Dspring.cloud.nacos.discovery.server-addr=192.168.68.152:8848 \
-Dspring.cloud.nacos.config.server-addr=192.168.68.152:8848 \
-jar consumer-feign-passport-0.0.1-SNAPSHOT.jar
3.4.5.2 服務注冊
再次通過nacos頁面查看服務注冊情況
3.4.5.3 訪問消費者Feign服務接口
http://192.168.68.152:9092/v1/auth/login
{
msg: "demo passport api",
api: "/v1/auth/Feign controller",
type: "feign",
status: 200
}
http://192.168.68.152:9092/passport
{
msg: "后台服務passport-修改配置測試",
api: "/passport",
type: "feignPassport",
status: 200
}
3.4.6 運行消費者consumer-passport服務
3.4.6.1 運行消費者consumer-passport服務
java -Dspring.cloud.nacos.discovery.server-addr=192.168.68.152:8848 \
-Dspring.cloud.nacos.config.server-addr=192.168.68.152:8848 \
-jar consumer-passport-0.0.1-SNAPSHOT.jar
3.4.6.2 服務注冊
通過nacos頁面或者從服務日志可以看到注冊成功
2020-08-27 10:41:27.177 INFO 21027 --- [ main] o.s.c.a.n.registry.NacosServiceRegistry : nacos registry, consumer-passport 192.168.68.152:9091 register finished
3.4.6.3 接口測試
http://192.168.68.152:9091/v1/auth/login
{
msg: "demo passport restTemplate /v1/auth/login api",
api: "{"msg":"demo passport api","api":"/v1/auth/consumer-passport","type":"passportProvider","status":200}",
type: "restTemplatePassport",
status: 200
}
http://192.168.68.152:9091/passport
{
msg: "demo passport restTemplate /passport api",
api: "{"msg":"后台服務passport-修改配置測試","api":"/passport","type":"autoNacosConfig","status":200}",
type: "restTemplatePassport",
status: 200
}
3.4.7 兩種消費者調用的區別是什么
restTemplate和Feign的區別
在spring cloud 中有兩種服務調用方式,一種是ribbon+restTemplate ,另一種是feign。相對來說,feign因為注解使用起來更簡便。而restTemplate需要我們自定義一個RestTemplate,手動注入,並設置成LoadBalance。
內部調用:(內網相通)使用feign調用,調用方式為http://服務名/接口地址,比如:http://provider-passport/passport
跨地址/區域調用:(走外網調用)使用restTemplate調用,調用方式為http://服務IP地址/服務名稱/接口地址,比如:http://192.168.68.152:8086/passport
我們在Java項目中調用接口有四種方式,分別是:
Httpclient
Okhttp
Httpurlconnection
RestTemplate
從消費者服務接口返回的內容與從passport提供者接口的內容一致,原理是訪問消費者接口反向代理到提供者接口,獲取返回內容。為什么要這么做的原因是如果后台有多個提供者的時候,消費客feign提供了負載均衡的作用。
3.4.8 運行網關服務
3.4.8.1 運行網關gateway服務
java -Dspring.cloud.nacos.discovery.server-addr=192.168.68.152:8848 \
-Dspring.cloud.nacos.config.server-addr=192.168.68.152:8848 \
-jar gateway-0.0.1-SNAPSHOT.jar
3.4.8.2 注冊服務
同樣的在nacos頁面或者服務啟動日志中可以看到服務注冊成功信息
2020-08-27 11:19:37.475 INFO 22094 --- [ main] o.s.c.a.n.registry.NacosServiceRegistry : nacos registry, spring-cloud-gateway 192.168.68.152:9000 register finished
3.4.8.3 接口測試
通過gateway訪問后台服務
通過consumer-feign-passport訪問后台服務/v1/auth/login
正常請求feign調用
http://192.168.68.152:9000/consumer-feign-passport/v1/auth/login?token=1231
{
msg: "demo passport api",
api: "/v1/auth/Feign controller",
type: "feign",
status: 200
}
http://192.168.68.152:9000/consumer-feign-passport/passport?token=123123
{
msg: "后台服務passport-修改配置測試",
api: "/passport",
type: "feignPassport",
status: 200
}
正常請求restTemplate調用
http://192.168.68.152:9000/consumer-passport/v1/auth/login?token=122222
{
msg: "demo passport restTemplate /v1/auth/login api",
api: "{"msg":"demo passport api","api":"/v1/auth/consumer-passport","type":"passportProvider","status":200}",
type: "restTemplatePassport",
status: 200
}
http://192.168.68.152:9000/consumer-passport/passport?token=123123
{
msg: "demo passport restTemplate /passport api",
api: "{"msg":"后台服務passport-修改配置測試","api":"/passport","type":"autoNacosConfig","status":200}",
type: "restTemplatePassport",
status: 200
}
3.4.9 鑒權功能
我們在訪問網關接口的時候,需要帶token才能正常訪問,否則會報非法請求
http://192.168.68.152:9000/consumer-feign-passport/v1/auth/login
{
code: 401,
cause: "Token字符串為空!",
message: "非法請求"
}
3.5 注冊中心服務列表
服務必須存在與服務列表才能被調用
3.6 微服務治理
3.6.1 服務熔斷處理
在正常服務訪問的情況下,后台服務不可用的情況下,或出現500的錯誤,返回客戶端很不友好,並且接口之間的調試比較困難,因為不知道后台服務發生了什么錯誤。
將后台passport服務停掉模擬后台服務掛掉不可訪問的狀態,分別查看有服務熔斷和沒有服務熔斷的接口返回
有服務熔斷的返回:
http://192.168.68.152:9000/consumer-feign-passport/v1/auth/login?token=122222
{
msg: "feign 調用后台認證服務接口(/v1/auth/login)失敗, 服務熔斷處理.",
type: "feignFallBack",
status: 400
}
http://192.168.68.152:9000/consumer-feign-passport/passport?token=123123
{
msg: "調用后台認證接口(/passport)失敗, 服務熔斷處理.",
type: "feignFallBack",
status: 400
}
沒有服務熔斷的返回
http://192.168.68.152:9000/consumer-passport/v1/auth/login?token=122222
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Thu Aug 27 14:13:04 CST 2020
There was an unexpected error (type=Internal Server Error, status=500).
No message available
3.6.2 服務熔斷的實現方法
- 代碼實現
- 集群實現(服務網格)
為什么會熔斷?
- 服務調用超時
- 服務異常宕機
- 優雅處理異常
3.6.3 調用鏈
介紹
http://skywalking.apache.org/zh/blog/2019-03-29-introduction-of-skywalking-and-simple-practice.html
使用APM分析接口調用過程
注意:
- 采樣率與損耗(默認是-1,每個3秒)
- 后台存儲保存數量h2(5000條)
服務端啟動
mkdir /root/apm && cd /root/apm
wget https://archive.apache.org/dist/skywalking/6.1.0/apache-skywalking-apm-6.1.0.tar.gz
tar zxvf apache-skywalking-apm-6.1.0.tar.gz
cd apache-skywalking-apm-bin/bin
sh startup.sh
正常啟動以后通過頁面訪問http://192.168.68.152:8080/
用戶名:admin
密碼:admin
配置文件 application.yml
#啟用ES的時候取消以下注釋
# clusterNodes: ${SW_STORAGE_ES_CLUSTER_NODES:localhost:9200}
# indexShardsNumber: ${SW_STORAGE_ES_INDEX_SHARDS_NUMBER:2}
# indexReplicasNumber: ${SW_STORAGE_ES_INDEX_REPLICAS_NUMBER:0}
# bulkActions: ${SW_STORAGE_ES_BULK_ACTIONS:2000} # Execute the bulk every 2000 requests
# bulkSize: ${SW_STORAGE_ES_BULK_SIZE:20} # flush the bulk every 20mb
# flushInterval: ${SW_STORAGE_ES_FLUSH_INTERVAL:10} # flush the bulk every 10 seconds whatever the number of requests
# concurrentRequests: ${SW_STORAGE_ES_CONCURRENT_REQUESTS:2} # the number of concurrent requests
# metadataQueryMaxSize: ${SW_STORAGE_ES_QUERY_MAX_SIZE:5000}
# segmentQueryMaxSize: ${SW_STORAGE_ES_QUERY_SEGMENT_SIZE:200}
#注釋掉h2模式配置
h2:
driver: ${SW_STORAGE_H2_DRIVER:org.h2.jdbcx.JdbcDataSource}
url: ${SW_STORAGE_H2_URL:jdbc:h2:mem:skywalking-oap-db}
user: ${SW_STORAGE_H2_USER:sa}
metadataQueryMaxSize: ${SW_STORAGE_H2_QUERY_MAX_SIZE:5000}
服務端啟動
拷貝agent目錄到需要監測的設備上,本次為單機部署,故只需要將agent目錄拷貝到指定目錄即可,當然也可以不拷貝到指定路徑,但是在啟動服務的時候需要指定agent所在的絕對路徑。
cp -r agent/ /root/springcloud/
啟動provider passport服務
java -Dspring.cloud.nacos.discovery.server-addr=192.168.68.152:8848 \
-Dspring.cloud.nacos.config.server-addr=192.168.68.152:8848 \
-javaagent:agent/skywalking-agent.jar \
-Dskywalking.agent.service_name=provide-passport \
-Dskywalking.collector.backend_service=192.168.68.152:11800 \
-jar provider-passport-0.0.1-SNAPSHOT.jar
啟動服務日志可以看到加載agent的信息
DEBUG 2020-08-27 16:34:03:616 main AgentPackagePath : The beacon class location is jar:file:/root/springcloud/agent/skywalking-agent.jar!/org/apache/skywalking/apm/agent/core/boot/AgentPackagePath.class.
INFO 2020-08-27 16:34:03:619 main SnifferConfigInitializer : Config file found in /root/springcloud/agent/config/agent.config.
...
2020-08-27 16:36:37.101 INFO 1080 --- [ main] o.s.c.a.n.registry.NacosServiceRegistry : nacos registry, provider-passport 192.168.68.152:8086 register finished
測試訪問passport服務,查看skywalking是否可以獲取到訪問信息
for i in `seq 10000` ;do curl 192.168.68.152:8086/passport ;echo "";done
從頁面查看信息
同樣的操作我們將消費者服務和網關服務也加入到skywalking的監測下
重新啟動feign服務
java -Dspring.cloud.nacos.discovery.server-addr=192.168.68.152:8848 \
-Dspring.cloud.nacos.config.server-addr=192.168.68.152:8848 \
-javaagent:agent/skywalking-agent.jar \
-Dskywalking.agent.service_name=consumer-feign-passport \
-Dskywalking.collector.backend_service=192.168.68.152:11800 \
-jar consumer-feign-passport-0.0.1-SNAPSHOT.jar
重新啟動restTemplate consumer-passport服務
java -Dspring.cloud.nacos.discovery.server-addr=192.168.68.152:8848 \
-Dspring.cloud.nacos.config.server-addr=192.168.68.152:8848 \
-javaagent:agent/skywalking-agent.jar \
-Dskywalking.agent.service_name=consumer-passport \
-Dskywalking.collector.backend_service=192.168.68.152:11800 \
-jar consumer-passport-0.0.1-SNAPSHOT.jar
重新啟動gateway服務
java -Dspring.cloud.nacos.discovery.server-addr=192.168.68.152:8848 \
-Dspring.cloud.nacos.config.server-addr=192.168.68.152:8848 \
-javaagent:agent/skywalking-agent.jar \
-Dskywalking.agent.service_name=gateway \
-Dskywalking.collector.backend_service=192.168.68.152:11800 \
-jar gateway-0.0.1-SNAPSHOT.jar
將上述4個服務全部重啟以后,再次在頁面查看,可以看到skywalking已經監測到這4個服務。
測試服務
- 對feien進行模擬訪問測試
http://192.168.68.152:9000/consumer-feign-passport/v1/auth/login?token=122222
for i in `seq 10000` ;do curl http://192.168.68.152:9000/consumer-feign-passport/passport?token=123123 ;echo "";done
{"msg":"后台服務passport-修改配置測試","api":"/passport","type":"feignPassport","status":200}
{"code":403,"msg":"服務限流, 請立刻停止非法訪問"}
{"code":403,"msg":"服務限流, 請立刻停止非法訪問"}
{"code":403,"msg":"服務限流, 請立刻停止非法訪問"}
...
- 對restTemplate passport進行模擬訪問測試
for i in `seq 10000` ;do curl http://192.168.68.152:9000/consumer-passport/v1/auth/login?token=122222 ;echo "";done
for i in `seq 10000` ;do curl http://192.168.68.152:9000/consumer-passport/passport?token=123123 ;echo "";done
{"msg":"demo passport restTemplate /v1/auth/login api","api":"{\"msg\":\"demo passport api\",\"api\":\"/v1/auth/consumer-passport\",\"type\":\"passportProvider\",\"status\":200}","type":"restTemplatePassport","status":200}
{"code":403,"msg":"服務限流, 請立刻停止非法訪問"}
{"code":403,"msg":"服務限流, 請立刻停止非法訪問"}
{"code":403,"msg":"服務限流, 請立刻停止非法訪問"}
...
這里顯示的內容是因為我們做了服務限流。
高並發系統中有三把利器用來保護系統:緩存、降級和限流。限流的目的是為了保護系統不被大量請求沖垮,通過限制請求的速度來保護系統。在電商的秒殺活動中,限流是必不可少的一個環節。
3.7 消費者調用
feign調用
restTemplate調用
3.7.1 什么是Feign
Feign是模板化的http客戶端,可以幫助我們更快捷,優雅的調用http API(Rest)
Spring Cloud 對Feign進行了增強,使Feign支持Spring MVC注解,並整合了Ribbon和Eureka,從而讓Feign的使用更加方便
3.7.2 為什么需要Feign
- 前面已經提到在消費后台服務的時候已經存下RestTemplate服務,為什么還需要Feign?
- Feign的目的是盡量的減少資源和代碼來實現和HTTP API的連接(HTTP客戶端封裝)內網與外網調用。
3.7.3 什么是restTemplate
RestTemplate是Spring提供的額用於訪問Rest服務的客戶端,它提供了多種便捷訪問遠程http服務的方法,能夠大大提高客戶端的編寫效率。
當后台服務,比如新聞資訊服務啟動以后,用戶需要訪問,那么需要通過consumer訪問,在本實例中consumer獨立為一個服務,在實際的應用開發阿忠,會與網關集成為一個整體的服務。
3.7.4 Frign與restTemplate對比
代碼框架實現反向代理+負載均衡
比較類型 | restTemplate+ribbon | Feign(自帶ribbon) |
---|---|---|
可讀性,可維護性 | 欠佳(無法從URL直觀了解這個遠程調用過程) | 極佳 |
開發體驗 | 欠佳(拼接URL) | 極佳(代碼整潔) |
風格一致性 | 一般(本地API調用和restTemplate調用的代碼風格不同) | 極佳(完全一致,不點開feign的接口根本不會察覺這是一個遠程調用而非本地api調用) |
性能 | 較好 | 中等(性能是restTemplate的50%左右,如果為feign配置連接池,性能可提升15%左右) |
靈活性 | 極佳 | 中等(內置功能能滿足大多數項目的需求) |
3.8 網關調用過程
- 把用戶需要請求的URL地址通過路由的方式轉發到后台的服務,同時也實現鑒權的功能。
網關位置
3.8.1 網關調用restTemplate接口過程
- 負載均衡根據調度算法調度到網關系統
- 網關系統接收請求以后,如果消費者(restTemplate)返回正確,那么狀態值為200,內容里面會包括provider返回的Json內容。
- 消費者接收請求以后,如果服務提供者(Provider)返回正確,那么狀態值為200.
3.8.2 網關調用Feign接口過程
- 負載均衡根據調度算法調度到網關系統
- 網關系統接收請求以后,如果消費者(feign)返回正確,那么狀態值為200,內容里面會包括provider返回的Json內容。
- 消費者接收請求以后,如果服務提供者(provider)返回正確,那么狀態值為200.
調用過程於restTemplate相同,只是feign多封裝了一層http client。
3.9 小結
- 所有服務注冊到注冊中心,並且每個服務可以展示多個實例
- 注冊實例分為:臨時實例與永久實例
- 網關:負責前台請求到后台的調用,起鑒權作用(配置文件路由/動態路由)
- Provider:后台真正的服務提供者
- Feign:網關通過此服務消費Provider
- restTemplate:網關通過此服務消費Provider
- 配置中心:在配置中心修改配置以后,可以實時通知到客戶端,並且可以回滾配置到上一個版本。