[Blog] [Docs] [Code] [Slides] [About]

问题求解OJ线上事故分析

2020-09-12 19:00 CST

2020-09-12 20:34 CST

aunt使用.NET Core技术栈自研开发的Online Judge上线第一晚出现的多个奇葩事故的分析

(好歹也是大厂实习过的人了,菜得产品bug满天飞,上线当晚硬盘崩了)

meme

项目简介

github.com/AlDanial/cloc v 1.82  T=5.72 s (47.4 files/s, 3410.2 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
C#                             112           1346            125          10932
TypeScript                      95            554            164           4310
HTML                            46              9              2           1689
Razor                           18             20              0            340
-------------------------------------------------------------------------------
SUM:                           271           1929            291          17271
-------------------------------------------------------------------------------

注释代码比高达惊人的1.68%,不愧是我(x)


事故1:无法打开排名页面

事故表现:本地环境和测试服没有遇到问题,点击Standings页面有几率打开,有几率什么都不展示。控制台报错Cannot read property 'name' of undefined。只有前端报错,其他功能不受影响。

事故原因:并发bug。加载排名信息时加载比赛信息和排名信息的请求产生竞争,排名信息获取成功后需要对数据进行排序,但排序函数使用的题目列表在比赛信息中还没有加载出来,contest变量此时为undefined,产生错误。

解决方案:给两个请求增加顺序,在加载比赛信息完成后才加载排名信息并排序。


事故2:评测服务不使用更新后的题目数据

事故表现:由yls在测试服提出,修改题目的时间限制后仍然会使用旧的时间限制进行评测,导致结果与预期不一致。影响修改了数据或限制的题目的评测,重启评测服务后使用的是正确的信息。

事故原因:Entity Framework对从数据库中获取的实体存在缓存(Tracking),由此可以避免每次都从数据库中获取数据。评测服务每次都会保持同一个服务作用域(ServiceScope)和同一个数据库上下文(DBContext),由此每次运行评测时题目信息不会从数据库中刷新最新值,而是使用了缓存中的数据,导致更新题目数据后运行结果与预期不一致。

解决方案:

  • (未采用)给上下文中的数据表设置AsNoTracking关闭数据缓存,但这种方法同时也会关闭对应数据的追踪,导致无法更新数据内容到数据库中;
  • 每次运行使用新创建的服务作用域,运行结束后(没有进行新的评测)则抛弃作用域然后休眠。

事故3:运行一晚后磁盘写满数据爆了

事故表现:睡了一觉之后硬盘剩余的30+GiB空间被写满,没有空余空间可以创建文件,评测服务全挂了。

事故原因:解决事故2时,将使用抛弃了的作用域对象创建的触发器对象保存在了一个没清空的列表中,每次运行都会遍历列表,导致遍历并调用了被抛弃的对象的成员,而DBContext会对是否已经抛弃进行检查并报错,报错日志以肉眼可见的速度平方级增长,很快填满了磁盘。

meme

解决方案:除了改代码以外,给Docker加了日志大小限制(这么重要的事竟然没做,真鸡儿丢人)

<EOF>

Loading Comments By Disqus