我的决策引擎是基于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有关,它需要更多的内存。在此周期内,流量看起来是相同的。所以我希望这不是由于人流量大。
根据我的调查,某些内存挂在某处,并且没有释放。
我做了以下解决方法释放挂起的内存并减少影响
1来自python的h2o中的GC
https://aichamp.wordpress.com/2016/11/10/calling-h2o-garbage-collect-from-python
2计划的服务重新启动-用新服务器正常替换旧服务器。
我想了解内部正在发生的事情,并介绍适当的修复方法而不是解决方法。帮助将不胜感激。
供参考,
我还没尝试
1将H2o群集更新为新版本,因为当前版本太旧(1年,7个月和11天)-同意最好使用最新版本,但不能保证相同版本不会再次发生,并且在验证分数,结果等方面也需要更多的努力
2我没有通过使用min_mem_size
来限制H2o的内存使用,因为我不希望记分卡评估失败。
和
我打算去
1添加内存分析器,以轻松了解与我的应用相关的每个部件/进程的内存利用率
谢谢
您描述的方法与我建议的方法不同。
为了简单起见(忽略多个服务器和负载平衡),我将这样绘制您的设置的体系结构图:
[Client HTTP program] -> [python flask app] -> [java scoring backend]
这种高级架构很好,但是您已经实现了Java评分层部分,我会说这是最困难的方法,而不是预期的方法。
预期的方法是仅使用MOJO和轻量级的MOJO运行时。一种简单的方法是将MOJO包装在非常简单的最小Web服务中。
这里是MOJO的javadoc链接:
和一个说明如何在简单的Java servlet容器中使用MOJO的github回购:
[此外,这是一个较旧的github存储库,您可能会发现使用POJO而不是MOJO很有用。 MOJO更好。使用MOJO而不是POJO,但您可能会发现阅读此存储库中的文档很有帮助:
[注意,如果您以这种方式进行操作,那么您仍然可以根据需要分别缩放/负载均衡[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服务器进程分配大量内存。我什至不会在-Xmx小于5G的笔记本电脑上运行它。因此,我将原始发布者的Java堆描述为严重不足(H2O cluster free memory: 1.656 Gb
)。
如果您看到Full GC爬升后剩余的可用堆,请重新启动Java进程,因为这不是标准用例,也不是经过全面测试的东西。开发团队认为H2O-3集群比起长期运行的服务(月数,例如nginx / apache),更像是中短寿命的服务(小时/天)。
希望有帮助!