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协议越来越受欢迎和被采用,越来越多的系统会在应用程 ... 
随机推荐
- 基于Hexo+Github Pages搭建的博客
			概念 Github Pages可以被认为是用户编写的.托管在github上的静态网页.使用Github Pages可以为你提供一个免费的服务器,免去了自己搭建服务器和写数据库的麻烦.此外还可以绑定自己 ... 
- SSM框架项目的mvc拦截器
			为了防止用户在不登录的情况下通过并接请求直接访问系统,我们需要通过session和拦截器来防止这样的情况. 拦截器的配置: 为拦截器建立一个包:interceptor,并在包里建立 LoginInte ... 
- 数据库已经存在表, django使用inspectdb反向生成model实体类
			1.通过inspectdb处理类,可以将现有数据库里的一个或者多个.全部数据库表生成Django model实体类 python manage.py inspectdb --database defa ... 
- 用 @Value("${xxxx}")注解从配置文件读取值的用法
			1. 用法: 从配置properties文件中读取init.password 的值. @Value("${init.password}") private String init ... 
- 【c++ Prime 学习笔记】第7章 类
			类的基本思想是数据抽象和封装 数据分离抽象是一种依赖于接口和实现分离的编程/设计技术.接口包括用户能执行的操作,实现包括类的数据成员.接口实现的函数体.定义类所需的各种私有函数 封装实现了类的接口和实 ... 
- leetcode 6/300 Z字型变换 py
			目录 题目说明 方法一:利用flag 题目说明 方法一:利用flag 简单来说就是利用flag来表示方向,真的神来之笔. class Solution: def convert(self, s: st ... 
- 网格布局GirdLayout在py中的引用,用于多行多列矩阵
			""" GridLayout为网格布局为了部件为多行距阵 """ from kivy.uix.gridlayout import GridL ... 
- MySQL:基础语法-3
			MySQL:基础语法-3 记录一下 MySQL 基础的一些语法,便于查询,该部分内容主要是参考:bilibili 上 黑马程序员 的课程而做的笔记,由于时间有点久了,课程地址忘记了 上文MySQL:基 ... 
- MacOS安装使用Kettle
			一.环境说明 操作系统版本:macOS Big Sur 11.6.1 机型:Intel版本 JDK版本:Amazon Corretto-openjdk8 Kettle版本:Kettle8.9 二.问题 ... 
- Scrum Meeting 0529
			零.说明 日期:2021-5-29 任务:简要汇报七日内已完成任务,计划后两日完成任务 一.进度情况 组员 负责 七日内已完成的任务 后两日计划完成的任务 困难 qsy PM&前端 完成后端管 ... 
