手把手教你学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 ...
随机推荐
- setTimeout 与setInterval的区别
setTimeout(code,millisec) 方法用于在指定的毫秒数后调用函数或计算表达式 setInterval(code,millisec) 方法可按照指定的周期(以毫秒计)来调用函数或计算 ...
- 获取用户id的方法
/** 获取ip */function getip() { if(getenv("HTTP_X_FORWARDED_FOR")!=''){ $cip = getenv(" ...
- 动图图解GC算法 - 让垃圾回收动起来!
原创:码农参上(微信公众号ID:CODER_SANJYOU),欢迎分享,转载请保留出处. 提到Java中的垃圾回收,我相信很多小伙伴和我一样,第一反应就是面试必问了,你要是没背过点GC算法.收集器什么 ...
- 鸿蒙内核源码分析(位图管理篇) | 谁能一分钱分两半用 | 百篇博客分析OpenHarmony源码 | v19.03
百篇博客系列篇.本篇为: v19.xx 鸿蒙内核源码分析(位图管理篇) | 谁能一分钱分两半用 | 51.c.h .o 先看四个宏定义,进程和线程(线程就是任务)最高和最低优先级定义,[0,31]区间 ...
- YbtOJ#912-神秘语言【结论,欧拉定理】
正题 题目链接:http://www.ybtoj.com.cn/problem/912 题目大意 给出\(L,R\),求有多少长度在\([L,R]\)之间的字符串满足依次取出所有偶数位置的放在最前面后 ...
- Maccms8.x(苹果cms)命令执行漏洞
getshell payload(a): http://0-sec.org/index.php?m=vod-search&wd={if-A:assert($_POST[a])}{endif-A ...
- Node.js躬行记(12)——BFF
BFF字面意思是服务于前端的后端,我的理解就是数据聚合层.我们组在维护一个后台管理系统,会频繁的与数据库交互. 过去为了增删改查会写大量的对应接口,并且还需要在Model.Service.Router ...
- 教你 4 步搭建弹性可扩展的 WebAPI
作者 | 萧起 阿里云云原生团队 本文整理自<Serverless 技术公开课>,关注"Serverless"公众号,回复"入门",即可获取 Se ...
- 从零入门 Serverless | 教你 7 步快速构建 GitLab 持续集成环境
作者 | 存诚 阿里云弹性计算团队 本文整理自<Serverless 技术公开课>,"Serverless"公众号后台回复"入门",即可获取系列文章 ...
- logstash输出到rabbitmq
场景 将应用日志文件发送到rabbitmq. filebeat 不支持rabbitmq作为输出.因此,需要先将文件由filebeat发送到logstash ,再由logstash 输出到rabbitm ...