You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于LiteDB的C#服务器AsyncReaderWriterLock设计合理性问询

问题分析与解决方案

问题重现

你用C#开发服务器,基于LiteDB存储消息,启动异步GC任务删除过期消息:

  • 依赖LiteDB的线程安全特性,未给常规读写加锁,仅用AsyncReaderWriterLock同步GC(写锁)与常规读写(读锁)
  • 50客户端测试正常,但100客户端时,GC无法获取写锁,最终触发LiteDB超时异常:

Exception thrown: 'LiteDB.LiteException' in LiteDB.dll
Database lock timeout when entering in transaction mode after 00:01:00

核心原因

这不是死锁,是锁饥饿+双层锁机制冲突:

  1. LiteDB自身已经实现了线程安全的锁与事务机制,你额外套的AsyncReaderWriterLock属于画蛇添足,两层锁互相干扰。
  2. 读写锁的特性是读优先:当大量客户端持续持有读锁时,新的读请求可以直接插队获取读锁,导致GC的写锁请求永远被阻塞,无法执行。
  3. GC任务持有写锁1秒的逻辑进一步加剧问题:LiteDB的事务被外部锁卡住超过默认1分钟超时阈值,直接抛出异常。

修复方案

  • 移除自定义的AsyncReaderWriterLock:完全信任LiteDB的线程安全实现,所有读写、清理操作直接基于LiteDB自身的API执行。
  • 重构GC清理逻辑:
    • 放弃长时间持有锁的方式,改为短事务批量删除:比如每次只删除100条过期消息,循环执行直到清理完成,单次事务时长控制在毫秒级,避免阻塞其他操作。
    • 调整GC执行间隔,比如从3秒延长至5-10秒,或者根据数据库中过期消息的数量动态调整执行频率。
  • 优化LiteDB使用方式:
    • 确保整个服务器生命周期内只使用一个LiteDatabase实例,LiteDB的连接是线程安全的,单实例才能最大化并发效率。
    • 若仍存在锁竞争,可适当调大LiteDB的Timeout配置参数(默认60秒),但这只是临时缓解,核心还是优化清理逻辑。
  • 优化消息插入效率:
    • 高并发场景下,将多个客户端的消息合并为批量插入,减少事务次数,降低LiteDB内部的锁竞争频率。

验证步骤

去掉外部锁后,重新运行100客户端测试:

  • 确认GC任务能正常执行清理操作
  • 监控消息发送吞吐量是否恢复正常
  • 检查是否再出现锁超时异常

内容的提问来源于stack exchange,提问作者Idra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 20:50:28