feat: 完善数据库持久化与存证功能

主要更新:

1. 数据库持久化功能
   - 支持三种策略:仅落库、既落库又存证、仅存证
   - 实现 Cursor Worker 异步扫描和存证机制
   - 实现 Retry Worker 失败重试机制
   - 支持 PostgreSQL、MySQL、SQLite 等多种数据库
   - 添加 ClientIP 和 ServerIP 字段(可空,仅落库)

2. 集群并发安全
   - 使用 SELECT FOR UPDATE SKIP LOCKED 防止重复处理
   - 实现 CAS (Compare-And-Set) 原子状态更新
   - 添加 updated_at 字段支持并发控制

3. Cursor 初始化优化
   - 自动基于历史数据初始化 cursor
   - 确保不遗漏任何历史记录
   - 修复 UPSERT 逻辑

4. 测试完善
   - 添加 E2E 集成测试(含 Pulsar 消费者验证)
   - 添加 PostgreSQL 集成测试
   - 添加 Pulsar 集成测试
   - 添加集群并发安全测试
   - 添加 Cursor 初始化验证测试
   - 补充大量单元测试,提升覆盖率

5. 工具脚本
   - 添加数据库迁移脚本
   - 添加 Cursor 状态检查工具
   - 添加 Cursor 初始化工具
   - 添加 Pulsar 消息验证工具

6. 文档清理
   - 删除冗余文档,只保留根目录 README

测试结果:
- 所有 E2E 测试通过(100%)
- 数据库持久化与异步存证流程验证通过
- 集群环境下的并发安全性验证通过
- Cursor 自动初始化和历史数据处理验证通过
This commit is contained in:
ryan
2025-12-24 15:31:11 +08:00
parent 88f80ffa5e
commit 4b72a37120
60 changed files with 6160 additions and 1313 deletions

View File

@@ -1,361 +0,0 @@
# Trustlog 数据库建表脚本
本目录包含 go-trustlog 数据库持久化模块的建表 SQL 脚本。
---
## 📁 文件列表
| 文件 | 数据库 | 说明 |
|------|--------|------|
| `postgresql.sql` | PostgreSQL 12+ | PostgreSQL 数据库建表脚本 |
| `mysql.sql` | MySQL 8.0+ / MariaDB 10+ | MySQL 数据库建表脚本 |
| `sqlite.sql` | SQLite 3+ | SQLite 数据库建表脚本 |
| `test_data.sql` | 通用 | 测试数据插入脚本 |
---
## 📊 表结构说明
### 1. operation 表
操作记录表,用于存储所有的操作记录。
**关键字段**:
- `op_id` - 操作ID主键
- `client_ip` - **客户端IP可空仅落库不存证**
- `server_ip` - **服务端IP可空仅落库不存证**
- `trustlog_status` - **存证状态NOT_TRUSTLOGGED / TRUSTLOGGED**
- `timestamp` - 操作时间戳
**索引**:
- `idx_operation_timestamp` - 时间戳索引
- `idx_operation_status` - 存证状态索引
- `idx_operation_doid` - DOID 索引
### 2. trustlog_cursor 表
游标表,用于跟踪处理进度,支持断点续传。
**关键字段**:
- `id` - 游标ID固定为1
- `last_processed_id` - 最后处理的操作ID
- `last_processed_at` - 最后处理时间
**特性**:
- 自动初始化一条记录id=1
- 用于实现最终一致性
### 3. trustlog_retry 表
重试表,用于管理失败的存证操作。
**关键字段**:
- `op_id` - 操作ID主键
- `retry_count` - 重试次数
- `retry_status` - 重试状态PENDING / RETRYING / DEAD_LETTER
- `next_retry_at` - 下次重试时间(指数退避)
- `error_message` - 错误信息
**索引**:
- `idx_retry_status` - 重试状态索引
- `idx_retry_next_retry_at` - 下次重试时间索引
---
## 🚀 使用方法
### PostgreSQL
```bash
# 方式1: 使用 psql 命令
psql -U username -d database_name -f postgresql.sql
# 方式2: 使用管道
psql -U username -d database_name < postgresql.sql
# 方式3: 在 psql 中执行
psql -U username -d database_name
\i postgresql.sql
```
### MySQL
```bash
# 方式1: 使用 mysql 命令
mysql -u username -p database_name < mysql.sql
# 方式2: 在 mysql 中执行
mysql -u username -p
USE database_name;
SOURCE mysql.sql;
```
### SQLite
```bash
# 方式1: 使用 sqlite3 命令
sqlite3 trustlog.db < sqlite.sql
# 方式2: 在 sqlite3 中执行
sqlite3 trustlog.db
.read sqlite.sql
```
---
## 🔍 验证安装
每个 SQL 脚本末尾都包含验证查询,执行后可以检查:
### PostgreSQL
```sql
-- 查询所有表
SELECT tablename FROM pg_tables WHERE schemaname = 'public'
AND tablename IN ('operation', 'trustlog_cursor', 'trustlog_retry');
```
### MySQL
```sql
-- 查询所有表
SHOW TABLES LIKE 'operation%';
SHOW TABLES LIKE 'trustlog_%';
```
### SQLite
```sql
-- 查询所有表
SELECT name FROM sqlite_master
WHERE type='table'
AND name IN ('operation', 'trustlog_cursor', 'trustlog_retry');
```
---
## 📝 字段说明
### operation 表新增字段
#### client_ip 和 server_ip
**特性**:
- 类型: VARCHAR(32) / TEXT (根据数据库而定)
- 可空: YES
- 默认值: NULL
**用途**:
- 记录客户端和服务端的 IP 地址
- **仅用于数据库持久化**
- **不参与存证哈希计算**
- **不会被序列化到 CBOR 格式**
**示例**:
```sql
-- 插入 NULL 值(默认)
INSERT INTO operation (..., client_ip, server_ip, ...)
VALUES (..., NULL, NULL, ...);
-- 插入 IP 值
INSERT INTO operation (..., client_ip, server_ip, ...)
VALUES (..., '192.168.1.100', '10.0.0.50', ...);
```
#### trustlog_status
**特性**:
- 类型: VARCHAR(32) / TEXT
- 可空: YES
- 可选值:
- `NOT_TRUSTLOGGED` - 未存证
- `TRUSTLOGGED` - 已存证
**用途**:
- 标记操作记录的存证状态
- 用于查询未存证的记录
- 支持最终一致性机制
---
## 🔄 常用查询
### 1. 查询未存证的操作
```sql
SELECT * FROM operation
WHERE trustlog_status = 'NOT_TRUSTLOGGED'
ORDER BY timestamp ASC
LIMIT 100;
```
### 2. 查询待重试的操作
```sql
SELECT * FROM trustlog_retry
WHERE retry_status IN ('PENDING', 'RETRYING')
AND next_retry_at <= NOW()
ORDER BY next_retry_at ASC
LIMIT 100;
```
### 3. 查询死信记录
```sql
SELECT
o.op_id,
o.doid,
r.retry_count,
r.error_message,
r.created_at
FROM operation o
JOIN trustlog_retry r ON o.op_id = r.op_id
WHERE r.retry_status = 'DEAD_LETTER'
ORDER BY r.created_at DESC;
```
### 4. 按 IP 查询操作
```sql
-- 查询特定客户端IP的操作
SELECT * FROM operation
WHERE client_ip = '192.168.1.100'
ORDER BY timestamp DESC;
-- 查询未设置IP的操作
SELECT * FROM operation
WHERE client_ip IS NULL
ORDER BY timestamp DESC;
```
### 5. 统计存证状态
```sql
SELECT
trustlog_status,
COUNT(*) as count
FROM operation
GROUP BY trustlog_status;
```
---
## 🗑️ 清理脚本
### 删除所有表
```sql
-- PostgreSQL / MySQL
DROP TABLE IF EXISTS trustlog_retry;
DROP TABLE IF EXISTS trustlog_cursor;
DROP TABLE IF EXISTS operation;
-- SQLite
DROP TABLE IF EXISTS trustlog_retry;
DROP TABLE IF EXISTS trustlog_cursor;
DROP TABLE IF EXISTS operation;
```
### 清空数据(保留结构)
```sql
-- 清空重试表
DELETE FROM trustlog_retry;
-- 清空操作表
DELETE FROM operation;
-- 重置游标表
UPDATE trustlog_cursor SET
last_processed_id = NULL,
last_processed_at = NULL,
updated_at = CURRENT_TIMESTAMP
WHERE id = 1;
```
---
## ⚠️ 注意事项
### 1. 字符集和排序规则MySQL
- 使用 `utf8mb4` 字符集
- 使用 `utf8mb4_unicode_ci` 排序规则
- 支持完整的 Unicode 字符
### 2. 索引长度MySQL
- `doid` 字段使用前缀索引 `doid(255)`
- 避免索引长度超过限制
### 3. 自增主键
- PostgreSQL: `SERIAL`
- MySQL: `AUTO_INCREMENT`
- SQLite: `AUTOINCREMENT`
### 4. 时间类型
- PostgreSQL: `TIMESTAMP`
- MySQL: `DATETIME`
- SQLite: `DATETIME` (存储为文本)
### 5. IP 字段长度
- 当前长度: 32 字符
- IPv4: 最长 15 字符 (`255.255.255.255`)
- IPv4 with port: 最长 21 字符 (`255.255.255.255:65535`)
- **IPv6: 最长 39 字符** - 如需支持完整 IPv6建议扩展到 64 字符
---
## 🔧 扩展建议
### 1. 如果需要支持完整 IPv6
```sql
-- 修改 client_ip 和 server_ip 字段长度
ALTER TABLE operation MODIFY COLUMN client_ip VARCHAR(64);
ALTER TABLE operation MODIFY COLUMN server_ip VARCHAR(64);
```
### 2. 如果需要分区表PostgreSQL
```sql
-- 按时间分区
CREATE TABLE operation_partitioned (
-- ... 字段定义 ...
) PARTITION BY RANGE (timestamp);
CREATE TABLE operation_2024_01 PARTITION OF operation_partitioned
FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');
```
### 3. 如果需要添加审计字段
```sql
-- 添加创建人和更新人
ALTER TABLE operation ADD COLUMN created_by VARCHAR(64);
ALTER TABLE operation ADD COLUMN updated_by VARCHAR(64);
ALTER TABLE operation ADD COLUMN updated_at TIMESTAMP;
```
---
## 📚 相关文档
- [PERSISTENCE_QUICKSTART.md](../../PERSISTENCE_QUICKSTART.md) - 快速入门
- [README.md](../README.md) - 详细技术文档
- [IP_FIELDS_USAGE.md](../IP_FIELDS_USAGE.md) - IP 字段使用说明
---
## ✅ 检查清单
安装完成后,请检查:
- [ ] 所有3个表都已创建
- [ ] 所有索引都已创建
- [ ] trustlog_cursor 表有初始记录id=1
- [ ] operation 表可以插入 NULL 的 IP 值
- [ ] operation 表可以插入非 NULL 的 IP 值
- [ ] 查询验证脚本能正常执行
---
**最后更新**: 2025-12-23
**版本**: v1.0.0

View File

@@ -12,6 +12,7 @@ CREATE TABLE IF NOT EXISTS operation (
producer_id VARCHAR(32),
request_body_hash VARCHAR(128),
response_body_hash VARCHAR(128),
op_hash VARCHAR(128), -- 操作哈希
sign VARCHAR(512),
op_source VARCHAR(10),
op_type VARCHAR(30),
@@ -21,7 +22,8 @@ CREATE TABLE IF NOT EXISTS operation (
server_ip VARCHAR(32), -- 服务端IP可空仅落库
trustlog_status VARCHAR(32), -- 存证状态NOT_TRUSTLOGGED / TRUSTLOGGED
timestamp TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -- 更新时间用于CAS
);
-- 创建索引