Python Web应用程序中的H20内存泄漏



我的决策引擎是在带有uWSGI和Nginx的python-flask框架上构建的。作为通过HTTP请求评估用户的一部分,我使用h2o==3.20.0.7运行记分卡,以生成一个分数来对用户做出决定。下面给出了一些关于我如何在我的应用中使用h2o的清晰信息

h2o.init()  # initialize 
predictions = h2o.mojo_predict_pandas(features_df, MODEL_MOJO_ZIP_FILE_PATH, MODEL_GENMODEL_JAR_PATH)  # generate score
# features_df -> pandas DF

应用程序启动的H2o详细信息

--------------------------  ----------------------------------------
H2O cluster uptime:         01 secs
H2O cluster timezone:       Etc/UTC
H2O data parsing timezone:  UTC
H2O cluster version:        3.20.0.7
H2O cluster version age:    1 year, 7 months and 10 days !!!
H2O cluster name:           H2O_from_python_unknownUser_t8cqu9
H2O cluster total nodes:    1
H2O cluster free memory:    1.656 Gb
H2O cluster total cores:    4
H2O cluster allowed cores:  4
H2O cluster status:         accepting new members, healthy
H2O connection url:         http://localhost:54321
H2O connection proxy:
H2O internal security:      False
H2O API Extensions:         XGBoost, Algos, AutoML, Core V3, Core V4
--------------------------  ----------------------------------------

H2o(作为一个单独的服务运行)和flask应用程序都在同一台服务器上运行(负载均衡器下有3-8台服务器)。

有时内存使用量稳步增加,并抛出Cannot allocate memory

同时计算记分卡。然后,它会在某些时候自动沉降。记分卡在HTTP请求下与其他规则一起运行(顺序运行),但错误仅在计算记分卡时报告。假设它需要更多的内存,因为它涉及到h2o。整个周期的交通量看起来是一样的。所以我希望这不是因为交通拥挤。

根据我的调查,一些记忆悬在某处,而且没有释放。

我做了以下变通办法以释放挂起的内存并减少的影响

1python 中h2o中的GC

https://aichamp.wordpress.com/2016/11/10/calling-h2o-garbage-collect-from-python

Python H2O内存管理

  • 没有受到积极影响

2计划的服务重启-用新服务器优雅地替换旧服务器。

  • 经历了积极的影响。60-70%的错误消失了

我想了解内部发生了什么,并介绍一个适当的解决方案,而不是解决方法。非常感谢您的帮助。

供您参考,

我还没有尝试过

1由于当前版本太旧(1年7个月11天),将H2o集群更新为新版本-同意最好使用最新版本,但不能保证不会再次发生同样的情况,所需的精力也更多地用于验证分数、结果等

2我没有通过使用min_mem_size来限制H2o的内存使用,因为我不希望记分卡评估失败。

我计划

1添加一个内存探查器,可以轻松了解与我的应用相关的每个片段/进程的内存利用率

编辑

2从flask应用程序中分离出h2o,并将其托管在不同的服务器中,以便轻松扩展。-不过,同样的问题也是可能的。

  • 我浏览了一些内存分析器,但仍然无法最终确定一个最适合我当前情况的分析器。我也想在这方面得到一个建议

感谢

您描述的方法与我推荐的方法不同。

为了简单起见(忽略多个服务器和负载平衡),我将绘制您的设置的架构图,如下所示:

[Client HTTP program] -> [python flask app] -> [java scoring backend]

这种高级体系结构很好,但您已经开始以我要说的最困难的方式而不是预期的方式来实现java评分层部分。

预期的方法是只使用MOJO和轻量级MOJO运行时。一种简单的方法是将MOJO封装在一个非常简单的最小web服务中。

以下是MOJO:的javadoc链接

  • http://docs.h2o.ai/h2o/latest-stable/h2o-genmodel/javadoc/overview-summary.html#whatisamojo

和github repo,演示如何在简单的Java servlet容器中使用MOJO:

  • https://github.com/h2oai/app-mojo-servlet

此外,这里有一个旧的github repo,您可能会发现它很有用,它使用POJO而不是MOJO。MOJO更好。使用MOJO而不是POJO,但您可能会发现阅读本回购中的文档很有帮助:

  • https://github.com/h2oai/app-consumer-loan

注意,如果你这样做,如果你愿意,你仍然可以分别扩展/负载平衡[python flask app]和[java scoring backend]服务,尽管我预计java会比python快得多,所以只需将python和java以两个一组的方式一起扩展,并让python向本地java发出请求可能会更容易。


好的,既然我已经讨论了最佳实践方式,让我指出一些我可以在你现在所做的事情中发现的问题(困难的方式)。

  1. 你没有提到你是一次一行得分还是批量得分。使用完整的H2O-3服务器本身进行评分更适合批量评分,而一次只对一行进行评分的效率极低。解析过程是重量级的,评分过程一次对一行是重量级的。这将影响延迟。

  2. 虽然您可以将MOJO对象本身读入一个完整的H2O-3服务器进程,并将其用于批量评分,但在实时HTTP工作流中这样做从来都不是目的。(有趣的是,在H2O-3存在的最初5年里,甚至不可能支持这样做。)

  3. 如果你自己不清理,肯定会有内存泄漏。

    不建议将H2O-3服务器进程作为长期运行的评分服务运行。但如果你真的想这么做,请采取以下步骤:

    • 需要清除内存中的对象。您可以用h2o.ls()找到它们,并用R/python客户端API中的h2o.rm()调用删除它们。数据集和分数都需要清理。不过,您可能不想删除模型本身。

    • 我不认为你需要在Java进程中手动触发垃圾收集,但如果你愿意的话,你可以。就我个人而言,我只在打开诸如-XX:+PrintGCDetails-XX:+PrintGCTimeStamps之类的Java标志时才会这样做,这样我就可以看到压缩对Full GC后剩余空闲堆内存的影响。我这样做是为了看看这些物体是否真的被保留了下来,这样我就可以确认它们是否被清除了。我喜欢把那些日志交给http://gceasy.io并将它们可视化。

    • 请监控日志以查看完整GC之后剩余的可用堆。

    • 即使你在清理内存方面做了正确的事情,也要给H2O-3服务器进程大量的内存。我甚至不会用比5G更小的Xmx在我的笔记本电脑上运行它。因此,我会将原始发布者的Java堆描述为严重供应不足(H2O cluster free memory: 1.656 Gb)。

    • 如果您看到Full GC缓慢上升后剩余的空闲堆,请重新启动Java进程,因为这不是标准用例,也不是经过彻底测试的东西。H2O-3集群被开发团队认为是中短期服务(小时/天),而不是长期服务(月+,例如nginx/apache)。


希望能有所帮助!

相关内容

  • 没有找到相关文章

最新更新