Dapr-状态管理
前言:
前一篇对Dapr的服务调用方式进行了解,本篇继续对状态管理进行了解。
一、状态管理-解决的问题
在分布式应用程序中跟踪状态存在一下问题:
- 应用程序可能需要不同类型的数据存储。
- 访问和更新数据时可能需要不同的一致性级别。
- 多个用户可以同时更新数据,需要冲突解决。
- 在与数据存储交互时,服务必须重试发生的任何短暂的暂时性错误 。
Dapr 状态管理构建块解决了这些难题。 它简化了跟踪状态,而无需依赖关系或第三方存储 Sdk 上的学习曲线。
Dapr 状态管理提供 密钥/值 API。 此功能不支持关系数据存储或图形数据存储。
二、状态管理-工作原理
应用程序可以使用Dapr的状态管理API,使用状态存储组件保存和读取键/值对。通过 HTTP 或 gRPC 调用 API。
例如,通过使用HTTP POST可以保存键/值对,通过使用HTTP GET可以读取一个键并返回它的值。

三、状态管理-特点
可插拔状态存储
Dapr数据存储被建模为组件,可以在不修改你的服务代码的情况下进行替换。
一致性
CAP 定理是一组适用于存储状态的分布式系统的原则。下图展示了CAP定理的三个属性。

定理指出,分布式数据系统提供一致性、可用性和分区容差之间的权衡。 而且,任何数据存储只能 保证三个属性中的两个:
一致性 (C) 。 群集中的每个节点都将使用最新的数据做出响应,即使在所有副本更新之前,系统都必须阻止请求。 如果查询当前正在更新的项的 "一致性系统",则在所有副本都成功更新之前,将不会收到响应。 但是,您将始终接收最新的数据。
可用性 () 。 即使该响应不是最新的数据,每个节点都将返回立即响应。 如果您在 "可用系统" 中查询正在更新的项,则您将获得该服务在此时可以提供的最佳可能的答案。
分区容差 (P) 。 即使复制的数据节点发生故障或失去与其他复制的数据节点的连接,保证系统仍可继续运行。
分布式应用程序必须处理 P 属性。 随着服务彼此间的网络调用通信,会发生网络中断 (P) 。 考虑到这一点,分布式应用程序必须是 AP 或 CP。
AP 应用程序选择 "可用性一致性"。 Dapr 通过其 最终一致性 策略支持此选择。 请考虑使用基础数据存储(例如 Azure CosmosDB)将冗余数据存储在多个副本上。 对于最终一致性,状态存储会将更新写入一个副本并完成与客户端的写入请求。 此时间过后,存储将以异步方式更新其副本。 读取请求可以返回任何副本的数据,包括尚未收到最新更新的副本。
CP 应用程序选择一致性和可用性。 Dapr 通过其 强一致性 策略支持此选择。 在此方案中,状态存储将同步更新 所有 (或在某些情况下,在完成写入请求 之前) 必需副本的 仲裁。 读取操作将跨副本持续返回最新数据。
并发
在多用户应用程序中,有可能多个用户同时更新同一时间) (相同的数据。 Dapr 支持乐观并发控制 (OCC) 来管理冲突。 OCC 基于一个假设,因为用户处理数据的不同部分,所以更新冲突很少见。 更有效的方法是将更新成功,如果不成功,则重试。 实现悲观锁定的替代方法可能会影响长时间运行的锁定,导致数据争用。
Dapr 支持使用 Etag) (OCC 的乐观并发控制。 ETag 是与存储的键/值对的特定版本相关联的值。 键/值对的每次更新时,ETag 值也会更新。 当客户端检索键/值对时,响应包括当前 ETag 值。 当客户端更新或删除键/值对时,它必须在请求正文中发送回该 ETag 值。 如果其他客户端同时更新了数据,则 Etag 不会匹配,请求将失败。 此时,客户端必须检索更新的数据,重新进行更改,然后重新提交更新。 此策略称为 第一次写入-wins。
Dapr 还支持 最后写入 wins 策略。 使用此方法时,客户端不会将 ETag 附加到写入请求。 状态存储组件将始终允许更新,即使基础值在会话期间已更改也是如此。 最后写入-wins 对于数据争用较少的高吞吐量写入方案非常有用。 同样,可以容忍偶尔的用户更新。
事务
Dapr 可以将 多项更改 作为一个作为事务实现的操作写入数据存储区。 此功能仅适用于支持 ACID 事务的数据存储。 在撰写本文时,这些存储包括 Redis、MongoDB、PostgreSQL、SQL Server和 Azure CosmosDB。
在下面的示例中,多项操作将发送到单个事务中的状态存储。 所有操作都必须成功,事务才能提交。 如果一个或多个操作失败,则回滚整个事务。
四、.Net Core中应用
1、在项目【DaprFrontEnd】中添加控制器-DaprStateController 用于展示状态的各种操作
[Route("[controller]")]
[ApiController]
public class StateController : ControllerBase
{
private readonly ILogger<DaprStateController> _logger;
private readonly DaprClient _daprClient;
public StateController(ILogger<StateController> logger, DaprClient daprClient)
{
_logger = logger;
_daprClient = daprClient;
}
/// <summary>
/// 获取值
/// </summary>
/// <returns></returns>
[HttpGet]
public async Task<ActionResult> GetAsync()
{
var result = await _daprClient.GetStateAsync<string>("statestore", "guid");
return Ok(result);
}
/// <summary>
/// 保存值
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task<ActionResult> PostAsync()
{
await _daprClient.SaveStateAsync<string>("statestore", "guid", Guid.NewGuid().ToString(), new StateOptions() { Consistency = ConsistencyMode.Strong });
return Ok("done");
}
/// <summary>
/// 删除值
/// </summary>
/// <returns></returns>
[HttpDelete]
public async Task<ActionResult> DeleteAsync()
{
await _daprClient.DeleteStateAsync("statestore", "guid");
return Ok("done");
}
/// <summary>
/// 通过tag防止并发冲突,保存值
/// </summary>
/// <returns></returns>
[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");
}
/// <summary>
/// 通过tag防止并发冲突,删除值
/// </summary>
/// <returns></returns>
[HttpDelete("withtag")]
public async Task<ActionResult> DeleteWithTagAsync()
{
var (value, etag) = await _daprClient.GetStateAndETagAsync<string>("statestore", "guid");
return Ok(await _daprClient.TryDeleteStateAsync("statestore", "guid", etag));
}
/// <summary>
/// 从绑定获取值,健值name从路由模板获取
/// </summary>
/// <param name="state"></param>
/// <returns></returns>
[HttpGet("frombinding/{name}")]
public async Task<ActionResult> GetFromBindingAsync([FromState("statestore", "name")] StateEntry<string> state)
{
return await Task.FromResult<ActionResult>(Ok(state.Value));
}
/// <summary>
/// 根据绑定获取并修改值,健值name从路由模板获取
/// </summary>
/// <param name="state"></param>
/// <returns></returns>
[HttpPost("withbinding/{name}")]
public async Task<ActionResult> PostWithBindingAsync([FromState("statestore", "name")] StateEntry<string> state)
{
state.Value = Guid.NewGuid().ToString();
return Ok(await state.TrySaveAsync());
}
/// <summary>
/// 获取多个值
/// </summary>
/// <returns></returns>
[HttpGet("list")]
public async Task<ActionResult> GetListAsync()
{
var result = await _daprClient.GetBulkStateAsync("statestore", new List<string> { "guid" }, 10);
return Ok(result);
}
/// <summary>
/// 删除多个值
/// </summary>
/// <returns></returns>
[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");
}
}
2、启动程序
dapr run --dapr-http-port 3501 --app-port 8230 --app-id frontend dotnet .\DaprFrontEnd.dll
3、调用过程:


五、总结:
Dapr 状态管理构建块提供了一个 API,用于在各种数据存储区中存储键/值数据。 API 为以下内容提供支持:
- 批量操作
- 强一致性和最终一致性
- 乐观并发控制
- 多项事务
Dapr-状态管理的更多相关文章
- Dapr实战(三)状态管理
状态管理解决了什么 分布式应用程序中的状态可能很有挑战性. 例如: 应用程序可能需要不同类型的数据存储. 访问和更新数据可能需要不同的一致性级别. 多个用户可以同时更新数据,这需要解决冲突. 服务必须 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(五)——一步一步教你如何撸Dapr之状态管理
状态管理和上一章的订阅发布都算是Dapr相较于其他服务网格框架来讲提供的比较特异性的内容,今天我们来讲讲状态管理. 目录:一.通过Dapr实现一个简单的基于.net的微服务电商系统 二.通过Dapr实 ...
- Blazor+Dapr+K8s微服务之状态管理
1 状态管理服务器端接口 1.1 添加Dapr.AspNetCore包 在DaprTest1.Server项目中添加Dapr.AspNetCore包,该包实现了ASP. ...
- 手把手教你学Dapr - 5. 状态管理
上一篇:手把手教你学Dapr - 4. 服务调用 介绍 使用状态管理,您的应用程序可以将数据作为键/值对存储在支持的状态存储中. 您的应用程序可以使用 Dapr 的状态管理 API 使用状态存储组件来 ...
- Redux状态管理方法与实例
状态管理是目前构建单页应用中不可或缺的一环,也是值得花时间学习的知识点.React官方推荐我们使用Redux来管理我们的React应用,同时也提供了Redux的文档来供我们学习,中文版地址为http: ...
- 表格搞定 Asp.net Web 状态管理
最近在网上搜罗了 ASP.NET WEB 状态管理方面的一些内容,终于把这些内容整合总结了一下. 1. 希望自己通过整理,能够掌握一些,为自己投资. 2. 以便自己忘记,又要浪费时间搜罗. 3. 希望 ...
- [译]面向初学者的Asp.Net状态管理技术
介绍 本文主要讲解Asp.Net应用程序中的状态管理技术(Asp.Net中有多种状态管理技术),并批判性地分析所有状态管理技术的优缺点. 背景 HTTP是无状态的协议.客户端发起一个请求,服务器响应完 ...
- [Asp.Net]状态管理(Session、Application、Cache)
上篇博文介绍了在客户端状态管理的两种方式:http://www.cnblogs.com/wolf-sun/p/3329773.html.除了在客户端上保存状态外,还可以在服务器上保存状态.使用客户端的 ...
- [Asp.Net]状态管理(ViewState、Cookie)
简介 HTTP协议是无状态的.从客户端到服务器的连接可以在每个请求之后关闭.但是一般需要把一些客户端信息从一个页面传送给另一个页面. 无状态的根本原因是:浏览器和服务器使用Socket通信,服务器将请 ...
- HttpClient_HttpClient 4.3.6 HTTP状态管理
HTTP状态管理 最初的HTTP被设计成以状态.请求/应答为导向的协议,它被制作成是没有特殊条款的,以便在状态会话中能交换逻辑关系请求/应答.HTTP协议越来越受欢迎和被采用,越来越多的系统会在应用程 ...
随机推荐
- react之组件数据挂在方式
1.属性(props) 组件间传值,在React中是通过只读属性 props 来完成数据传递的. props:接受任意的入参,并返回用于描述页面展示内容的 React 元素. import React ...
- 如何评估 Serverless 服务能力?这份报告给出了 40 条标准
编者按:两年前,我们还在讨论什么是 Serverless,Serverless 如何落地.如今,已经有评测机构给出了 40 条标准来对 Serverless 的服务能力进行评估,这些评估细则既是技术生 ...
- 如何通过 Serverless 轻松识别验证码?
作者 | 江昱 来源 | Serverless 公众号 前言 Serverless 概念自被提出就倍受关注,尤其是近些年来 Serverless 焕发出了前所未有的活力,各领域的工程师都在试图将 Se ...
- 简单几步零成本使用Vercel部署OneIndex 无需服务器搭建基于OneDrive的网盘
前提 你需要一个OneDrive账号,必须管理员开放API 需要已安装Node.js 拥有Github账号,没有就注册一个 魔法上网环境(看情况) 注册应用 登录https://portal.azur ...
- Java(40)网络编程
作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15201659.html 博客主页:https://www.cnblogs.com/testero ...
- gitk
gitk gitk [<options>] [<revision range>] [--] [<path>-] 查看单个文件的变更历史 gitk -- CppPri ...
- Java字符串分割函数split源码分析
spilt方法作用 以所有匹配regex的子串为分隔符,将input划分为多个子串. 例如: The input "boo:and:foo", for example, yield ...
- 测试小姐姐问我 gRPC 怎么用,我直接把这篇文章甩给了她
原文链接: 测试小姐姐问我 gRPC 怎么用,我直接把这篇文章甩给了她 上篇文章 gRPC,爆赞 直接爆了,内容主要包括:简单的 gRPC 服务,流处理模式,验证器,Token 认证和证书认证. 在多 ...
- 在kivy中加图片
from kivy.app import App from kivy.uix.scatterlayout import ScatterLayout from kivy.uix.image import ...
- [对对子队]会议记录4.16(Scrum Meeting7)
今天已完成的工作 何瑞 工作内容:完成成本和分数系统 相关issue:实现成本和分数系统的逻辑 相关签入:4.16签入1 吴昭邦 工作内容:对接流水线和成本和分数系统 相关issu ...