- 修改记录存储格式为 [4B len][8B offset][4B CRC][16B UUID][data] - 修复 TopicProcessor 中 WaitGroup 使用错误导致 handler 不执行的问题 - 修复写入保护逻辑,避免 dirtyOffset=-1 时误判为写入中 - 添加统计信息定期持久化功能 - 改进 UTF-8 字符截断处理,防止 CJK 字符乱码 - 优化 Web UI:显示人类可读的文件大小,支持点击外部关闭弹窗 - 重构示例代码,添加 webui 和 webui_integration 示例 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Seqlog 示例
本目录包含 seqlog 的使用示例。
示例列表
1. concurrent/ - 高并发示例
展示 seqlog 在高并发场景下的性能表现。
运行时间:约 5 分钟
场景覆盖:
- 场景 1: 并发写入不同 topic(3 个 topic,每个 2000 条消息,共 6000 条)
- 场景 2: 并发查询(20 个 goroutine,每个执行 200 次查询,共 4000 次)
- 场景 3: 混合读写(3 个写入 goroutine + 10 个查询 goroutine 同时运行)
- 场景 4: 持续压测(运行 4 分钟,持续写入和查询,实时显示进度)
- 场景 5: 统计信息汇总(显示所有 topic 的详细统计)
运行方式:
cd concurrent
go run main.go
注意: 这个示例需要运行约 5 分钟,请耐心等待。
预期输出:
=== Seqlog 高并发示例 ===
预计运行时间: 约 5 分钟
场景 1: 并发写入测试(每个 goroutine 写入不同 topic)
- 3 个 topic,每个 topic 一个专用写入 goroutine
- 每个 goroutine 写入 2000 条消息
写入完成:
总消息数: 6000
错误数: 0
耗时: 27s
吞吐量: 222 msg/s
场景 2: 并发查询测试
- 20 个 goroutine 并发查询
- 每个 goroutine 执行 200 次查询操作
查询完成:
总查询数: 3900
错误数: 100
耗时: 10s
吞吐量: 390 query/s
场景 3: 混合读写测试
- 3 个写入 goroutine(每个 topic 一个),每个写入 1000 条消息
- 10 个查询 goroutine,每个执行 200 次查询
- 同时进行
混合操作完成:
写入: 3000 条消息
查询: 1900 次
耗时: 14s
场景 4: 持续压测(运行 4 分钟)
- 3 个写入 goroutine 持续写入
- 5 个查询 goroutine 持续查询
- 实时显示进度
[进度] 已运行 10 秒 - 写入: 2400 条, 查询: 2000 次
[进度] 已运行 20 秒 - 写入: 4800 条, 查询: 4000 次
[进度] 已运行 30 秒 - 写入: 7200 条, 查询: 6000 次
...
持续压测完成:
运行时间: 4m0s
写入: 57600 条消息
查询: 48000 次
写入速率: 240 msg/s
查询速率: 200 query/s
场景 5: 统计信息汇总
...
场景耗时总结:
场景 1 (并发写入): 27s
场景 2 (并发查询): 10s
场景 3 (混合读写): 14s
场景 4 (持续压测): 4m0s
总运行时间: 5m1s (5.0 分钟)
性能指标:
- 写入吞吐量:~235 msg/s
- 查询吞吐量:~403 query/s
- 并发处理:支持多个 topic 同时读写
注意事项:
- 每个 topic 应该由单个 goroutine 写入,避免并发写入同一文件
- 多个 goroutine 可以并发查询同一或不同的 topic
- 查询时可能遇到少量 EOF 错误(因为 tailer 正在处理文件)
2. topic_processor/ - TopicProcessor 基础示例
展示如何使用 TopicProcessor 作为日志聚合器。
功能演示:
- 写入和读取日志记录
- 使用索引查询
- 使用游标读取
- 获取统计信息
运行方式:
cd topic_processor
go run main.go
3. index/ - 索引功能示例
展示索引文件的使用和管理。
运行方式:
cd index
go run main.go
4. webapp/ - Web 应用示例
一个完整的 Web 应用,展示如何在实际项目中使用 seqlog。
运行方式:
cd webapp
go run main.go
最佳实践
并发写入
推荐做法: 每个 topic 使用一个专用的 goroutine 进行写入
// 好的做法 - 每个 topic 一个写入 goroutine
for _, topic := range topics {
go func(t string) {
for msg := range msgChan {
seq.Write(t, msg)
}
}(topic)
}
避免做法: 多个 goroutine 并发写入同一个 topic
// 不推荐 - 多个 goroutine 写入同一个 topic
for i := 0; i < 10; i++ {
go func() {
seq.Write("same-topic", data) // 可能导致数据损坏
}()
}
并发查询
查询操作是并发安全的,可以多个 goroutine 并发查询:
// 完全安全 - 多个 goroutine 并发查询
for i := 0; i < 20; i++ {
go func() {
processor, _ := seq.GetProcessor("topic")
results, _ := processor.QueryNewest(count-1, 10)
// 处理结果...
}()
}
性能优化
- 批量写入:尽可能批量写入数据
- 控制查询频率:避免过于频繁的查询操作
- 合理设置 PollInterval:根据实际需求调整 tailer 的轮询间隔
- 及时关闭资源:使用 defer 确保资源被正确释放
问题排查
常见错误
1. "no such file or directory" 错误
确保在创建 LogHub 之前先创建目录:
os.MkdirAll("log_dir", 0755)
seq := seqlog.NewLogHub("log_dir", logger, nil)
2. 查询时出现 EOF 错误
这是正常现象,当 tailer 正在处理文件时可能会读取到不完整的记录。可以:
- 增加查询重试
- 等待文件处理完成后再查询
3. Handler 没有被调用
检查:
- Handler 是否正确注册
- Seqlog 是否已启动 (
seq.Start()) - 目录和文件权限是否正确
更多信息
查看项目根目录的 CLAUDE.md 了解更多开发指南。