Skip to content

feat: 重构流量历史记录优化性能#2226

Open
Yundi339 wants to merge 1 commit intozhongyang219:masterfrom
Yundi339:fix_log
Open

feat: 重构流量历史记录优化性能#2226
Yundi339 wants to merge 1 commit intozhongyang219:masterfrom
Yundi339:fix_log

Conversation

@Yundi339
Copy link

@Yundi339 Yundi339 commented Jan 4, 2026

相关

#2225
我在排查磁盘健康寿命的时候,发现TrafficMonitor存在频繁写入磁盘的问题,虽然是30s写入一次,但是全量写入的机制,实际上不友好的。

提交目的

解决 history_traffic.dat 文件频繁写入问题,通过引入增量保存机制,在保持数据安全性的前提下,大幅减少磁盘I/O操作。

细节说明

1. 数据结构重构

(目的是减少代码的复杂度,不用每次都更新数组,直接链表进行维护)

  • 分离存储设计: 将流量记录分为两部分
    • m_today_traffic: 单独存储今天的记录(频繁更新)
    • m_history_traffics: 历史记录链表(按日期从大到小排序,较少更新)
    • m_traffics_cache: 缓存合并后的完整列表(按需更新)

2. 新增增量保存机制

(这是我加入的核心功能,可以有效减少磁盘写入频率,原先的全量保存是写一点就触发一次缓冲区同步,对磁盘IO来说是很不友好的)

  • 新增方法: SaveTodayOnly()
    • 只更新文件的前两行:
      1. 第一行:lines计数(今天的记录 + 历史记录数量)
      2. 第二行:今天的流量记录
    • 保留文件第3行及之后的历史记录,直接读取后写入,不进行格式化处理
    • 在日期改变或文件不存在时,自动降级为完整保存

3. 保存策略优化

(原本是30s && 100kB 触发一次保存,现在增加更大的30s&&10MB)

  • 频繁保存场景(流量变化超过10MB时):

    • 使用 SaveHistoryTraffic()SaveTodayOnly() 进行增量保存
    • 大幅减少I/O操作,只写入必要的数据
  • 程序退出/系统关机场景:

    • 使用 SaveHistoryTrafficFull()Save() 进行完整保存
    • 确保所有数据完整写入,保证数据安全

4. 缓存机制

(简化代码复杂度)

  • 引入 m_cache_dirty 标志,实现按需更新缓存
  • GetTraffics() 方法在缓存过期时自动更新
  • 避免频繁的列表合并操作

5. 数据一致性保障

(简化代码复杂度)

  • IsTodayRecord() 方法检查今天的记录日期是否正确
  • 日期改变时自动调用 OnDateChanged() 将今天的记录移到历史记录
  • MormalizeData() 方法确保数据排序和去重

影响分析

  1. 性能显著提升

    • I/O操作大幅减少: 从每次完整写入整个文件(可能包含数百条历史记录)改为只写入2行
    • 磁盘写入频率降低: 在频繁保存场景下,写入数据量减少90%以上
    • 响应速度提升: 减少文件I/O阻塞时间,提升程序响应性
  2. 磁盘寿命延长

    • 减少对SSD/HDD的写入磨损
    • 特别适用于长时间运行的场景
  3. 数据安全性保持

    • 程序退出时仍使用完整保存,确保数据完整性
    • 增量保存有完善的降级机制(日期改变、文件不存在时自动完整保存)
    • 备份机制保持不变

⚠️ 潜在风险与应对

  1. 文件格式兼容性

    • 风险: 新代码读取旧文件格式时可能出现问题
    • 应对: Load() 方法保持向后兼容,能正确解析旧格式文件
    • 影响: 无,向后兼容
  2. 并发访问

    • 风险: 如果多个进程同时访问文件,可能出现数据不一致
    • 应对: 单进程应用,不存在并发问题
    • 影响: 无
  3. 文件损坏恢复

    • 风险: 增量保存过程中程序异常退出,可能导致文件损坏
    • 应对:
      • 有备份机制(.bak文件)
      • 程序启动时会检查并尝试从备份恢复
      • 增量保存失败时会降级为完整保存
    • 影响: 低,有多重保障机制
  4. 数据丢失风险

    • 风险: 增量保存只更新前两行,如果历史记录被外部修改,可能丢失
    • 应对:
      • 历史记录部分直接读取后写入,不进行解析和格式化
      • 如果文件格式正确,不会丢失数据
    • 影响: 极低,正常情况下不会发生

@Yundi339
Copy link
Author

Yundi339 commented Jan 4, 2026

📊 性能对比(估算)

场景 旧方案 新方案 提升
单次保存数据量 全部记录(假设100条) 2行 减少98%
保存耗时 ~10-50ms ~1-5ms 减少80-90%
磁盘写入次数 每次完整写入 只写入必要部分 大幅减少

技术亮点

  1. 智能降级机制: 增量保存失败时自动降级为完整保存,保证可靠性
  2. 缓存优化: 使用脏标记实现按需更新,避免不必要的计算
  3. 数据分离: 将频繁更新的数据和静态数据分离,优化I/O模式
  4. 向后兼容: 保持文件格式兼容,不影响现有数据

@Yundi339
Copy link
Author

Yundi339 commented Jan 4, 2026

1、监控测试结果
这是一个微软的Process Monitor进程监控工具,优化后显示WriteFile事件,30秒内只触发几次写事件。
在之前,由于是全量写入,会导致每写1行数据就触发一次数据同步。
image

2、已测试+1天、备份、未来数据
补充:如果history_traffic.dat.bak、history_traffic.dat都包含未来的数据,在加载时会自动清理未来数据。
由于只更新前两行,我认为,只有人为制造这种异常数据,才会触发风险。不过我也还是在代码中,加上了日期排序,保证数据按照顺序记录。
image

@mian196
Copy link

mian196 commented Feb 2, 2026

Thanks for this PR. By moving to an incremental save/SaveTodayOnly() approach, does this also improve data recovery or prevent file corruption after a crash? I frequently lose my historical data when the app crashes, as it stops reading the .dat file and resets the count.

@Yundi339
Copy link
Author

Yundi339 commented Feb 3, 2026

Thanks for this PR. By moving to an incremental save/SaveTodayOnly() approach, does this also improve data recovery or prevent file corruption after a crash? I frequently lose my historical data when the app crashes, as it stops reading the .dat file and resets the count.

我有重新优化读取备份的逻辑,程序启动和退出,会重新检查history_traffic.dathistory_traffic.dat.bak,将两个数据进行排序合并。我的优化逻辑不算好,但是看上去够用,我刚刚尝试了一下没有什么问题。但是你说的文件损坏问题,我目前没有遇到过,我只有手动破坏文件能够复现,但是这种情况,程序只能从history_traffic.dat.bak当中进行恢复。

@Yundi339
Copy link
Author

Yundi339 commented Feb 3, 2026

自从我提交这个PR以来,我就一直在使用这个优化后的功能,并且我部署在了三台win机器上, 看数据是正常的。

但是程序从休眠中唤醒的时候,仍有可能出现程序挂掉,我对这个现象并不感兴趣,手动重启程序就行了。

@mian196
Copy link

mian196 commented Feb 3, 2026

Thank you for your response. The crash scenario occurs as follows:

  • The system is operating normally when a power outage occurs, causing an abrupt shutdown.

  • Once power is restored, the system powers on automatically. Windows loads along with all startup processes while remaining on the lock screen (remote desktop is configured on the machine).

  • After unlocking the system and reviewing the history, the records are inconsistent sometimes the history is missing, and other times it is present but incomplete.

I will review the history and backup files to determine whether any relevant logs can be recovered.

@Yundi339
Copy link
Author

Yundi339 commented Feb 7, 2026

Thank you for your response. The crash scenario occurs as follows:

  • The system is operating normally when a power outage occurs, causing an abrupt shutdown.
  • Once power is restored, the system powers on automatically. Windows loads along with all startup processes while remaining on the lock screen (remote desktop is configured on the machine).
  • After unlocking the system and reviewing the history, the records are inconsistent sometimes the history is missing, and other times it is present but incomplete.

I will review the history and backup files to determine whether any relevant logs can be recovered.

如果可以的话,你可以试试看我这个版本。

https://github.com/Yundi339/TrafficMonitor/actions/runs/21777997183

@mian196
Copy link

mian196 commented Feb 7, 2026

Thank you for your response. The crash scenario occurs as follows:

  • The system is operating normally when a power outage occurs, causing an abrupt shutdown.
  • Once power is restored, the system powers on automatically. Windows loads along with all startup processes while remaining on the lock screen (remote desktop is configured on the machine).
  • After unlocking the system and reviewing the history, the records are inconsistent sometimes the history is missing, and other times it is present but incomplete.

I will review the history and backup files to determine whether any relevant logs can be recovered.

If you'd like, you can try my version.

https://github.com/Yundi339/TrafficMonitor/actions/runs/21777997183

will try this, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants