手把手教你学Dapr - 4. 服务调用
介紹
通過使用服務調用,您的應用程序可以使用標準的gRPC或HTTP協議與其他應用程序可靠、安全地通信。
為什么不直接用HttpClientFactory呢
先問幾個問題:
如何發現和調用不同服務的方法
如何安全地調用其他服務,并對方法應用訪問控制
如何處理重試和瞬態錯誤
如何使用分布式跟蹤指標來查看調用圖來診斷生產中的問題
此時你會發現這些事情HttpClientFactory沒有幫你完成,而在微服務中這些又是必不可少的能力,接下來看看服務調用都做了什么
服務調用如何工作的
先看一下兩個服務之間的調用順序
服務A 向服務B發起一個HTTP/gRPC的調用。調用轉到了本地的Dapr sidecar
Dapr使用名稱解析組件發現服務B的位置
Dapr 將消息轉發至服務 B的 Dapr sidecar
注: Dapr sidecar之間的所有調用都通過gRPC來提高性能。僅服務與 Dapr sidecar之間的調用可以是 HTTP或gRPC
服務B 的 Dapr sidecar將請求轉發至服務B 上的特定端點 (或方法) 。服務B 隨后運行其業務邏輯代碼
服務B 發送響應給服務A。響應將轉至服務B 的Dapr sidecar
Dapr 轉發響應至服務A 的 Dapr sidecar
服務 A 接收響應
命名空間作用域
默認情況下,調用同一個命名空間的其他服務可以直接使用AppID(假設是:nodeapp)
localhost:3500/v1.0/invoke/nodeapp/method/neworder服務調用也支持跨命名空間調用,在所有受支持的宿主平臺上,Dapr AppID遵循FQDN格式,其中包括目標命名空間。
FQDN:(Fully Qualified Domain Name)全限定域名:同時帶有主機名和域名的名稱。(通過符號“.”)
例如:主機名是bigserver,域名是mycompany.com,那么FQDN就是bigserver.mycompany.com
? ?注:FQDN是通過符號.來拼接域名的,這也就解釋了AppID為什么不能用符號.,這里不記住的話,應該會有不少小伙伴會踩坑
? ? ? ? ? ?比如.net開發者習慣用 A.B.C 來命名項目,但AppID需要把.換成-且所有單詞最好也變成小寫 (a-b-c),建議把它變成約定遵守
比如調用命名空間:production,AppID:nodeapp
localhost:3500/v1.0/invoke/nodeapp.production/method/neworder這在K8s集群中的跨名稱空間調用中特別有用 ?
服務間安全性
通過托管平臺上的相互(mTLS)身份驗證,包括通過Dapr Sentry服務的自動證書轉移,可以確保Dapr應用程序之間的所有調用的安全。下圖顯示了自托管應用程序的情況。
訪問控制
應用程序可以控制哪些其他應用程序可以調用它們,以及通過訪問策略授權它們做什么。這使您能夠限制具有個人信息的敏感應用程序不被未經授權的應用程序訪問,并結合服務到服務的安全通信,提供了軟多租戶部署。?
具體的訪問控制后續章節會介紹
重試
在調用失敗和瞬態錯誤的情況下,服務調用執行自動重試,并在回退時間段內執行。
注:自動重試,默認是開啟的,可以關。但如果不關且業務又不支持冪等是很危險的。建議服務的接口要設計支持冪等,這在微服務里也是一個標配的選擇。
導致重試的錯誤有: ?
網絡錯誤,包括端點不可用和拒絕連接。?
由于在調用/被調用的Dapr sidecars上更新證書而導致的身份驗證錯誤。?
每次呼叫重試的回退間隔為1秒,最多為3次。通過gRPC與目標Sidecar連接的超時時間為5秒
可插拔的服務發現
Dapr可以在各種托管平臺上運行。為了啟用服務發現和服務調用,Dapr使用可插拔的名稱解析組件。例如,K8s名稱解析組件使用K8s DNS服務來解析集群中運行的其他應用程序的位置。自托管機器可以使用mDNS名稱解析組件。Consul名稱解析組件可以在任何托管環境中使用,包括K8s或自托管環境
劃重點,自托管機器使用mDNS,在開發環境中后面文章會推薦VS上的無縫開發體驗,就是基于mDNS的
但它有點點小問題,我們已經解決了。你只需要像開發一個控制臺程序一樣,基于Minimal API開心的F5就可以了
建議還沒有了解Minimal API的小伙伴可以研究起來了,真香
使用mDNS進行輪詢負載均衡
一圖勝千言,就使用mDNS輪著調用
可觀測性的跟蹤和指標
默認情況下,將跟蹤應用程序之間的所有調用,并收集指標,以提供應用程序的洞察力和診斷,這在生產場景中尤其重要。這為您提供了服務之間調用的調用圖和指標。?
服務調用API和gRPC代理
pythonapp 通過Dapr sidecar調用nodeapp,通過服務調用的API及gRPC代理依然是上面見到的那個調用流程,做到了語言無關
使用HTTP調用服務
創建Assignment.Server
創建ASP.NET Core空項目,并修改launchSettings.json,讓啟動HTTP的啟動端口變為5000
profiles.Assignment.Server.applicationUrl 的值改為 "https://localhost:6000;http://localhost:5000"
修改Program.cs文件
var builder = WebApplication.CreateBuilder(args); var app = builder.Build();app.MapPost("/", () => Console.WriteLine("Hello!"));app.MapGet("/Hello1", () => {Console.WriteLine("Hello World1!");return $"\"Hello World1!\""; });app.MapPost("/Hello2", () => Console.WriteLine("Hello World2!"));app.Map("/Hello3", () => Console.WriteLine("Hello World3!"));app.Run();此時一共有4個服務
/ :Post方法,打印Hello!
/Hello1:Get方法,打印Hello World1!,返回Hello World1!
注:返回的類型要是Json字符串,方便SDK反序列化
/Hello2:Post方法,打印Hello World2!
/Hello3:不帶后綴表示適配所有方法,打印Hello World3!
先使用Dapr CLI來驗證一下
運行Assignment.Server:在目錄dapr-study-room\Assignment04\Assignment.Server打開命令行工具,并執行下面命令
dapr run --app-id assignment-server --app-port 5000 dotnet watch細心的小伙伴應該可以發現與上一篇的命令有一點點不同,dontet run變成了dotnet watch,這樣會開啟熱重載,方便調試
調用服務:再打開一個新的命令行工具,并執行下面命令
dapr invoke --app-id assignment-server --method / dapr invoke --app-id assignment-server --method Hello1 dapr invoke --app-id assignment-server --method Hello2 dapr invoke --app-id assignment-server --method Hello3可以發現4個命令都調用成功了,但是Assignment.Server輸出結果有點意外
== APP == Hello! == APP == Hello World2! == APP == Hello World3!是的,沒有Hello World1!,那怎么辦呢?我們把Hello1的命令改一下
dapr invoke --app-id assignment-server --method Hello1 --verb GETinvoke調用的輸出除了App invoked successfully以外還多了一行Hello World1!
與此同時Assignment.Server的輸出正確了
== APP == Hello World1!除此之外invoke還有一些參數,比如--data,--data-file,喜歡研究Dapr CLI的小伙伴可以繼續嘗試。不過一般情況下用SDK就可以了
創建Assignment.Client
HTTP服務調用
創建控制臺應用程序項目,使用NuGet包管理器添加Dapr.Client SDK,并修改Program.cs文件
using Dapr.Client;var appId = "assignment-server";var client = new DaprClientBuilder().Build();await client.InvokeMethodAsync(appId, "/");var resp = await client.InvokeMethodAsync<string>(HttpMethod.Get, appId, "Hello1"); Console.WriteLine($"Hello1 Response: {resp}");await client.InvokeMethodAsync(appId, "Hello2");await client.InvokeMethodAsync(appId, "Hello3");看幾個細節
DaprClient是從DaprClinetBuilder Build出來的
還有一種方式使用DaprClient,通過DI
首先都是需要添加Dapr.AspNetCore NuGet包
然后開始有分支了,如果是以前Web API的方式可以在Startup.cs文件ConfigureServices方法加入一行代碼
services.AddControllers().AddDapr();如果使用Minimal API默認是沒有Controllers的,那可以在var builder = WebApplication.CreateBuilder(args); 之后加入一行代碼
builder.Services.AddDaprClient();成功的注入進來了,在構造函數或者[FromServices]里愉快的玩耍吧
HttpMethod.Post 的我都沒有指定,默認就是Post
HttpMethod.Get的時候,返回值會自動用Json反序列化
不喜歡Json?可以通過 DaprClient.CreateInvokeHttpClient 構造 HttpClient,聰明的你肯定知道后面怎么辦了
注:
Minimal API雖香,但新,所以不是所有功能都支持,比如從參數中直接映射狀態管理,要等Minimal API支持Model Binder以后且SDK也同步支持了才可以
DaprClient是TCP的,也是線程安全的,可以大膽的復用,如果不用DI的話不需要頻繁構建DaprClient
驗證調用成功
使用命令行工具打開目錄dapr-study-room\Assignment04\Assignment.Client,然后執行命令
dotnet run如果你不是用VS Code終端的PowerShell執行dapr run就可能遇到下面的錯誤
即便你沒有遇到也建議了解一下如何支持非默認端口
An exception occurred while invoking method: '/' on app-id: 'assignment-server'---> System.Net.Http.HttpRequestException: 由于目標計算機積極拒絕,無法連接。 (127.0.0.1:3500)---> System.Net.Sockets.SocketException (10061): 由于目標計算機積極拒絕,無法連接。因為上面使用dapr run的時候沒有指定dapr http port,而默認client訪問的是3500端口
解決的辦法有兩種:
修改Assignment.Server啟動參數,增加--dapr-http-port 3500,這個方法治標不治本,因為將來我們可能啟動多個服務
dapr run --app-id assignment-server --app-port 5000 --dapr-http-port 3500 dotnet watch修改Assignment.Client的環境變量
首先執行dapr list查看端口,以下面為例,HTTP PORT是51460
APP ID ? ? ? ? ? ? HTTP PORT ?GRPC PORT ?APP PORT ?COMMAND ? ? ? AGE ?CREATED ? ? ? ? ? ? ?PID
assignment-server ?51460 ? ? ?51461 ? ? ?5000 ? ? ?dotnet watch ?7s ? 2021-10-29 14:13.49 ?11676
修改Assignment.Client的啟動參數,注意把51460換成你自己的端口,使用PowerShell執行下面命令
$Env:DAPR_HTTP_PORT = 51460 dotnet run再執行一次dotnet run就可以看到正確的輸出結果了
Hello1 Response: Hello World1!gRPC服務調用
篇幅太長了,舉一反三吧。就是調用InvokeMethodGrpcAsync,然后dapr-http-port換成dapr-grpc-port,DAPR_HTTP_PORT換成DAPR_GRPC_PORT
查看跟蹤
還記得dapr init的時候docker里有個zipkin吧,通過zipkin可以看一下調用跟蹤,通過瀏覽器打開下面地址
http://localhost:9411/
此時頁面是空的
根據步驟操作一下就可以看到了
隨便點開一行數據尾部的SHOW,就可以看到調用詳情
本章源碼
Assignment04
https://github.com/doddgu/dapr-study-room
我們正在行動,新的框架、新的生態
我們的目標是自由的、易用的、可塑性強的、功能豐富的、健壯的。
所以我們借鑒Building blocks的設計理念,正在做一個新的框架MASA Framework,它有哪些特點呢?
原生支持Dapr,且允許將Dapr替換成傳統通信方式
架構不限,單體應用、SOA、微服務都支持
支持.Net原生框架,降低學習負擔,除特定領域必須引入的概念,堅持不造新輪子
豐富的生態支持,除了框架以外還有組件庫、權限中心、配置中心、故障排查中心、報警中心等一系列產品
核心代碼庫的單元測試覆蓋率90%+
開源、免費、社區驅動
還有什么?我們在等你,一起來討論
經過幾個月的生產項目實踐,已完成POC,目前正在把之前的積累重構到新的開源項目中
目前源碼已開始同步到Github(文檔站點在規劃中,會慢慢完善起來):
MASA.BuildingBlocks
MASA.Contrib
MASA.Utils
MASA.EShop
BlazorComponent
MASA.Blazor
QQ群:7424099
微信群:加技術運營微信(MasaStackTechOps),備注來意,邀請進群
總結
以上是生活随笔為你收集整理的手把手教你学Dapr - 4. 服务调用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 互联网巨头基于全球产业链打造ARM CP
- 下一篇: 手把手教你学Dapr - 2. 必须知道