feat: 新增数据库持久化模块(Persistence),实现 Cursor + Retry 双层架构

## 核心功能

### 1. 数据库持久化支持
- 新增完整的 Persistence 模块 (api/persistence/)
- 支持三种持久化策略:
  * StrategyDBOnly - 仅落库,不存证
  * StrategyDBAndTrustlog - 既落库又存证(推荐)
  * StrategyTrustlogOnly - 仅存证,不落库
- 支持多数据库:PostgreSQL, MySQL, SQLite

### 2. Cursor + Retry 双层架构
- CursorWorker:第一道防线,快速发现新记录并尝试存证
  * 增量扫描 operation 表(基于时间戳游标)
  * 默认 10 秒扫描间隔,批量处理 100 条
  * 成功更新状态,失败转入重试队列
- RetryWorker:第二道防线,处理失败记录
  * 指数退避重试(1m → 2m → 4m → 8m → 16m)
  * 默认最多重试 5 次
  * 超限自动标记为死信

### 3. 数据库表设计
- operation 表:存储操作记录,支持可空 IP 字段
- trustlog_cursor 表:Key-Value 模式,支持多游标
- trustlog_retry 表:重试队列,支持指数退避

### 4. 异步最终一致性
- 应用调用立即返回(仅落库)
- CursorWorker 异步扫描并存证
- RetryWorker 保障失败重试
- 完整的监控和死信处理机制

## 修改文件

### 核心代码(11个文件)
- api/persistence/cursor_worker.go - Cursor 工作器(新增)
- api/persistence/repository.go - 数据仓储层(新增)
- api/persistence/schema.go - 数据库 Schema(新增)
- api/persistence/strategy.go - 策略管理器(新增)
- api/persistence/client.go - 客户端封装(新增)
- api/persistence/retry_worker.go - Retry 工作器(新增)
- api/persistence/config.go - 配置管理(新增)

### 修复内部包引用(5个文件)
- api/adapter/publisher.go - 修复 internal 包引用
- api/adapter/subscriber.go - 修复 internal 包引用
- api/model/envelope.go - 修复 internal 包引用
- api/model/operation.go - 修复 internal 包引用
- api/model/record.go - 修复 internal 包引用

### 单元测试(8个文件)
- api/persistence/*_test.go - 完整的单元测试
- 测试覆盖率:28.5%
- 测试通过率:49/49 (100%)

### SQL 脚本(4个文件)
- api/persistence/sql/postgresql.sql - PostgreSQL 建表脚本
- api/persistence/sql/mysql.sql - MySQL 建表脚本
- api/persistence/sql/sqlite.sql - SQLite 建表脚本
- api/persistence/sql/test_data.sql - 测试数据

### 文档(2个文件)
- README.md - 更新主文档,新增 Persistence 使用指南
- api/persistence/README.md - 完整的 Persistence 文档
- api/persistence/sql/README.md - SQL 脚本说明

## 技术亮点

1. **充分利用 Cursor 游标表**
   - 作为任务发现队列,非简单的位置记录
   - Key-Value 模式,支持多游标并发扫描
   - 时间戳天然有序,增量扫描高效

2. **双层保障机制**
   - Cursor:正常流程,快速处理
   - Retry:异常流程,可靠重试
   - 职责分离,监控清晰

3. **可空 IP 字段支持**
   - ClientIP 和 ServerIP 使用 *string 类型
   - 支持 NULL 值,符合数据库最佳实践
   - 使用 sql.NullString 正确处理

4. **完整的监控支持**
   - 未存证记录数监控
   - Cursor 延迟监控
   - 重试队列长度监控
   - 死信队列监控

## 测试结果

-  单元测试:49/49 通过 (100%)
-  代码覆盖率:28.5%
-  编译状态:无错误
-  支持数据库:PostgreSQL, MySQL, SQLite

## Breaking Changes

无破坏性变更。Persistence 模块作为可选功能,不影响现有代码。

## 版本信息

- 版本:v2.1.0
- Go 版本要求:1.21+
- 更新日期:2025-12-23
This commit is contained in:
ryan
2025-12-23 18:59:43 +08:00
parent d313449c5c
commit 88f80ffa5e
31 changed files with 6551 additions and 36 deletions

272
README.md
View File

@@ -1,12 +1,48 @@
# Trustlog-SDK 使用说明
# Go-Trustlog SDK
本 SDK 提供基于 [Watermill](https://watermill.io/) 抽象层的统一消息发送与接收能力,以及基于 gRPC 的操作查询和取证验证功能。
[![Go Version](https://img.shields.io/badge/Go-1.21+-blue.svg)](https://golang.org)
[![Test Status](https://img.shields.io/badge/tests-passing-brightgreen.svg)](.)
SDK 支持两种数据模型:
- **`Operation`**(操作记录):用于记录完整的业务操作,包含请求/响应体哈希,支持完整的取证验证
- **`Record`**(简单记录):用于记录简单的事件或日志,轻量级,适合日志和事件追踪场景
SDK 提供基于 [Watermill](https://watermill.io/) 抽象层的统一消息发送与接收能力,基于 gRPC 的操作查询和取证验证功能,以及**完整的数据库持久化支持**。
两种模型分别发布到不同的 Topic通过统一的 `HighClient``QueryClient` 进行操作。支持通过 Watermill Forwarder 将消息持久化到 SQL 数据库,实现事务性保证。
### 核心特性
#### 📦 双数据模型
- **`Operation`**(操作记录):完整的业务操作,包含请求/响应体哈希,支持完整的取证验证
- **`Record`**(简单记录):轻量级事件或日志记录,适合日志和事件追踪场景
#### 💾 数据库持久化(新增)
- **三种持久化策略**:仅落库、既落库又存证、仅存证
- **Cursor + Retry 双层架构**:异步最终一致性保障
- **多数据库支持**PostgreSQL、MySQL、SQLite
- **可靠重试机制**:指数退避 + 死信队列
#### 🔄 消息发布
- **直接发布**:通过 Pulsar Publisher 发送到对应的 Topic
- **事务性发布**:使用 Watermill Forwarder 持久化到 SQL保证事务性
#### 🔍 查询验证
- **统一查询客户端**:单一连接池同时支持 Operation 和 Record 查询
- **流式验证**:实时获取取证验证进度
- **负载均衡**:多服务器轮询分发
---
## 📋 目录
- [安装](#-安装)
- [核心概念](#-核心概念)
- [使用场景](#-使用场景)
- [快速开始](#-快速开始)
- [HighClient 使用(消息发布)](#1-highclient-使用消息发布)
- [QueryClient 使用(统一查询)](#2-queryclient-使用统一查询客户端)
- [Persistence 使用(数据库持久化)](#3-persistence-使用数据库持久化) ⭐ 新增
- [Subscriber 使用(消息订阅)](#4-subscriber-使用消息订阅)
- [Forwarder 事务性发布](#5-forwarder-事务性发布sql持久化)
- [完整示例](#-完整示例)
- [操作类型枚举](#-操作类型枚举)
- [注意事项](#-注意事项)
- [架构图](#-架构图)
---
@@ -360,6 +396,10 @@ lowPublisher := client.GetLow()
#### 2.1 创建 QueryClient
`QueryClient` 是统一的查询客户端,同时支持 **Operation操作****Record记录** 两种服务的查询和验证。使用单一连接池,两种服务共享同一组 gRPC 连接。
#### 2.1 创建 QueryClient
##### 单服务器模式
```go
import (
@@ -586,7 +626,167 @@ recGrpcClient := queryClient.GetLowLevelRecordClient()
---
### 3. Subscriber 使用(消息订阅)
### 3. Persistence 使用(数据库持久化)⭐ 新增
**Persistence 模块**提供完整的数据库持久化支持,实现 **Cursor + Retry 双层架构**,保证异步最终一致性。
#### 3.1 快速开始
```go
import (
"context"
"time"
"go.yandata.net/iod/iod/go-trustlog/api/persistence"
"go.yandata.net/iod/iod/go-trustlog/api/model"
)
func main() {
ctx := context.Background()
// 创建 Persistence Client
client, err := persistence.NewPersistenceClient(ctx, persistence.PersistenceClientConfig{
Publisher: publisher, // Pulsar Publisher
Logger: logger,
EnvelopeConfig: envelopeConfig, // SM2 签名配置
DBConfig: persistence.DBConfig{
DriverName: "postgres",
DSN: "postgres://user:pass@localhost:5432/trustlog?sslmode=disable",
},
PersistenceConfig: persistence.PersistenceConfig{
Strategy: persistence.StrategyDBAndTrustlog, // 既落库又存证
},
// 启用 Cursor 工作器(推荐)
EnableCursorWorker: true,
CursorWorkerConfig: &persistence.CursorWorkerConfig{
ScanInterval: 10 * time.Second, // 10秒扫描一次
BatchSize: 100, // 每批处理100条
MaxRetryAttempt: 1, // Cursor阶段快速失败
},
// 启用 Retry 工作器(必需)
EnableRetryWorker: true,
RetryWorkerConfig: &persistence.RetryWorkerConfig{
RetryInterval: 30 * time.Second, // 30秒重试一次
MaxRetryCount: 5, // 最多重试5次
},
})
if err != nil {
panic(err)
}
defer client.Close()
// 发布操作(立即返回,异步存证)
clientIP := "192.168.1.100"
serverIP := "10.0.0.1"
op := &model.Operation{
OpID: "op-001",
OpType: model.OpTypeCreate,
Doid: "10.1000/repo/obj",
ProducerID: "producer-001",
OpSource: model.OpSourceDOIP,
DoPrefix: "10.1000",
DoRepository: "repo",
ClientIP: &clientIP, // 可空
ServerIP: &serverIP, // 可空
}
if err := client.OperationPublish(ctx, op); err != nil {
panic(err)
}
// ✅ 落库成功CursorWorker 会自动异步存证
println("操作已保存,正在异步存证...")
}
```
#### 3.2 三种持久化策略
| 策略 | 说明 | 适用场景 |
|------|------|----------|
| **StrategyDBOnly** | 仅落库,不存证 | 历史数据存档、审计日志 |
| **StrategyDBAndTrustlog** | 既落库又存证(异步) | ⭐ 生产环境推荐 |
| **StrategyTrustlogOnly** | 仅存证,不落库 | 轻量级场景 |
#### 3.3 Cursor + Retry 双层架构
```
应用调用
仅落库(立即返回)
CursorWorker第一道防线
├── 增量扫描 operation 表
├── 快速尝试存证
├── 成功 → 更新状态
└── 失败 → 加入 retry 表
RetryWorker第二道防线
├── 扫描 retry 表
├── 指数退避重试
├── 成功 → 删除 retry 记录
└── 失败 → 标记死信
```
**优势**
- ✅ 充分利用 cursor 游标表作为任务发现队列
- ✅ 双层保障确保最终一致性
- ✅ 性能优秀,扩展性强
- ✅ 监控清晰,易于维护
#### 3.4 数据库表设计
**operation 表**(必需):
- 存储所有操作记录
- `trustlog_status` 字段标记存证状态
- `client_ip`, `server_ip` 可空字段(仅落库)
**trustlog_cursor 表**(核心):
- Key-Value 模式,支持多游标
- 使用时间戳作为游标值
- 作为任务发现队列
**trustlog_retry 表**(必需):
- 存储失败的重试记录
- 支持指数退避
- 死信队列
#### 3.5 监控和查询
```go
// 查询未存证记录数
var count int
db.QueryRow(`
SELECT COUNT(*)
FROM operation
WHERE trustlog_status = 'NOT_TRUSTLOGGED'
`).Scan(&count)
// 查询重试队列长度
db.QueryRow(`
SELECT COUNT(*)
FROM trustlog_retry
WHERE retry_status IN ('PENDING', 'RETRYING')
`).Scan(&count)
// 查询死信记录
rows, _ := db.Query(`
SELECT op_id, retry_count, error_message
FROM trustlog_retry
WHERE retry_status = 'DEAD_LETTER'
`)
```
#### 3.6 详细文档
- 📘 [Persistence 完整文档](api/persistence/README.md)
- 🚀 [快速开始指南](PERSISTENCE_QUICKSTART.md)
- 🏗️ [架构设计文档](api/persistence/ARCHITECTURE_V2.md)
- 💾 [SQL 脚本说明](api/persistence/sql/README.md)
---
### 4. Subscriber 使用(消息订阅)
> **注意**:通常业务代码不需要直接使用 Subscriber除非需要原始的 Watermill 消息处理。
@@ -645,7 +845,7 @@ for msg := range msgChan {
---
### 4. Forwarder 事务性发布SQL持久化
### 5. Forwarder 事务性发布SQL持久化
使用 Watermill Forwarder 可以将消息先持久化到 SQL 数据库,然后异步发送到 Pulsar保证消息的事务性和可靠性。
这在需要确保消息不丢失的场景下非常有用。
@@ -907,6 +1107,9 @@ model.OpTypeOCQueryRouter
12. **Record 支持**
除了 OperationSDK 现在也支持 Record 类型的发布、查询和验证,两种服务使用同一个 QueryClient。
13. **数据库持久化** ⭐ 新增
完整的数据库持久化支持Cursor + Retry 双层架构,保证异步最终一致性,支持 PostgreSQL、MySQL、SQLite。
---
## 🔄 架构图
@@ -964,4 +1167,57 @@ model.OpTypeOCQueryRouter
- 减少连接数,降低服务器压力
```
### 持久化架构Cursor + Retry 双层模式)⭐ 新增
```
[应用调用 OperationPublish()]
[保存到 operation 表状态NOT_TRUSTLOGGED]
[立即返回成功]
[异步处理开始]
[CursorWorker每10秒]
├── 增量扫描 operation 表
├── 尝试发送到存证系统
├── 成功 → 更新状态为 TRUSTLOGGED
└── 失败 → 加入 trustlog_retry 表
[RetryWorker每30秒]
├── 扫描 trustlog_retry 表
├── 指数退避重试1m → 2m → 4m → 8m → 16m
├── 成功 → 删除 retry 记录
└── 失败 → 标记为 DEAD_LETTER
优势:
- ✅ 充分利用 cursor 游标表作为任务发现队列
- ✅ 双层保障确保最终一致性
- ✅ 性能优秀(增量扫描 + 索引查询)
- ✅ 易于监控和运维
```
---
## 📚 相关文档
### 核心文档
- 📘 [Persistence 完整文档](api/persistence/README.md) - 数据库持久化详细说明
- 🚀 [快速开始指南](PERSISTENCE_QUICKSTART.md) - 5分钟上手教程
- 🏗️ [架构设计文档](api/persistence/ARCHITECTURE_V2.md) - Cursor + Retry 双层架构
- 💾 [SQL 脚本说明](api/persistence/sql/README.md) - 数据库脚本文档
- ✅ [修复记录](FIXES_COMPLETED.md) - 问题修复历史
### 测试状态
-**49/49** 单元测试通过
- ✅ 代码覆盖率: **28.5%**
- ✅ 支持数据库: PostgreSQL, MySQL, SQLite
---
## 📝 版本信息
- **当前版本**: v2.1.0
- **Go 版本要求**: 1.21+
- **最后更新**: 2025-12-23
---