状态管理解决了什么

分布式应用程序中的状态可能很有挑战性。 例如:

  • 应用程序可能需要不同类型的数据存储
  • 访问和更新数据可能需要不同的一致性级别。
  • 多个用户可以同时更新数据,这需要解决冲突
  • 服务必须重试 与数据存储交互 时发生的任何短期暂时性错误。

Dapr 状态管理解决了这些难题。 它简化了跟踪状态,而无需依赖关系或第三方存储 SDK 上的学习曲线。

工作原理

应用程序与 Dapr sidecar 交互,以存储和检索键/值数据。 在底层,sidecar API 使用可配置的状态存储组件来保存数据。 开发人员可以从不断增长的受支持状态存储集合中选择,其中包括 Azure Cosmos DB、SQL Server 和 Cassandra。

可以使用 HTTP 或 gRPC 调用 API。 使用以下 URL 调用 HTTP API:

http://localhost:<dapr-port>/v1.0/state/<store-name>/
  • <dapr-port>:Dapr 侦听的 HTTP 端口。
  • <store-name>:使用的状态存储组件的名称。

状态组件

Dapr支持的组件

为本地自承载开发初始化时,Dapr 将 Redis 注册为默认状态存储。 下面是默认状态存储配置的示例,配置文件位置为C:\Users\<username>\.dapr\components。 记下默认名称 statestore :

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"

项目演示

仍然使用 上一篇服务调用 的FrontEnd项目,新建StateController

using Dapr;
using Dapr.Client; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging; using System;
using System.Collections.Generic;
using System.Threading.Tasks; namespace FrontEnd.Controllers
{
[Route("[controller]")]
[ApiController]
public class StateController : ControllerBase
{
private readonly ILogger<StateController> _logger;
private readonly DaprClient _daprClient;
public StateController(ILogger<StateController> logger, DaprClient daprClient)
{
_logger = logger;
_daprClient = daprClient;
} // 获取一个值
[HttpGet]
public async Task<ActionResult> GetAsync()
{
var result = await _daprClient.GetStateAsync<string>("statestore", "guid");
return Ok(result);
} //保存一个值
[HttpPost]
public async Task<ActionResult> PostAsync()
{
await _daprClient.SaveStateAsync<string>("statestore", "guid", Guid.NewGuid().ToString(), new StateOptions() { Consistency = ConsistencyMode.Strong });
return Ok("done");
} //删除一个值
[HttpDelete]
public async Task<ActionResult> DeleteAsync()
{
await _daprClient.DeleteStateAsync("statestore", "guid");
return Ok("done");
} //通过tag防止并发冲突,保存一个值
[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");
} //通过tag防止并发冲突,删除一个值
[HttpDelete("withtag")]
public async Task<ActionResult> DeleteWithTagAsync()
{
var (value, etag) = await _daprClient.GetStateAndETagAsync<string>("statestore", "guid");
return Ok(await _daprClient.TryDeleteStateAsync("statestore", "guid", etag));
} // 从绑定获取一个值,健值name从路由模板获取
[HttpGet("frombinding/{name}")]
public async Task<ActionResult> GetFromBindingAsync([FromState("statestore", "name")] StateEntry<string> state)
{
return Ok(state.Value);
} // 根据绑定获取并修改值,健值name从路由模板获取
[HttpPost("withbinding/{name}")]
public async Task<ActionResult> PostWithBindingAsync([FromState("statestore", "name")] StateEntry<string> state)
{
state.Value = Guid.NewGuid().ToString();
return Ok(await state.TrySaveAsync());
} // 获取多个个值
[HttpGet("list")]
public async Task<ActionResult> GetListAsync()
{
var result = await _daprClient.GetBulkStateAsync("statestore", new List<string> { "guid" }, 10);
return Ok(result);
} // 删除多个个值
[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");
}
}
}

cmd运行

dapr run --dapr-http-port 3501 --app-port 5001  --app-id frontend dotnet  .\FrontEnd\bin\Debug\net5.0\FrontEnd.dll

可通过postman调用sidecar的endpoint

查看store存储中的内容

进入容器内部

docker exec -it dapr_redis /bin/sh

调用redis-cli

redis-cli

查看所有key

keys *

可以看到有"frontend||guid"这个key,所以状态在redis中存储中Name的规则是appName||keyName,这样可以防止不同app的键冲突

我们通过type key查看下这个键的类型,可以发现他是一个hash

127.0.0.1:6379> type frontend||guid
hash

再通过hgetall key查看他的数据,发现有两个键,一个data,一个version

127.0.0.1:6379> hgetall  frontend||guid
1) "data"
2) "\"e17b3e06-ba30-42c5-8960-48511c70b496\""
3) "version"
4) "1"

data很明显是存入的数据,version呢?现在猜测是防止并发冲突的etag,我们下面来验证一下

在StateController中新增接口

        // 获取一个值和etag
[HttpGet("withetag")]
public async Task<ActionResult> GetWithEtagAsync()
{
var (value,etag) = await _daprClient.GetStateAndETagAsync<string>("statestore", "guid");
return Ok($"value is {value}, etag is {etag}");
}

通过dapr重启这个app,并调用withetag api,很明显redis中version与etag相等,初步印证我们的猜测

我们可以通过post方法修改一下guid这个key,修改后etag会变更,再来看一下redis中version和etag是不是一个东西

首先调用POST方法修改值

再调用withetag方法,看下etag,发现etag变成了2

在比较一下redis中的version

127.0.0.1:6379> hgetall  frontend||guid
1) "data"
2) "\"36a55558-35c3-402c-ac9e-615014eb6904\""
3) "version"
4) "2"

现在可以确定etag就是redis中的version

Dapr实战(三)状态管理的更多相关文章

  1. 通过Dapr实现一个简单的基于.net的微服务电商系统(五)——一步一步教你如何撸Dapr之状态管理

    状态管理和上一章的订阅发布都算是Dapr相较于其他服务网格框架来讲提供的比较特异性的内容,今天我们来讲讲状态管理. 目录:一.通过Dapr实现一个简单的基于.net的微服务电商系统 二.通过Dapr实 ...

  2. Flutter实战视频-移动电商-24.Provide状态管理基础

    24.Provide状态管理基础 Flutter | 状态管理特别篇 —— Provide:https://juejin.im/post/5c6d4b52f265da2dc675b407?tdsour ...

  3. Flutter移动电商实战 --(24)Provide状态管理基础

    Flutter | 状态管理特别篇 —— Provide:https://juejin.im/post/5c6d4b52f265da2dc675b407?tdsourcetag=s_pcqq_aiom ...

  4. Blazor+Dapr+K8s微服务之状态管理

    1         状态管理服务器端接口 1.1         添加Dapr.AspNetCore包 在DaprTest1.Server项目中添加Dapr.AspNetCore包,该包实现了ASP. ...

  5. 手把手教你学Dapr - 5. 状态管理

    上一篇:手把手教你学Dapr - 4. 服务调用 介绍 使用状态管理,您的应用程序可以将数据作为键/值对存储在支持的状态存储中. 您的应用程序可以使用 Dapr 的状态管理 API 使用状态存储组件来 ...

  6. HttpClient4.3教程 第三章 Http状态管理

    最初,Http被设计成一个无状态的,面向请求/响应的协议,所以它不能在逻辑相关的http请求/响应中保持状态会话.由于越来越多的系统使用http协议,其中包括http从来没有想支持的系统,比如电子商务 ...

  7. hadoop基础----hadoop实战(七)-----hadoop管理工具---使用Cloudera Manager安装Hadoop---Cloudera Manager和CDH5.8离线安装

    hadoop基础----hadoop实战(六)-----hadoop管理工具---Cloudera Manager---CDH介绍 简介 我们在上篇文章中已经了解了CDH,为了后续的学习,我们本章就来 ...

  8. Flutter | 状态管理特别篇——Provide

    前言 今天偶然发现在谷歌爸爸的仓库下出现了一个叫做flutter-provide的状态管理框架,2月8日才第一次提交,非常新鲜.在简单上手之后感觉就是一个字--爽!所以今天就跟大家分享一下这个新的状态 ...

  9. 为了弄懂Flutter的状态管理, 我用10种方法改造了counter app

    为了弄懂Flutter的状态管理, 我用10种方法改造了counter app 本文通过改造flutter的counter app, 展示不同的状态管理方法的用法. 可以直接去demo地址看代码: h ...

随机推荐

  1. ECDSA—模加减模块

    如果a,b GF(P),则加法运算a+b=r (mod p),其中r满足0<r<p-1,即a+b除以p的余数,该操作成为模p加法.对于模减运算可以视为另类的模加运算,即a+(-b)=k ( ...

  2. 安鸾CTF-cookies注入

    什么是cookie注入? cookie注入的原理是:修改cookie的值进行注入 cookie注入其原理也和平时的注入一样,只不过注入参数换成了cookie 例如:PHP $_REQUEST 变量变量 ...

  3. 更好地使用Atom支持基于Jupyter的Python开发

    有关于使用Atom进行Python开发的网上资料比较少,最近发现使用Atom结合Hydrogen插件进行Python开发,尤其是数据挖掘相关的工作,整体体验要好于Vscode,Vscode虽然说也有连 ...

  4. 零基础学Java之Java学习笔记(二):Java快速入门

    提出要求: 开发一个 HelloWorld.java 程序,可以输出 "Hello,world!" 开发步骤: (1)将 Java 代码编写到扩展名为 HelloWorld.jav ...

  5. Pikachu-暴力破解模块

    一.概述 "暴力破解"是一攻击具手段,在web攻击中,一般会使用这种手段对应用系统的认证信息进行获取. 其过程就是使用大量的认证信息在认证接口进行尝试登录,直到得到正确的结果. 为 ...

  6. NOIP 模拟 $16\; \rm God Knows$

    题解 \(by\;zj\varphi\) 对于这道题,不难想到可以用 \(dp\),就是求一个最小权极长上升子序列 设 \(dp_i\) 表示最后一个选 \(i\) 时,覆盖前 \(i\) 条边的最小 ...

  7. 获取访问者真实ip地址?我觉得不可能

    我们真的能通过请求来获取用户真实的ip地址嘛? 答案是不能,如果能,肯定是我学的不够深入,欢迎交流指正. 那么写这篇文章的意义是什么?我们接着往下看. IP地址相当于电脑在网络上的身份证,但事实上IP ...

  8. cad转换成png,svg

    1.设置仓库可以在setting.xml中设置(也可以在pom中设置,设置项即可) <mirror> <id>AsposeJavaAPI</id> <name ...

  9. COM笔记-CoCreateInstance

    CoCreateInstance 创建组件的最简单的方法是使用CoCreateInstance函数. 在COM库中包含一个用于创建组件的名为CoCreateInstance的函数.此函数需要一个CLS ...

  10. C++ 三数之和

    来自leecode做题时,发现的双指针用法,觉得挺有意思所以记录一下 链接:https://leetcode-cn.com/problems/3sum 题目: 给你一个包含 n 个整数的数组 nums ...