Seata 应用部分源码分析
为了清晰理解 Seata 工作机制,在出现问题时能快速找到原因并给出对应的解决方案,下面对 Seata 应用部分源码进行分析。这部分主要关注 Seata 在应用中的介入部分,对于 TM、RM 的实现部分分析会另开一文进行记录。这里主要针对 AT 模式进行展开,其他模式可基于相似的起点开始源码的阅读和学习。
为了清晰理解 Seata 工作机制,在出现问题时能快速找到原因并给出对应的解决方案,下面对 Seata 应用部分源码进行分析。这部分主要关注 Seata 在应用中的介入部分,对于 TM、RM 的实现部分分析会另开一文进行记录。这里主要针对 AT 模式进行展开,其他模式可基于相似的起点开始源码的阅读和学习。
在数据库中存储的数据,最终需要都需要落到磁盘上进行持久化保存。这里对 MySQL 的数据存储结构进行分析。
MySQL 中,表数据由存储引擎负责存取。下面的数据存储结构以 InnoDB 存储引擎为准。在 InnoDB 存储引擎中,数据保存在 /var/lib/mysql/ 目录下,对于创建的每个数据库,会用数据库名称创建一个同名目录。该目录中,包括 db.opt 文件存储数据库的默认字符编码等信息。另外,为每个数据表创建同名的 frm 和 ibd 两个文件。frm 文件存储数据表的元数据,包括表结构等信息。ibd 文件存储数据表的表数据,也称为表空间文件。
Slint 的应用架构如下图所示:
Slint 应用使用为 UI 设计的 Slint DSL 对 UI 进行描述。这些 UI 代码通过若干 .slint 文件构成,每个 .slint 文件中可以描述若干个组件,这些组件之间进行复用,并构造一个完整的 UI 界面。
为了展示 Slint 界面,需要通过 Slint 编译器将 .slint 文件编译为 Slint 的内部表示后原生运行。这个编译的过程可以在应用程序编译时完成,也可以在程序运行时再进行。
在运行时内部,按 .slint 描述的界面元素,构成一棵 UI 元素树,在进行渲染时便基于这个 UI 元素树进行。
Slint 使用的属性、回调、模型元素也在运行时内部维护。这些元素也是应用程序代码与 UI 之间沟通的桥梁。用户界面与应用程序逻辑的交互全部通过这几类元素完成。
基于最终的 UI 元素树可以计算得到每个像素值,这些值需要展示到显示设备上。这个计算每个像素值并向显示设备传输的过程便由渲染器实现。
为了相互用户的输入,需要与输入设备交互,并将这些交互封装为输入事件传入运行时,从而分发到对应的处理函数,并产生最终的交互。
在使用数据库进行业务开发时,常常提到“事务”这一概念。这里的事务指的是对数据库的一组读写操作,并且这一系列操作需要具有 ACID 特性。
ACID 由 Atomicity(原子性)、Consistency(一致性)、Isolation(隔离性)、Durability(持久性)四种特性组成。
Atomicity(原子性):构成事务的一组读写操作要么全部成功,要么全部失败。在成功提交时,数据修改落到数据库中,事务中的操作全部成功。当出现失败时,事务回滚将所有数据恢复到执行前的状态,所有操作全部失败。
Consistency(一致性):在数据库执行后,无论成功还是失败,数据库的完整性不会被破坏。数据库中的数据持续满足数据定义给出的要求。
Isolation(隔离性):在多个事务并发执行时,他们之间的干扰要满足一定的要求。这些不同的要求构成了不同的隔离级别。隔离级别包括:读未提交、读已提交、可重复读、可串行化。
Durability(持久性):在事务成功提交后,即使数据库管理系统发生故障,在恢复运行后,事务中提交的修改也不会丢失。
曾经编写过一篇关于 Rust 异步的文章,以非常肤浅的视角对 Rust 的异步原理进行了描述。现在将 Tokio 官方教程的其中一篇进行翻译,其中非常深入地讲解了 Rust 异步的原理。
原文链接:https://tokio.rs/tokio/tutorial/async
文章内容:
至此,我们已经完成了对异步 Rust 和 Tokio 的相当全面的介绍。现在我们将深入研究 Rust 的异步运行时模型。在本教程的一开始,我们暗示异步 Rust 采用了一种独特的方法。现在,我们来解释一下这意味着什么。
根据 Slint 提供的 memory 示例程序学习 Slint GUI 编程。
与许多网络协议一样,Redis客户端和服务器端之间的通信可以使用帧结构作为基本的构成指令。mini-redis中命令模块在命令解析时就是从帧结构出发。本篇就对帧的解析进行分析和实现。
Redis客户端与服务端之间的通信,整体上属于请求-响应模型,但是引入了流水线、推送等一些特例情况。在Redis的请求和响应中具有一些固定的形态。在请求中,命令总是表示为批量字符串的的数组,响应则可以是帧结构中的各种类型。每种类型消息的第一个字节总是用来标识消息的类型。\r\n
作为协议中的终止符,用于划分不同部分。
下面是一些消息的格式或示例,在文章的后半部分需要对这些命令进行解析并封装为 Rust 中的数据结构。
1 | +OK\r\n |
这些消息代表的类型分别为简单字符串、错误、整型、批量字符串、Null、数组。在 mini-redis 支持的几个命令中,利用这些帧结构即可实现支持的几个命令。
概述篇对mini-redis的模块结构进行了介绍,并构建了具有日志能力的基本项目结构。存储篇将对mini-redis的数据存储进行分析,并在存储上实现其需要对外提供的功能。
在分析存储模块的实现前,我们首先对存储模块所需提供的功能进行分析。mini-redis 在整体上提供了两套功能,带有过期能力的KV存储、发布-订阅功能。
在KV存储方面,需要提供根据键获取值的 get 功能和提供键、值以及可选的有效期的 set 功能。同时,需要在请求-响应之外提供按照过期时间清理过期数据的能力。
在发布-订阅方面,需要提供 subscribe 功能用于订阅特定通道,从而在给定的通道上发布消息时进行接收;还需要提供 publish 功能用于向给定的通道上发布消息。
由于不同客户端的处理任务需要共享相同的存储,存储模块需要能够在不同任务间共享,并保证线程安全。