Dapr + .NET Core实战(三)状态管理
狀態(tài)管理解決了什么
分布式應(yīng)用程序中的狀態(tài)可能很有挑戰(zhàn)性。例如:
應(yīng)用程序可能需要不同類型的數(shù)據(jù)存儲。
訪問和更新數(shù)據(jù)可能需要不同的一致性級別。
多個用戶可以同時更新數(shù)據(jù),這需要解決沖突。
服務(wù)必須重試?與數(shù)據(jù)存儲交互?時發(fā)生的任何短期暫時性錯誤。
Dapr 狀態(tài)管理解決了這些難題。它簡化了跟蹤狀態(tài),而無需依賴關(guān)系或第三方存儲 SDK?上的學(xué)習(xí)曲線。
工作原理
應(yīng)用程序與 Dapr sidecar 交互,以存儲和檢索鍵/值數(shù)據(jù)。在底層,sidecar API 使用可配置的狀態(tài)存儲組件來保存數(shù)據(jù)。開發(fā)人員可以從不斷增長的受支持狀態(tài)存儲集合中選擇,其中包括 Azure Cosmos DB、SQL Server 和 Cassandra。
可以使用 HTTP 或 gRPC 調(diào)用 API。使用以下 URL 調(diào)用 HTTP API:
http://localhost:<dapr-port>/v1.0/state/<store-name>/<dapr-port>:Dapr 偵聽的 HTTP 端口。
<store-name>:使用的狀態(tài)存儲組件的名稱。
狀態(tài)組件
Dapr支持的組件
為本地自承載開發(fā)初始化時,Dapr 將 Redis 注冊為默認狀態(tài)存儲。下面是默認狀態(tài)存儲配置的示例,配置文件位置為C:\Users\<username>\.dapr\components。記下默認名稱?statestore?:
apiVersion: dapr.io/v1alpha1 kind: Component metadata:name: statestore spec:type: state.redisversion: v1metadata:- name: redisHostvalue: localhost:6379- name: redisPasswordvalue: ""- name: actorStateStorevalue: "true"項目演示
仍然使用 上一篇服務(wù)調(diào)用 的FrontEnd項目,新建StateController
using Dapr; using Dapr.Client;using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging;using System; using System.Collections.Generic; using System.Threading.Tasks;namespace FrontEnd.Controllers {[Route("[controller]")][ApiController]public class StateController : ControllerBase{private readonly ILogger<StateController> _logger;private readonly DaprClient _daprClient;public StateController(ILogger<StateController> logger, DaprClient daprClient){_logger = logger;_daprClient = daprClient;}// 獲取一個值[HttpGet]public async Task<ActionResult> GetAsync(){var result = await _daprClient.GetStateAsync<string>("statestore", "guid");return Ok(result);}//保存一個值[HttpPost]public async Task<ActionResult> PostAsync(){await _daprClient.SaveStateAsync<string>("statestore", "guid", Guid.NewGuid().ToString(), new StateOptions() { Consistency = ConsistencyMode.Strong });return Ok("done");}//刪除一個值[HttpDelete]public async Task<ActionResult> DeleteAsync(){await _daprClient.DeleteStateAsync("statestore", "guid");return Ok("done");}//通過tag防止并發(fā)沖突,保存一個值[HttpPost("withtag")]public async Task<ActionResult> PostWithTagAsync(){var (value, etag) = await _daprClient.GetStateAndETagAsync<string>("statestore", "guid");await _daprClient.TrySaveStateAsync<string>("statestore", "guid", Guid.NewGuid().ToString(), etag);return Ok("done");}//通過tag防止并發(fā)沖突,刪除一個值[HttpDelete("withtag")]public async Task<ActionResult> DeleteWithTagAsync(){var (value, etag) = await _daprClient.GetStateAndETagAsync<string>("statestore", "guid");return Ok(await _daprClient.TryDeleteStateAsync("statestore", "guid", etag));}// 從綁定獲取一個值,健值name從路由模板獲取[HttpGet("frombinding/{name}")]public async Task<ActionResult> GetFromBindingAsync([FromState("statestore", "name")] StateEntry<string> state){return Ok(state.Value);}// 根據(jù)綁定獲取并修改值,健值name從路由模板獲取[HttpPost("withbinding/{name}")]public async Task<ActionResult> PostWithBindingAsync([FromState("statestore", "name")] StateEntry<string> state){state.Value = Guid.NewGuid().ToString();return Ok(await state.TrySaveAsync());}// 獲取多個個值[HttpGet("list")]public async Task<ActionResult> GetListAsync(){var result = await _daprClient.GetBulkStateAsync("statestore", new List<string> { "guid" }, 10);return Ok(result);}// 刪除多個個值[HttpDelete("list")]public async Task<ActionResult> DeleteListAsync(){var data = await _daprClient.GetBulkStateAsync("statestore", new List<string> { "guid" }, 10);var removeList = new List<BulkDeleteStateItem>();foreach (var item in data){removeList.Add(new BulkDeleteStateItem(item.Key, item.ETag));}await _daprClient.DeleteBulkStateAsync("statestore", removeList);return Ok("done");}} }cmd運行
dapr run --dapr-http-port 3501 --app-port 5001 --app-id frontend dotnet .\FrontEnd\bin\Debug\net5.0\FrontEnd.dll可通過postman調(diào)用sidecar的endpoint
?
?查看store存儲中的內(nèi)容
進入容器內(nèi)部
docker exec -it dapr_redis /bin/sh調(diào)用redis-cli
redis-cli查看所有key
keys *可以看到有"frontend||guid"這個key,所以狀態(tài)在redis中存儲中Name的規(guī)則是appName||keyName,這樣可以防止不同app的鍵沖突
我們通過type key查看下這個鍵的類型,可以發(fā)現(xiàn)他是一個hash
127.0.0.1:6379> type frontend||guid hash再通過hgetall key查看他的數(shù)據(jù),發(fā)現(xiàn)有兩個鍵,一個data,一個version
127.0.0.1:6379> hgetall frontend||guid 1) "data" 2) "\"e17b3e06-ba30-42c5-8960-48511c70b496\"" 3) "version" 4) "1"data很明顯是存入的數(shù)據(jù),version呢?現(xiàn)在猜測是防止并發(fā)沖突的etag,我們下面來驗證一下
在StateController中新增接口
// 獲取一個值和etag[HttpGet("withetag")]public async Task<ActionResult> GetWithEtagAsync(){var (value,etag) = await _daprClient.GetStateAndETagAsync<string>("statestore", "guid");return Ok($"value is {value}, etag is {etag}");}通過dapr重啟這個app,并調(diào)用withetag api,很明顯redis中version與etag相等,初步印證我們的猜測
?我們可以通過post方法修改一下guid這個key,修改后etag會變更,再來看一下redis中version和etag是不是一個東西
首先調(diào)用POST方法修改值
?再調(diào)用withetag方法,看下etag,發(fā)現(xiàn)etag變成了2
?在比較一下redis中的version
127.0.0.1:6379> hgetall frontend||guid 1) "data" 2) "\"36a55558-35c3-402c-ac9e-615014eb6904\"" 3) "version" 4) "2"現(xiàn)在可以確定etag就是redis中的version了
相關(guān)文章:
Dapr實戰(zhàn)(一) 基礎(chǔ)概念與環(huán)境搭建
Dapr + .NET Core實戰(zhàn)(二) 服務(wù)調(diào)用
總結(jié)
以上是生活随笔為你收集整理的Dapr + .NET Core实战(三)状态管理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 成长 | 《大厂晋升指南》学习总结(下)
- 下一篇: 【干货】单日10亿GMV的.NET5电商