手把手教你学Dapr - 5. 状态管理
介绍
使用状态管理,您的应用程序可以将数据作为键/值对存储在支持的状态存储中。
您的应用程序可以使用 Dapr 的状态管理 API 使用状态存储组件来保存和读取键/值对,如下图所示。例如,通过使用 HTTP POST,您可以保存键/值对,通过使用 HTTP GET,您可以读取键并返回其值。

特性
可插拔状态存储
Dapr 数据存储被建模为组件,可以在不更改代码的情况下更换它。例如:MySQL、Redis、Azure CosmosDB等。
可配置的状态存储行为
Dapr 允许开发人员将额外的元数据附加到状态操作请求中,用以描述请求的处理方式。如:
- 并发要求
- 一致性要求
默认情况下,您的应用程序应假定数据存储最终一致并使用最后写入获胜的并发模式
并发
Dapr 支持使用 ETags 的乐观并发控制 (OCC)。当请求状态时,Dapr 总是将 ETag 属性附加到返回的状态。当用户代码尝试更新或删除状态时,应该通过请求正文附加 ETag 以进行更新或通过 If-Match 标头进行删除。只有当提供的 ETag 与状态存储中的 ETag 匹配时,写操作才能成功。建议您在使用 ETag 时使用重试策略来补偿此类冲突。
如果您的应用程序在写入请求时省略 ETag,则 Dapr 在处理请求时会跳过 ETag 检查。与使用 ETag 的先写赢模式相比,这实质上启用了最后写赢模式。
自动加密
Dapr 支持应用程序状态的自动客户端加密,并支持密钥轮换。这是一项预览功能,所有 Dapr 状态存储都支持。
一致性
Dapr 支持强一致性和最终一致性,最终一致性作为默认行为。
当使用强一致性时,Dapr 在确认写入请求之前等待所有副本(或指定的仲裁)确认。
当使用最终一致性时,一旦底层数据存储接受写入请求,Dapr 就会立即返回,即使这是单个副本。
批量操作
Dapr 支持两种类型的批量操作 - 批量(bulk)或多(multi)。
注:bulk与multi的区别在于bulk不是事务性的,multi是事务处理。
Actor状态
事务状态存储可用于存储Actor状态。要指定用于Actor的状态存储,请在状态存储组件的元数据部分中将属性 actorStateStore 的值指定为 true。
注:Actors 状态以特定方案存储在事务状态存储中允许一致的查询。所以只能有一个状态存储组件被用于所有的Actor。
直接查询状态存储
Dapr 无需任何转换即可保存和检索状态值。您可以直接从底层状态存储查询和聚合状态。
例如,要在 Redis 中获取与应用程序 ID “myApp” 关联的所有状态键,请使用:
KEYS "myApp*"
查询Actor状态
如果数据存储支持 SQL 查询,您可以使用 SQL 查询查询参与者的状态。例如使用:
SELECT * FROM StateTable WHERE Id='<app-id>||<actor-type>||<actor-id>||<key>'
您还可以跨Actor实例执行聚合查询,避免Actor 框架常见的基于回合的并发限制。例如,要计算所有温度计Actor的平均温度,请使用:
保存并获取状态
状态管理是任何应用程序最常见的需求之一:新的或遗留的、单体或微服务。处理不同的数据库、测试、处理重试和故障可能既费时又费力。
先决条件
准备好Dapr运行环境可以看之前的文章
手把手教你学Dapr - 3. 使用Dapr运行第一个.Net程序
设置状态存储
Windows打开目录%USERPROFILE%\.dapr\components
创建文件
statestore.yaml使用
redis作为状态存储的数据库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"注:这个yaml已经通过actorStateStore开启了Actor状态
保存和检索单个状态
注:设置 app-id 很重要,因为状态键以该值作为前缀。如果您不设置它,则在运行时为您生成一个,下次运行该命令时将生成一个新的,您将无法再访问以前保存的状态。换句话说,如果你要共享状态可以自定义一个保留app-id作为共享状态而不是留空。
运行Dapr Sidecar
运行一个空的Sidecar,因为我们只用它来帮助访问状态存储,所以与之前不同的是,dapr run后面没有接dotnet run去作为某一个程序的Sidecar
dapr run --app-id myapp --dapr-http-port 3500 --dapr-grpc-port 50001
创建客户端
创建控制台程序,添加Dapr.Client NuGet包引用。
修改Program.cs
using Dapr.Client;
var storeName = "statestore";
var key = "myFirstKey";
var value = "myFirstValue";
var client = new DaprClientBuilder().Build();
await client.SaveStateAsync(storeName, key, value);
Console.WriteLine("State has been stored");
var data = await client.GetStateAsync<string>(storeName, key);
Console.WriteLine($"Got value: {data}");
Console.ReadKey();
删除单个状态
await client.DeleteStateAsync(storeName, key);
通过事务保存和检索多个状态
Dapr 还允许您在同一个调用中保存和检索多个状态。
var lst = new List<StateTransactionRequest>()
{
new StateTransactionRequest("test1", System.Text.Encoding.UTF8.GetBytes("value1"), StateOperationType.Upsert),
new StateTransactionRequest("test2", System.Text.Encoding.UTF8.GetBytes("value2"), StateOperationType.Upsert),
};
await client.ExecuteStateTransactionAsync(storeName, lst);
var datas = await client.GetBulkStateAsync(storeName, lst.Select(r => r.Key).ToList(), 0);
Console.WriteLine($"Got items: {string.Join(",", datas.Select(d => $"{d.Key}={d.Value}"))}");
强一致性
使用强一致性时,Dapr将确保底层状态存储在写入或删除状态之前,一旦数据被写入到所有副本或收到来自quorum的ack,就会返回响应。
对于GET请求,Dapr 将确保存储在副本之间一致地返回最新数据。默认为最终一致性,除非在对状态 API 的请求中另有说明。
await client.SaveStateAsync(storeName, key, value, new StateOptions() { Consistency = ConsistencyMode.Strong });
var etagData = await client.GetStateAndETagAsync<string>(storeName, key, ConsistencyMode.Strong);
Console.WriteLine($"ETag:{etagData.etag}");
await client.DeleteStateAsync(storeName, key, new StateOptions() { Consistency = ConsistencyMode.Strong });
先写赢和最后写赢
Dapr 允许开发人员在使用数据存储时选择两种常见的并发模式:首先写入获胜和``最后写入获胜`。 First-Write-Wins 在您有多个应用程序实例的情况下很有用,所有实例都同时写入同一个键。
Dapr 的默认模式是最后写入获胜。
下面的例子展示了如何获取一个 ETag,然后使用它来保存状态,然后删除状态:
await client.SaveStateAsync(storeName, key, value, new StateOptions() { Concurrency = ConcurrencyMode.FirstWrite });
var firstWriteWinData = await client.GetStateAndETagAsync<string>(storeName, key);
var etag = firstWriteWinData.etag;
await client.TrySaveStateAsync(storeName, key, DateTime.Now.Ticks.ToString(), etag, new StateOptions() { Concurrency = ConcurrencyMode.FirstWrite });
var firstWriteWinDeleteSucceeded = await client.TryDeleteStateAsync(storeName, key, etag);
Console.WriteLine($"First write wins delete:{firstWriteWinDeleteSucceeded}");
firstWriteWinData = await client.GetStateAndETagAsync<string>(storeName, key);
firstWriteWinDeleteSucceeded = await client.TryDeleteStateAsync(storeName, key, firstWriteWinData.etag);
Console.WriteLine($"First write wins delete:{firstWriteWinDeleteSucceeded}");
注:这里演示了ETag在更新后尝试删除失败的例子,最后再重新获取新的状态以修正ETag再删除
在不同的应用程序之间共享状态
为了实现状态共享,Dapr 支持以下键前缀策略
appid- 这是默认策略。 appid 前缀允许状态只能由具有指定 appid 的应用程序管理。所有状态键都将以 appid 为前缀,并以应用程序为范围。name- 此设置使用状态存储组件的名称作为前缀。对于给定的状态存储,多个应用程序可以共享相同的状态。none- 此设置不使用前缀。多个应用程序在不同的状态存储之间共享状态
举个例子:要指定前缀策略,请在状态组件上添加名为 keyPrefix 的元数据键
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: statestore
namespace: production
spec:
type: state.redis
version: v1
metadata:
- name: keyPrefix
value: <key-prefix-strategy>
注:此示例演示相对较复杂,思路大概是使用多个statestore.yaml,然后根据不同的storename切换不同策略即可。感兴趣的小伙伴可以自行尝试。
自动加密状态并管理密钥轮换
注:截止目前,这个功能是个预览版,感兴趣的小伙伴可以自行尝试
应用程序状态通常需要静态加密,以在企业工作负载或受监管环境中提供更强的安全性。 Dapr 提供基于 AES256 的自动客户端加密。
状态的生存时间(TTL)
Dapr 为每个状态在请求时设置生存时间 (TTL)。这意味着应用程序可以为每个存储的状态设置生存时间,并且这些状态在到期后无法检索。
注:只有一部分 Dapr 状态存储组件与状态 TTL 兼容。对于支持的状态存储,只需在发布消息时设置 ttlInSeconds 元数据。其他状态存储将忽略此值。
await client.SaveStateAsync(storeName, key, value, metadata: new Dictionary<string, string>() { { "ttlInSeconds", "3" } });
var ttlData = await client.GetStateAsync<string>(storeName, key);
Console.WriteLine($"TTL Data:{ttlData}");
Thread.Sleep(5000);
ttlData = await client.GetStateAsync<string>(storeName, key);
Console.WriteLine($"TTL Data:{ttlData}");
持久化状态
要显式设置持久化状态(忽略为键设置的任何 TTL),请将 ttlInSeconds 值指定为 -1。
本章源码
Assignment05
https://github.com/doddgu/dapr-study-room
我们正在行动,新的框架、新的生态
我们的目标是自由的、易用的、可塑性强的、功能丰富的、健壮的。
所以我们借鉴Building blocks的设计理念,正在做一个新的框架MASA Framework,它有哪些特点呢?
- 原生支持Dapr,且允许将Dapr替换成传统通信方式
- 架构不限,单体应用、SOA、微服务都支持
- 支持.Net原生框架,降低学习负担,除特定领域必须引入的概念,坚持不造新轮子
- 丰富的生态支持,除了框架以外还有组件库、权限中心、配置中心、故障排查中心、报警中心等一系列产品
- 核心代码库的单元测试覆盖率90%+
- 开源、免费、社区驱动
- 还有什么?我们在等你,一起来讨论
经过几个月的生产项目实践,已完成POC,目前正在把之前的积累重构到新的开源项目中
目前源码已开始同步到Github(文档站点在规划中,会慢慢完善起来):
QQ群:7424099
微信群:加技术运营微信(MasaStackTechOps),备注来意,邀请进群

手把手教你学Dapr - 5. 状态管理的更多相关文章
- 手把手教你学Dapr - 6. 发布订阅
上一篇:手把手教你学Dapr - 5. 状态管理 介绍 发布/订阅模式允许微服务使用消息相互通信.生产者或发布者在不知道哪个应用程序将接收它们的情况下向主题发送消息.这涉及将它们写入输入通道.同样,消 ...
- 手把手教你学Dapr - 8. 绑定
目录 手把手教你学Dapr - 1. .Net开发者的大时代 手把手教你学Dapr - 2. 必须知道的概念 手把手教你学Dapr - 3. 使用Dapr运行第一个.Net程序 手把手教你学Dapr ...
- 手把手教你学Dapr - 9. 可观测性
目录 手把手教你学Dapr - 1. .Net开发者的大时代 手把手教你学Dapr - 2. 必须知道的概念 手把手教你学Dapr - 3. 使用Dapr运行第一个.Net程序 手把手教你学Dapr ...
- 手把手教你学Dapr - 3. 使用Dapr运行第一个.Net程序
上一篇:手把手教你学Dapr - 2. 必须知道的概念 注意: 文章中提到的命令行工具即是Windows Terminal/PowerShell/cmd其中的一个,推荐使用Windows Termin ...
- 手把手教你学Dapr - 4. 服务调用
上一篇:手把手教你学Dapr - 3. 使用Dapr运行第一个.Net程序 介绍 通过使用服务调用,您的应用程序可以使用标准的gRPC或HTTP协议与其他应用程序可靠.安全地通信. 为什么不直接用Ht ...
- 手把手教你学Dapr - 7. Actors
上一篇:手把手教你学Dapr - 6. 发布订阅 介绍 Actor模式将Actor描述为最低级别的"计算单元".换句话说,您在一个独立的单元(称为actor)中编写代码,该单元接收 ...
- 手把手教你学Dapr - 1. .Net开发者的大时代
Dapr全称 Distributed Application Runtime,分布式应用运行时 Dapr的口号 简化云原生应用开发,聚焦在应用的核心逻辑,让代码简单.可移植 Dapr的目标 最佳实践的 ...
- 手把手教你学Dapr - 2. 必须知道的概念
Sidecar 边车 Dapr API提供Http和gRPC两种通讯方式. 运行方式则可以是容器也可以是进程(Windows开发推荐使用Self Hosted,后续会解释). 这样的好处是与运行环境无 ...
- 每天记录一点:NetCore获得配置文件 appsettings.json vue-router页面传值及接收值 详解webpack + vue + node 打造单页面(入门篇) 30分钟手把手教你学webpack实战 vue.js+webpack模块管理及组件开发
每天记录一点:NetCore获得配置文件 appsettings.json 用NetCore做项目如果用EF ORM在网上有很多的配置连接字符串,读取以及使用方法 由于很多朋友用的其他ORM如S ...
随机推荐
- python学习笔记(六)-集合
集合是一个无序不重复元素的集.基本功能包括关系测试和消除重复元素.集合对象还支持union(联合),intersection(交),difference(差)和sysmmetric differenc ...
- HTML 网页开发、CSS 基础语法——五. 编辑器
- P7099-[yLOI2020]灼【数学期望,结论】
正题 题目链接:https://www.luogu.com.cn/problem/P7099 题目大意 给出\(n\)个坐标轴上的点,\(q\)次询问从某点出发每次等概率向左或者向右一格求到达某个给出 ...
- AT2164-[AGC006C]Rabbit Exercise【差分,倍增,数学期望】
正题 题目链接:https://www.luogu.com.cn/problem/AT2164 题目大意 \(n\)只兔子编号为\(1\sim n\),第\(i\)只在坐标轴\(x_i\)处.然后\( ...
- PyTorch模型读写、参数初始化、Finetune
使用了一段时间PyTorch,感觉爱不释手(0-0),听说现在已经有C++接口.在应用过程中不可避免需要使用Finetune/参数初始化/模型加载等. 模型保存/加载 1.所有模型参数 训练过程中,有 ...
- MySQL学习总结:提问式回顾 undo log 相关知识
原文链接:MySQL学习总结:提问式回顾 undo log 相关知识 1.redo 日志支持恢复重做,那么如果是回滚事务中的操作呢,也会有什么日志支持么? 也回滚已有操作,那么就是想撤销,对应的有撤销 ...
- 深入剖析 Spring WebFlux
一.WebFlux 简介 WebFlux 是 Spring Framework5.0 中引入的一种新的反应式Web框架.通过Reactor项目实现Reactive Streams规范,完全异步和非阻塞 ...
- 极简SpringBoot指南-Chapter03-基于SpringBoot的Web服务
仓库地址 w4ngzhen/springboot-simple-guide: This is a project that guides SpringBoot users to get started ...
- md5验证文件上传,确保信息传输完整一致
注:因为是公司项目,仅记录方法和思路以及可公开的代码. 最近在公司的项目中,需要实现一个上传升级包到服务器的功能: 在往服务器发送文件的时候,需要确保 文件从开始发送,到存入服务器磁盘的整个传输的过程 ...
- st表树状数组入门题单
预备知识 st表(Sparse Table) 主要用来解决区间最值问题(RMQ)以及维护区间的各种性质(比如维护一段区间的最大公约数). 树状数组 单点更新 数组前缀和的查询 拓展:原数组是差分数组时 ...