目前我正在尝试使用Snap编写的一个小Haskell Web服务器来加载并向客户端提供大量数据.而且我非常非常难以控制服务器进程.在随机的瞬间,该过程使用大量的CPU几秒到几分钟,并且对客户端请求没有反应.有时内存使用量会在几秒钟内达到峰值(有时会下降)数百兆字节.
希望有人对使用大量内存的长时间运行的Haskell进程有更多的经验,并且可以给我一些指导以使事情更稳定.我已经调试了几天了,我开始有点绝望了.
我的设置概述:
在服务器启动时,我将大约5千兆字节的数据读入内存中的大型(嵌套)Data.Map相似结构.嵌套映射是值严格的,并且映射中的所有值都是数据类型,其所有字段也都是严格的.我花了很多时间确保没有留下未评估的thunk.导入(取决于我的系统负载)大约需要5-30分钟.奇怪的是连续运行的波动比我预期的要大,但这是一个不同的问题.
大数据结构存在于由"Snap"服务器生成的所有客户端线程共享的"TVar"中.客户端可以使用小型查询语言请求数据的任意部分.数据请求的数量通常很小(高达300kb左右),只接触数据结构的一小部分.所有只读请求都使用'readTVarIO'完成,因此它们不需要任何STM事务.
服务器使用以下标志启动:+ RTS -N -I0 -qg -qb.这将以多线程模式启动服务器,禁用空闲时间和并行GC.这似乎加快了这个过程.
服务器大多运行没有任何问题.但是,偶尔客户端请求会超时并且CPU达到100%(甚至超过100%),并且会持续这么长时间.同时服务器不再响应请求.
我可以想到几个可能导致CPU使用的原因:
请求只需要花费很多时间,因为还有很多工作要做.这有点不太可能,因为有时它会发生在先前运行中证明非常快的请求(快速我的意思是20-80ms左右).
在处理数据并将数据发送到客户端之前,仍然需要计算一些未评估的thunk.这也不太可能,原因与前一点相同.
以某种方式垃圾收集开始并开始扫描我的整个5GB堆.我可以想象这可能会花费很多时间.
问题是我不知道如何弄清楚究竟发生了什么,以及如何处理这个问题.因为导入过程花了这么长时间的分析结果,所以没有向我展示任何有用的东西.似乎没有办法从代码中有条件地打开和关闭探查器.
我个人怀疑GC是问题所在.我正在使用GHC7,它似乎有很多选项可以调整GC的工作原理.
在使用通常非常稳定的数据的大堆时,您建议使用哪些GC设置?