【发布时间】:2011-10-01 04:35:02
【问题描述】:
目前我正在试验一个用 Snap 编写的小型 Haskell Web 服务器,它可以加载并向客户端提供大量数据。而且我很难控制服务器进程。在随机时刻,该进程会在几秒钟到几分钟内使用大量 CPU,并且对客户端请求无响应。有时内存使用量会在几秒钟内达到数百兆字节(有时会下降)。
希望有人对使用大量内存的长时间运行的 Haskell 进程有更多经验,并且可以给我一些指示以使事情更稳定。我已经调试了好几天了,现在我开始有点绝望了。
我的设置的一点概述:
在服务器启动时,我将大约 5 GB 的数据读入内存中的大型(嵌套)Data.Map 结构。嵌套映射是值严格的,并且映射内的所有值都是数据类型,并且它们的所有字段也都是严格的。我花了很多时间来确保不会留下未评估的重击。导入(取决于我的系统负载)大约需要 5-30 分钟。奇怪的是连续运行的波动比我预期的要大得多,但这是一个不同的问题。
大数据结构位于“TVar”中,由 Snap 服务器生成的所有客户端线程共享。客户端可以使用小型查询语言请求数据的任意部分。请求的数据量通常很小(最多300kb左右),只涉及数据结构的一小部分。所有只读请求都使用“readTVarIO”完成,因此它们不需要任何 STM 事务。
服务器使用以下标志启动:+RTS -N -I0 -qg -qb。这将以多线程模式启动服务器,禁用空闲时间和并行 GC。这似乎大大加快了进程。
服务器大部分运行没有任何问题。但是,有时客户端请求会超时,CPU 会飙升至 100%(甚至超过 100%),并且会持续很长时间。同时服务器不再响应请求。
我能想到的几个原因可能会导致 CPU 使用率:
这个请求需要很多时间,因为有很多工作要做。这有点不太可能,因为有时会发生在以前的运行中被证明非常快的请求(快速我的意思是 20-80 毫秒左右)。
在处理数据并将其发送到客户端之前,仍然需要计算一些未评估的 thunk。这也不太可能,原因与上一点相同。
不知何故垃圾收集开始扫描我的整个 5GB 堆。我可以想象这会占用很多时间。
问题是我不知道如何弄清楚到底发生了什么以及如何解决这个问题。因为导入过程需要很长时间,所以分析结果并没有向我显示任何有用的信息。似乎没有办法在代码中有条件地打开和关闭分析器。
我个人怀疑 GC 是这里的问题。我正在使用 GHC7,它似乎有很多选项可以调整 GC 的工作方式。
在使用具有通常非常稳定的数据的大型堆时,您推荐哪些 GC 设置?
【问题讨论】:
-
嗯.. 有趣.. 运行此服务器应用程序的盒子有多少 RAM
-
我的机器上总共有 8GB RAM。应该够了。
-
是的.. 这似乎足以避免页面错误
-
一开始就传入一个大的
-H值可能是值得的。我不认为这对暂停有帮助,但它可以帮助加载时间。 -
你能使用开销更少的数据类型吗?例如,HashMap 的开销比 Map 小。
标签: performance haskell garbage-collection memory-management