dapr+.netcore实战状态管理(代码片段)

dotNET跨平台 dotNET跨平台     2023-01-08     120

关键词:

状态管理解决了什么

分布式应用程序中的状态可能很有挑战性。例如:

  • 应用程序可能需要不同类型的数据存储

  • 访问和更新数据可能需要不同的一致性级别。

  • 多个用户可以同时更新数据,这需要解决冲突

  • 服务必须重试 与数据存储交互 时发生的任何短期暂时性错误。

Dapr 状态管理解决了这些难题。它简化了跟踪状态,而无需依赖关系或第三方存储 SDK 上的学习曲线。

工作原理

应用程序与 Dapr sidecar 交互,以存储和检索键/值数据。在底层,sidecar API 使用可配置的状态存储组件来保存数据。开发人员可以从不断增长的受支持状态存储集合中选择,其中包括 Azure Cosmos DB、SQL Server 和 Cassandra。

可以使用 HTTP 或 gRPC 调用 API。使用以下 URL 调用 HTTP API:

http://localhost:<dapr-port>/v1.0/state/<store-name>/
  • <dapr-port>:Dapr 侦听的 HTTP 端口。

  • <store-name>:使用的状态存储组件的名称。

状态组件

Dapr支持的组件

为本地自承载开发初始化时,Dapr 将 Redis 注册为默认状态存储。下面是默认状态存储配置的示例,配置文件位置为C:\\Users\\<username>\\.dapr\\components。记下默认名称 statestore :

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: statestore
spec:
  type: state.redis
  version: v1
  metadata:
  - name: redisHost
    value: localhost:6379
  - name: redisPassword
    value: ""
  - name: actorStateStore
    value: "true"

项目演示

仍然使用 上一篇服务调用 的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防止并发冲突,保存一个值
        [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防止并发冲突,删除一个值
        [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);
        


        // 根据绑定获取并修改值,健值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调用sidecar的endpoint

 

 查看store存储中的内容

进入容器内部

docker exec -it dapr_redis /bin/sh

调用redis-cli

redis-cli

查看所有key

keys *

可以看到有"frontend||guid"这个key,所以状态在redis中存储中Name的规则是appName||keyName,这样可以防止不同app的键冲突

我们通过type key查看下这个键的类型,可以发现他是一个hash

127.0.0.1:6379> type frontend||guid
hash

再通过hgetall key查看他的数据,发现有两个键,一个data,一个version

127.0.0.1:6379> hgetall  frontend||guid
1) "data"
2) "\\"e17b3e06-ba30-42c5-8960-48511c70b496\\""
3) "version"
4) "1"

data很明显是存入的数据,version呢?现在猜测是防止并发冲突的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,并调用withetag api,很明显redis中version与etag相等,初步印证我们的猜测

 我们可以通过post方法修改一下guid这个key,修改后etag会变更,再来看一下redis中version和etag是不是一个东西

首先调用POST方法修改值

 再调用withetag方法,看下etag,发现etag变成了2

 在比较一下redis中的version

127.0.0.1:6379> hgetall  frontend||guid
1) "data"
2) "\\"36a55558-35c3-402c-ac9e-615014eb6904\\""
3) "version"
4) "2"

现在可以确定etag就是redis中的version

相关文章:

dapr在java中的实践之状态管理(代码片段)

文章目录状态管理编写示例代码启动服务状态储存组件状态管理状态管理(StateManagement)使用键值对作为存储机制,可以轻松的使长时运行、高可用的有状态服务和无状态服务共同运行在我们的服务中。我们的服务可... 查看详情

dapr+.net实战(十-终篇)k8s运行dapr(代码片段)

工作原理为了实现在k8s上安装Dapr,Dapr需要部署dapr-sidecar-injector、dapr-operator、dapr-placement和dapr-sentry服务。 dapr-operator:管理组件(statestores,pub/subs,etc.)dapr-sidecar-injector: 将Dapr注入 annotated pods,并 查看详情

手把手教你学dapr-5.状态管理(代码片段)

介绍使用状态管理,您的应用程序可以将数据作为键/值对存储在支持的状态存储中。您的应用程序可以使用Dapr的状态管理API使用状态存储组件来保存和读取键/值对,如下图所示。例如,通过使用HTTPPOST,您可以... 查看详情

dapr+.net实战绑定(代码片段)

什么是绑定处理外部事件或调用外部接口的功能就是绑定,绑定可以提供以下好处:避免连接到消息系统(如队列和消息总线)并进行轮询的复杂性聚焦于业务逻辑,而不是如何与系统交互使代码不受SDK或外部库的强耦... 查看详情

dapr+.net实战secrets(代码片段)

什么是Secrets应用程序通常会通过使用专用的存储来存储敏感信息,如连接字符串、密钥等。通常这需要建立一个密钥存储,如AzureKeyVault、Hashicorp等,并在那里存储应用程序级别的密钥。要访问这些密钥存储,应... 查看详情

dapr+.net实战actor(代码片段)

什么是Actor模式Actors为最低级别的“计算单元”以上解释来自官方文档,看起来“晦涩难懂”。大白话就是说Actors模式是一段需要单线程执行的代码块。实际开发中我们经常会有一些逻辑不能并发执行,我们常用的做法就... 查看详情

dapr+.net实战发布和订阅(代码片段)

什么是发布-订阅发布订阅是一种众所周知并被广泛使用的消息传送模式,常用在微服务架构的服务间通信,高并发削峰等情况。但是不同的消息中间件之间存在细微的差异,项目使用不同的产品需要实现不同的实现... 查看详情

asp.netcore2.0项目实战ncmvc一个基于netcore2.0搭建的角色权限管理开发框架(代码片段)

....总结 1. 摘要  NCMVC角色权限管理框架是由最近练习NetCore时抽时间整理的系统,后续能不能发展成一个cms还要看朋友们是否有需要或时间是否充实。这里NCMVC主要还是给想要学习接触Asp.NetCore2.0的朋友们提供一些借鉴以及坑... 查看详情

netcore体系-web应用程序-4asp.netcore2.0项目实战-3项目架构说明(代码片段)

...4.总结1. 摘要  NCMVC角色权限管理框架是由最近练习NetCore时抽时间整理的系统,后续能不能发展成一个cms还要看朋友们是否有需要或时间是否充实。这里NCMVC主要还是给想要学习接触Asp.NetCore2.0的朋友们提供一些借鉴以及坑... 查看详情

netcore体系-web应用程序-4asp.netcore2.0项目实战-13基于onactionexecuting全局过滤器,页面操作权限过滤控制到按钮级(代码片段)

...理  权限管理的基本定义:百度百科。  基于《Asp.NetCore2.0项目实战(10)基于cookie登录授权认证并实现前台会员、后台管理员同时登录》我们做过了登录认证,登录是权限的最基础的认证,没有登录就没有接下来的各种操... 查看详情

我被dapr点燃

...pr的热度个人认为才刚刚热起来,9月份我写了Dapr+.NETCore实战一共10篇,从基础概念到简单的实战,但是有很多人感兴趣,具体表现在我个人维护的QQ群,人数从80人左右,增加到了155,将近增加了1倍&... 查看详情

netcore体系-api-1ocelot-项目实战(代码片段)

首先,让我们简单了解下什么是API网关?   API网关是一个服务器,是系统的唯一入口。从面向对象设计的角度看,它与外观模式类似。API网关封装了系统内部架构,为每个客户端提供一个定制的API。它可能还具有其它... 查看详情

dapr简介(代码片段)

...行并包含多种语言和开发人员框架的弹性,微服务无状态和有状态应用程序。分布式程序(DistributedApplica 查看详情

dapr牵手.net学习笔记:状态管理进阶

在上一篇文章中说到,dapr默认的状态是不可能跨appid的,也就是只能在相同的应用内访问自己设置的状态数据,dapr支持三种状态的共享配置:appid,nam,none,是通过修改components下的statestore.yaml文件中... 查看详情

dapr在java中的实践之环境准备(代码片段)

...开发人员都可以轻松地构建运行在云和边缘上的弹性、无状态和有状态的应用程序,并支持语言和开发人员框架的多样性。Dapr利用Sidecar架构的优势,帮助我们解决构建微服务所带来的挑战,并保持代码与平台无关。... 查看详情

dapr牵手.net学习笔记:状态管理进阶

为了防止并发对数据修改造成差异,dapr使用了etag标签来作为版本号,对数据修改进行验证。下面是对etag的一个demoappsettings.json中的url配置"StateUrl":"http://localhost:3500/v1.0/state/statestore"在PaymentSystem项目中添加两... 查看详情

flutterprovider状态管理---mvvm架构实战(代码片段)

源码仓库地址github仓库地址MVVM介绍MVVM架构分为M(Model)、V(View)、VM(ViewModel)三个部分,他们分别处理自己的分工,在View和Model之间使用ViewModel作为中介者,使View和Model不受业务逻辑影响。Model: 模型层,处理Api数据... 查看详情

dapr牵手.net学习笔记:状态管理之docker-compose发布

...的基础,会更容易阅读一些。在分布式应用,有状态服务是常态 查看详情