介绍

应用状态治理,您的应用程序能够将数据作为键/值对存储在反对的状态存储中。

您的应用程序能够应用 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的平均温度,请应用:

SELECT AVG(value) FROM StateTable WHERE Id LIKE '<app-id>||<thermometer>||*||temperature'

保留并获取状态

状态治理是任何应用程序最常见的需要之一:新的或遗留的、单体或微服务。解决不同的数据库、测试、解决重试和故障可能既费时又费劲。

先决条件

筹备好Dapr运行环境能够看之前的文章

手把手教你学Dapr - 3. 应用Dapr运行第一个.Net程序

设置状态存储

Windows关上目录%USERPROFILE%\.dapr\components

  1. 创立文件statestore.yaml
  2. 应用redis作为状态存储的数据库

    apiVersion: dapr.io/v1alpha1kind: Componentmetadata:  name: statestorespec:  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/v1alpha1kind: Componentmetadata:  name: statestore  namespace: productionspec:  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/dap...

咱们正在口头,新的框架、新的生态

咱们的指标是自在的易用的可塑性强的功能丰富的强壮的

所以咱们借鉴Building blocks的设计理念,正在做一个新的框架MASA Framework,它有哪些特点呢?

  • 原生反对Dapr,且容许将Dapr替换成传统通信形式
  • 架构不限,单体利用、SOA、微服务都反对
  • 反对.Net原生框架,升高学习累赘,除特定畛域必须引入的概念,保持不造新轮子
  • 丰盛的生态反对,除了框架以外还有组件库、权限核心、配置核心、故障排查核心、报警核心等一系列产品
  • 外围代码库的单元测试覆盖率90%+
  • 开源、收费、社区驱动
  • 还有什么?咱们在等你,一起来探讨
通过几个月的生产我的项目实际,已实现POC,目前正在把之前的积攒重构到新的开源我的项目中

目前源码已开始同步到Github(文档站点在布局中,会缓缓欠缺起来):

MASA.BuildingBlocks

MASA.Contrib

MASA.Utils

MASA.EShop

BlazorComponent

MASA.Blazor

QQ群:7424099

微信群:加技术经营微信(MasaStackTechOps),备注来意,邀请进群