我的决策引擎是在带有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发出请求可能会更容易。
好的,既然我已经讨论了最佳实践方式,让我指出一些我可以在你现在所做的事情中发现的问题(困难的方式)。
你没有提到你是一次一行得分还是批量得分。使用完整的H2O-3服务器本身进行评分更适合批量评分,而一次只对一行进行评分的效率极低。解析过程是重量级的,评分过程一次对一行是重量级的。这将影响延迟。
虽然您可以将MOJO对象本身读入一个完整的H2O-3服务器进程,并将其用于批量评分,但在实时HTTP工作流中这样做从来都不是目的。(有趣的是,在H2O-3存在的最初5年里,甚至不可能支持这样做。)
如果你自己不清理,肯定会有内存泄漏。
不建议将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)。
希望能有所帮助!