Dapr Outbox 执行流程
Dapr Outbox 是1.12中的功能。
本文只介绍Dapr Outbox 执行流程,Dapr Outbox基本用法请阅读官方文档 。本文中appID=order-processor,topic=orders
本文前提知识:熟悉Dapr状态管理、Dapr发布订阅和Outbox 模式。
Outbox 模式的核心是在同一个数据库事务中保存业务数据和待发布的事件消息,再由某个“定时任务”读取待发布的事件消息并发布事件(并删除数据库中事件消息)
相关文章:
.NET中实现Outbox模式的框架CAP,作者Savorboard
使用 dotnetcore/CAP 的本地消息表模式,圣杰
先在内部发布一个主题(topic)
要使用Dapr Outbox,在.NET中就是调用DaprClient的ExecuteStateTransactionAsync(...)方法(得先完成Outbox相关的配置!),调用此方法会完成事务操作(保存业务数据和待发布的事件消息)并发布事件消息。
string DAPR_STORE_NAME = "statestoresql";
var client = new DaprClientBuilder().Build();
var orderId = 1;
var order = new Order(orderId);
var bytes = JsonSerializer.SerializeToUtf8Bytes(order);
var upsert = new List<StateTransactionRequest>()
{
new StateTransactionRequest(orderId.ToString(), bytes, StateOperationType.Upsert)
};
// 保存状态,并发布事件消息
await client.ExecuteStateTransactionAsync(DAPR_STORE_NAME, upsert);
public record Order([property: JsonPropertyName("orderId")] int orderId);
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: orderpubsub # 发布订阅组件
spec:
type: pubsub.redis
version: v1
metadata:
- name: redisHost
value: localhost:6379
- name: redisPassword
value: ""
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: statestoresql # 状态组件
spec:
type: state.mysql
version: v1
metadata:
- name: connectionString
value: "root:mysecret@tcp(localhost:3306)/?allowNativePasswords=true"
- name: outboxPublishPubsub
value: orderpubsub
- name: outboxPublishTopic
value: orders
调用ExecuteStateTransactionAsync(...)方法时,此方法把请求转发给sidecar,sidecar会发布一个内部主题。所谓内部,就是供Dapr使用,用户不用操作;所谓主题(Topic)就是一个事件;此主题格式为:namespace + appID + topic + "outbox" ,假设appID=order-processor,topic=orders,则内部主题(Topic)名就是order-processorordersoutbox(namespace 是与k8s有关),此主题用于判断事务是否执行成功。
注:该内部主题(topic)默认和事件消息使用同一个Dapr发布/订阅组件,可以通过配置状态组件的元数据(metadata配置)字段outboxPubsub单独指定内部主题所使用的发布/订阅组件。相关配置请看官方文档
主题内容是CloudEvent格式,发布的事件数据如下(真正的待发布事件消息就是json中的data字段,后面就是读取的此值):
{
"data":"{\"orderId\":1}",
"datacontenttype":"text/plain",
"id":"outbox-a53e45f3-d646-4e4e-bcbf-0692ec7b9dd0",
"pubsubname":"orderpubsub",
"source":"order-processor",
"specversion":"1.0",
"time":"2024-01-25T17:12:31+08:00",
"topic":"",
"traceid":"",
"traceparent":"",
"tracestate":"",
"type":"com.dapr.event.sent"
}
有了事件的发布者,那事件的订阅者是谁呢?appID=order-processor的Dapr sidecar实例。可以是执行保存状态的sidecar程序,或者是appID=order-processor的其他sidecar。
在同一事务中保存状态和事件消息
在内部主题(Topic)发布
成功后,会在同一事务中保存状态和事件消息,也就是将方法client.ExecuteStateTransactionAsync(...)中的数据保存到数据库。id为outbox-a53e45f3-d646-4e4e-bcbf-0692ec7b9dd0的表示需待发布事件消息,id为order-processor||1表示状态数据。事件消息和状态数据保存在同一张表state中,在mysql中其表结构和数据如下所示。如果此内部主题(Topic)发布
失败,调用方直接抛异常,不会执行事务操作!state表不会有下面两条数据。"eyJvcmRlcklkIjoxfQ=="既是状态数据又是待发布的事件数据;经过Base64解码,得到该值为json格式,即:
{"orderId":1}
CREATE TABLE `state` (
`id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`value` json NOT NULL,
`isbinary` tinyint(1) NOT NULL,
`insertDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updateDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`eTag` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`expiredate` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `expiredate_idx`(`expiredate` ASC) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
| id | value | isbinary | insertDate | updateDate | eTag | expiredate |
|---|---|---|---|---|---|---|
| outbox-a53e45f3-d646-4e4e-bcbf-0692ec7b9dd0 | "0" | 0 | 2024-01-25 09:22:14 | 2024-01-25 09:22:14 | 07884eed-eb5d-4887-8399-051c71206ed5 | |
| order-processor||1 | "eyJvcmRlcklkIjoxfQ==" | 1 | 2024-01-25 09:12:31 | 2024-01-25 09:22:14 | 3d1e368f-f6d8-4ccd-946d-c10090c7cc42 |
内部主题(Topic)的订阅者发布事件消息
数据库事务执行成功后,什么时候把事件消息发布出去呢?
把事件消息发布出去是在内部主题(Topic)的订阅者中实现的,具体如下:
步骤X:appID为order-processor的sidecar接收到内部主题(Topic)发送的事件,然后通过查询判断id为outbox-a53e45f3-d646-4e4e-bcbf-0692ec7b9dd0的数据是否存在?
- 如果存在,表示状态数据和事件消息都已保存在mysql中,则发布
事件消息(事件数据就前面提到的data字段)。事件发布成功后,则删除id为outbox-a53e45f3-d646-4e4e-bcbf-0692ec7b9dd0的记录。 - 如果不存在就直接退出,停止后续操作;事件的订阅者会多次收到订阅消息,即重复
步骤X过程。
这里会有一个问题:接收到内部主题(Topic)后,状态和事件消息可能没有持久化到mysql(前面提到过,Dapr sidecar是先发布一个内部主题,再在同一事务中保存状态和事件消息)。所以获取状态执行以下重试策略。删除状态时也是此重试策略。
bo := &backoff.ExponentialBackOff{
InitialInterval: time.Millisecond * 500,// 初始间隔
MaxInterval: time.Second * 3, // 最大间隔。重试时间超过此值时,以此值为准
MaxElapsedTime: time.Second * 10, // 累计重试时间
Multiplier: 3, // 递增倍数
Clock: backoff.SystemClock,
RandomizationFactor: 0.1, // 随机因子
}
总结
Dapr Outbox 执行流程简单说就是:先发布一个内部事件,再执行保存业务数据和事件消息,内部事件的订阅者再发布真正的事件消息。Dapr轮询数据库中待发布事件消息是通过订阅一个内部主题(Topic)实现的。
因为状态保存和事件发布是在sidecar中执行,所以业务代码和事件消息不在同一个事务中!!!Dapr Outbox是把业务的状态数据和事件消息在同一个事务中保存,也就是代码client.ExecuteStateTransactionAsync(...);并且状态数据和事件消息是保存到同一张表state中。
参考:
Enable the transactional outbox pattern
Dapr Outbox 执行流程的更多相关文章
- 步步深入:MySQL架构总览->查询执行流程->SQL解析顺序
前言: 一直是想知道一条SQL语句是怎么被执行的,它执行的顺序是怎样的,然后查看总结各方资料,就有了下面这一篇博文了. 本文将从MySQL总体架构--->查询执行流程--->语句执行顺序来 ...
- 第二天 ci执行流程
第二天 ci执行流程 welcome 页面 this this->load 单入口框架index.php 两个文件夹 system application定义 定义常亮路径 载入 codeign ...
- 轻量级前端MVVM框架avalon - 执行流程2
接上一章 执行流程1 在这一大堆扫描绑定方法中应该会哪些实现? 首先我们看avalon能帮你做什么? 数据填充,比如表单的一些初始值,切换卡的各个面板的内容({{xxx}},{{xxx|html}}, ...
- [Java编程思想-学习笔记]第4章 控制执行流程
4.1 return 关键字return有两方面的用途:一方面指定一个方法结束时返回一个值:一方面强行在return位置结束整个方法,如下所示: char test(int score) { if ...
- ThinkPHP2.2框架执行流程图,ThinkPHP控制器的执行流程
ThinkPHP2.2框架执行原理.流程图在线手册 ThinkPHP控制器的执行流程 对用户的第一次URL访问 http://<serverIp>/My/index.php/Index/s ...
- 深入浅出Mybatis系列(十)---SQL执行流程分析(源码篇)
最近太忙了,一直没时间继续更新博客,今天忙里偷闲继续我的Mybatis学习之旅.在前九篇中,介绍了mybatis的配置以及使用, 那么本篇将走进mybatis的源码,分析mybatis 的执行流程, ...
- Servlet执行流程和生命周期【慕课网搬】
Servlet执行流程(GET方式为例) 首先用户客户端浏览器发出Get方式(点击超链接方式)向浏览器发出请求. 服务器接收到客户端点击超链接,接收到GET请求之后,服务器到WEB.xml中<s ...
- javascript事件执行流程分析
我一直想搞清楚事件在DOM中的传播方式,今天经高人指点终于明白一二.首先扒了一张图: 事件捕获过程:当我们点击TEXT时,首先是window->document->body->div ...
- asp.net MVC4的执行流程
MVC在底层和传统的asp.net是一致的,在底层之上,相关流程如下: 1)Global.asax里,MvcApplication对象的Application_Start()事件中,调用 RouteC ...
- 03Mybatis_mybatis框架原理——执行流程
mybatis的框架的原理(执行流程).
随机推荐
- Windows改变终端字体后,终端一片黑 的解决办法
使用Windows终端的时候总觉得字体不好看,于是乎按照网上的教程改了一下 注册表 计算机\HKEY_CURRENT_USER\Console%SystemRoot%_system32_cmd.exe ...
- Android Progressbar进度条样式调整为圆角矩形,且改变颜色
原文地址: Android Progressbar进度条样式调整为圆角矩形,且改变颜色 美工设计的进度条是圆角矩形的,与Android默认的样式有所区别,可以通过样式progressDrawable属 ...
- 【stras-one】星念漫画下载器
原文链接:[stras-one]星念漫画下载器 - Stars-One的杂货小窝 一款将在线漫画保存到本地的下载工具 应一位蓝奏云批量下载器的用户的要求,实现了这款漫画下载的工具开发, 一直没时间,鸽 ...
- 静态类使用@Resource注解注入
工作中需要,简单记录一下 @Component public class AccountUtil { private static AccountIdDao accountIdDao; @Resour ...
- Caffe源码编译,win10+vs2015+Ninja,C++接口测试(mnist),Python接口测试(mnist),(坑爹篇)
PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明 本文作为本人csdn blog的主站的备份.(Bl ...
- mysql迁移到pqsql笔记
在将MySQL迁移到PostgreSQL的过程中,遇到了一些问题,下面是一些简单的解决方案. 使用命令,初始化数据库,并设置postgres的密码 bin\initdb -E UTF-8 -A md5 ...
- 除gRPC之外的另一个选择,IceRPC-支持QUIC
作者引言 自从19年开始接处到RPC,当时完全没有相关概念,接触到的都是http,tcp等,当时公司用的是zeroc出品的ice框架,对应rpc非常强大,跨平台,跨语言.可惜的国内并不是主流,主流是g ...
- modelsim常用操作之波形仿真
modelsim波形仿真的新手问题 1.实验目的 在刚接触modelsim时,被其繁复的操作流程所困,一度只能依靠在quartus中修改代码编译后再重启modelsim,自动导入才能得到波形.这样的操 ...
- X-Y问题
什么是X-Y问题 X-Y问题就是有人想解决问题X,他觉得Y可能是解决X的方法但不知道Y怎么做:在我们的工作中,需求方给出的来的是Y,而软件工程师不知道需要解决的X是什么. 我理解的X-Y问题是没有找到 ...
- 如何在Java中读取超过内存大小的文件
读取文件内容,然后进行处理,在Java中我们通常利用 Files 类中的方法,将可以文件内容加载到内存,并流顺利地进行处理.但是,在一些场景下,我们需要处理的文件可能比我们机器所拥有的内存要大.此时, ...