分布式应用框架 Dapr
微服務架構已成為構建云原生應用程序的標準,微服務架構提供了令人信服的好處,包括可伸縮性,松散的服務耦合和獨立部署,但是這種方法的成本很高,需要了解和熟練掌握分布式系統。為了使用所有開發人員能夠使用任何語言和任何框架輕松地構建便攜式微服務應用程序,無論是開發新項目還是遷移現有代碼
Dapr 介紹
Github:??https://github.com/dapr/dapr
Dapr是一種可移植的,事件驅動的,無服務器運行時,用于構建跨云和邊緣的分布式應用程序。
Distributed Application Runtime. An event-driven, portable runtime for building microservices on cloud and edge.
其中提到了多語言和多開發者框架,我認為這是他選擇的通過通信共享信息,即?HTTP?和?GRPC?支持多語言等特性。微軟想通過這個設定一個構建微服務應用的規則。從根本上確立你開發的每一個應用的獨立性。賦能每個開發者,為了使Dapr對于不同的語言更加方便,它還包括針對Go,Java,JavaScript,.NET和Python的語言特定的SDK。這些SDK通過類型化的語言API(而不是調用http / gRPC API)公開了Dapr構建塊中的功能,例如保存狀態,發布事件或創建actor。這使開發人員可以使用他們選擇的語言編寫無狀態和有狀態功能以及參與者的組合。并且由于這些SDK共享Dapr運行時,您甚至可以獲得跨語言的actor和功能支持!
Dapr還可以與任何開發人員框架集成。例如,在Dapr .NET SDK中,您將找到ASP.NET?Core集成,該集成帶來了可響應其他服務的發布/訂閱事件的狀態路由控制器,從而使ASP.NET?Core成為構建微服務Web應用程序的更好框架。?
不過需要注意的是Dapr目前正處于Alpha階段, 今天剛發布了0.2版本。在v1.0穩定版本發布之前,建議不要用于生產環境。?
下面進行一個 QuickStart
環境
Install?Docker(微服務已經離不開容器化了)
Install?Dapr CLI
Install?.Net Core SDK 3.0
在Windows 上通過Powershell 安裝:
powershell -Command "iwr -useb https://raw.githubusercontent.com/dapr/cli/master/install/install.ps1 | iex"然后把 c:\dapr 添加到環境變量 PATH運行dapr命令,檢查輸出是否正常C:\workshop\Github\dotnet-sdk>dapr --help
???????? __
???? ____/ /___ _____? _____
??? / __? / __ '/ __ \/ ___/
?? / /_/ / /_/ / /_/ / /????
?? \__,_/\__,_/ .___/_/
?????????????? /_/
======================================================
A serverless runtime for hyperscale, distributed systems
Usage:
?? dapr [command]
Available Commands:
?? help??????? Help about any command
?? init??????? Setup dapr in Kubernetes or Standalone modes
?? list??????? List all dapr instances
?? publish???? publish an event to multiple consumers
?? run???????? Launches dapr and your app side by side
?? send??????? invoke a dapr app with an optional payload
?? stop??????? Stops a running dapr instance and its associated app
?? uninstall?? removes a dapr installation
Flags:
?? -h, --help????? help for dapr
?????? --version?? version for dapr
Use "dapr [command] --help" for more information about a command.
| 示例 | 描述 |
| 1. Actor | Demonstrates creating virtual actors that encapsulate code and state. Also see docs in this repo for a tutorial. |
| 2. ASP.NET Core | Demonstrates ASP.NET Core integration with Dapr by create Controllers and Routes. |
| 3. gRPC client | The gRPC client sample shows how to make Dapr calls to publish events, save state, get state and delete state using a gRPC client. |
例子中主 我們使用?Dapr?的交互。Dapr通過?Runtime
提供 Dapr API 給多語言調用。
提供 狀態管理 By state stores
/// <summary>
? /// Sample showing Dapr integration with controller.
? /// </summary>
? [ApiController]
? public class SampleController : ControllerBase
? {
????? /// <summary>
????? /// Gets the account information as specified by the id.
????? /// </summary>
????? /// <param name="account">Account information for the id from Dapr state store.</param>
????? /// <returns>Account information.</returns>
????? [HttpGet("{account}")]
????? public ActionResult<Account> Get(StateEntry<Account> account)
????? {
????????? if (account.Value is null)
????????? {
????????????? return this.NotFound();
????????? }
???????? return account.Value;
????? }
???? /// <summary>
????? /// Method for depositing to account as psecified in transaction.
????? /// </summary>
????? /// <param name="transaction">Transaction info.</param>
????? /// <param name="stateClient">State client to interact with dapr runtime.</param>
????? /// <returns>A <see cref="Task{TResult}"/> representing the result of the asynchronous operation.</returns>
????? [Topic("deposit")]
????? [HttpPost("deposit")]
????? public async Task<ActionResult<Account>> Deposit(Transaction transaction, [FromServices] StateClient stateClient)
????? {
????????? var state = await stateClient.GetStateEntryAsync<Account>(transaction.Id);
????????? state.Value ??= new Account() { Id = transaction.Id, };
????????? state.Value.Balance += transaction.Amount;
????????? await state.SaveAsync();
????????? return state.Value;
????? }
???? /// <summary>
????? /// Method for withdrawing from account as specified in transaction.
????? /// </summary>
????? /// <param name="transaction">Transaction info.</param>
????? /// <param name="stateClient">State client to interact with dapr runtime.</param>
????? /// <returns>A <see cref="Task{TResult}"/> representing the result of the asynchronous operation.</returns>
????? [Topic("withdraw")]
????? [HttpPost("withdraw")]
????? public async Task<ActionResult<Account>> Withdraw(Transaction transaction, [FromServices] StateClient stateClient)
????? {
????????? var state = await stateClient.GetStateEntryAsync<Account>(transaction.Id);
???????? if (state.Value == null)
????????? {
????????????? return this.NotFound();
????????? }
???????? state.Value.Balance -= transaction.Amount;
????????? await state.SaveAsync();
????????? return state.Value;
????? }
? }
Dapr 運行.NET 應用程序
演示Dapr的服務調用,在終端中切換到項目目錄,然后使用dapr啟動應用
C:\workshop\Github\dotnet-sdk\samples\AspNetCore\ControllerSample>dapr run --app-id routing --app-port 5000 dotnet run????
Starting Dapr with id routing. HTTP Port: 61102. gRPC Port: 61103
You're up and running! Both Dapr and your app logs will appear here.
注意:?以上dapr run命令,通過app-id指定了應用的ID,通過app-port指定了應用的端口(webapi默認使用5000作為http端口),后跟dotnet run命名啟動當前項目。可參考Dapr文檔服務調用
后臺運行的?CLI?命令,這里是前臺打印的日志, 注意到 .NET?App?在指定的?5000?端口運行,同時還有狀態存儲的?redis?在?6379?端口運行
== DAPR == time="2019-11-16T18:33:22+08:00" level=info msg="starting Dapr Runtime -- version 0.2.0 -- commit c75b11
1-dirty"
???? == DAPR == time="2019-11-16T18:33:22+08:00" level=info msg="log level set to: info"
== DAPR == time="2019-11-16T18:33:22+08:00" level=info msg="standalone mode configured"
== DAPR == time="2019-11-16T18:33:22+08:00" level=info msg="dapr id: routing"
== DAPR == time="2019-11-16T18:33:22+08:00" level=info msg="loaded component messagebus (pubsub.redis)"????????
???? == DAPR == time="2019-11-16T18:33:22+08:00" level=info msg="loaded component statestore (state.redis)"
???? == DAPR == time="2019-11-16T18:33:22+08:00" level=info msg="application protocol: http. waiting on port 5000"
???? == APP == info: Microsoft.Hosting.Lifetime[0]
???? == APP ==?????? Now listening on:?http://localhost:5000
== APP == info: Microsoft.Hosting.Lifetime[0]
== APP ==?????? Application started. Press Ctrl+C to shut down.
???? == APP == info: Microsoft.Hosting.Lifetime[0]
== APP ==?????? Hosting environment: Development
== APP == info: Microsoft.Hosting.Lifetime[0]
== APP ==?????? Content root path: C:\workshop\Github\dotnet-sdk\samples\AspNetCore\ControllerSample
???? == DAPR == time="2019-11-16T18:33:31+08:00" level=info msg="application discovered on port 5000"
???? == DAPR == 2019-11-16 18:33:32.029764 I | redis: connecting to localhost:6379
???? == DAPR == 2019-11-16 18:33:32.036316 I | redis: connected to localhost:6379 (localAddr: [::1]:61164, remAddr:?
[::1]:6379)
???? == DAPR == time="2019-11-16T18:33:32+08:00" level=info msg="actor runtime started. actor idle timeout: 1h0m0s.?
actor scan interval: 30s"
???? == DAPR == time="2019-11-16T18:33:32+08:00" level=info msg="actors: starting connection attempt to placement se
rvice at localhost:6050"
== DAPR == time="2019-11-16T18:33:32+08:00" level=info msg="http server is running on port 61102"
== DAPR == time="2019-11-16T18:33:32+08:00" level=info msg="gRPC server is running on port 61103"
???? == DAPR == time="2019-11-16T18:33:32+08:00" level=info msg="local service entry announced"
== DAPR == time="2019-11-16T18:33:32+08:00" level=info msg="dapr initialized. Status: Running. Init Elapsed 917
6.5164ms"
== DAPR == time="2019-11-16T18:33:32+08:00" level=info msg="actors: established connection to placement service
? at localhost:6050"
== DAPR == time="2019-11-16T18:33:32+08:00" level=info msg="actors: placement order received: lock"
== DAPR == time="2019-11-16T18:33:32+08:00" level=info msg="actors: placement order received: update"
== DAPR == time="2019-11-16T18:33:32+08:00" level=info msg="actors: placement tables updated"
== DAPR == time="2019-11-16T18:33:32+08:00" level=info msg="actors: placement order received: unlock"
== APP == info: System.Net.Http.HttpClient.state.LogicalHandler[100]
== APP ==?????? Start processing HTTP request GET?http://localhost:61102/v1.0/state/17
== APP == info: System.Net.Http.HttpClient.state.ClientHandler[100]
== APP ==?????? Sending HTTP request GET?http://localhost:61102/v1.0/state/17
== APP == info: System.Net.Http.HttpClient.state.ClientHandler[101]
== APP ==?????? Received HTTP response after 2228.2998000000002ms - OK?????
== APP == info: System.Net.Http.HttpClient.state.LogicalHandler[101]???????
== APP ==?????? End processing HTTP request after 2257.3405000000002ms - OK
== APP == info: System.Net.Http.HttpClient.state.LogicalHandler[100]
== APP ==?????? Start processing HTTP request POST?http://localhost:61102/v1.0/state
== APP == info: System.Net.Http.HttpClient.state.ClientHandler[100]
== APP ==?????? Sending HTTP request POST?http://localhost:61102/v1.0/state
== APP == info: System.Net.Http.HttpClient.state.ClientHandler[101]
???? == APP ==?????? Received HTTP response after 67.46000000000001ms - Created
== APP == info: System.Net.Http.HttpClient.state.LogicalHandler[101]
== APP ==?????? End processing HTTP request after 68.0343ms - Created
???? == APP == info: System.Net.Http.HttpClient.state.LogicalHandler[100]
???? == APP ==?????? Start processing HTTP request GET?http://localhost:61102/v1.0/state/17
== APP == info: System.Net.Http.HttpClient.state.ClientHandler[100]
== APP ==?????? Sending HTTP request GET?http://localhost:61102/v1.0/state/17
== APP == info: System.Net.Http.HttpClient.state.ClientHandler[101]
== APP ==?????? Received HTTP response after 5.8247ms - OK
== APP == info: System.Net.Http.HttpClient.state.LogicalHandler[101]
== APP ==?????? End processing HTTP request after 6.268400000000001ms - OK
== APP == info: System.Net.Http.HttpClient.state.LogicalHandler[100]
== APP ==?????? Start processing HTTP request POST?http://localhost:61102/v1.0/state
== APP == info: System.Net.Http.HttpClient.state.ClientHandler[100]
== APP ==?????? Sending HTTP request POST?http://localhost:61102/v1.0/state
== APP == info: System.Net.Http.HttpClient.state.ClientHandler[101]
== APP ==?????? Received HTTP response after 4.5181000000000004ms - Created
== APP == info: System.Net.Http.HttpClient.state.LogicalHandler[101]
== APP ==?????? End processing HTTP request after 4.6208ms - Created
== APP == info: System.Net.Http.HttpClient.state.LogicalHandler[100]
== APP ==?????? Start processing HTTP request GET?http://localhost:61102/v1.0/state/17
== APP == info: System.Net.Http.HttpClient.state.ClientHandler[100]
== APP ==?????? Sending HTTP request GET?http://localhost:61102/v1.0/state/17
== APP == info: System.Net.Http.HttpClient.state.ClientHandler[101]
== APP ==?????? Received HTTP response after 20.2967ms - OK
== APP == info: System.Net.Http.HttpClient.state.LogicalHandler[101]
== APP ==?????? End processing HTTP request after 20.691100000000002ms – OK
為了同時實現可移植性和與現有代碼的輕松集成,Dapr通過http或gRPC提供了標準API。Dapr端口可從Dapr啟動日志中獲取,如以下日志表示Dapr公開的HTTP端口為61102(通過Dapr也可使用gRPC方式進行服務調用)
== DAPR == time="2019-11-16T18:33:32+08:00" level=info msg="http server is running on port 61102"
== DAPR == time="2019-11-16T18:33:32+08:00" level=info msg="gRPC server is running on port 61103"
我們可通過以下地址來調用示例方法,根據Dapr服務調用API規范,其代理調用規則為:
POST/GET/PUT/DELETE http://localhost:<Dapr端口>/v1.0/invoke/<id>/method/<method-name>直接調用:GET http://localhost:5000/17
通過Dapr服務調用: GET http://localhost:61102/v1.0/invoke/routing/method/17?注意: Dapr的服務調用是有dapr sidecar來實現的,在被調用的服務中無需注入任何與dapr相關的代碼。總結
以上是生活随笔為你收集整理的分布式应用框架 Dapr的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: China .NET Conf 2019
- 下一篇: 你可能不知道的 docker 命令的奇淫