【问题标题】:Solr and JVM memory management issuesSolr 和 JVM 内存管理问题
【发布时间】:2015-12-04 11:38:01
【问题描述】:

我们的 Solr 部署在 4.6.0 版上运行时遇到了问题,其参数如下:

java -Xss256k -Xms512m -Xmx30g -jar start.jar

Solr 在具有 64GB RAM 和 12 个内核的 Windows Server 2008 R2 上运行。 Solr 实例分配了 30 GB,数据导入后的索引大小约为。 1.2 GB。 启动 Solr 实例后,Solr 仪表板上的 JVM 内存使用情况显示:

Used Memory: 8.61 GB
Peak Memory: 15.19 GB
Total Memory: 29.02 GB

几天后,我们注意到内存读起来像

Used Memory: 22.32 GB
Peak Memory: 29.02 GB
Total Memory: 29.02 GB

索引每小时刷新一次(凌晨 2 点到 4 点之间除外),它们的大小几乎没有太大变化。

但是,过了一会儿,Solr 似乎变得没有反应了。 Solr 仪表板未加载,查询失败,出现如下错误。 我们进行了很多搜索,似乎找不到任何解决方案。唯一的临时解决方法是在 java 进程超过 30 GB 的内存使用量后重新启动 Solr 实例。此后它运行良好大约 10-12 天,但同样的问题再次出现。

并且下面给出的错误每天都会发生,主要是在上午 12 点到 6 点之间。但是,这段时间的流量非常少,而且在凌晨 2 点至凌晨 4 点之间也没有重新索引 Solr 核心,因为在此期间没有数据更改。

我们在 jetty.xml 中更改了以下几个配置,但这似乎也没有太大帮助。

<Set name="maxIdleTime">1200000</Set>
<Set name="lowResourceMaxIdleTime">10000</Set>

 

ERROR - 2015-12-04 02:10:56.821; org.apache.solr.common.SolrException; null:org.eclipse.jetty.io.EofException 
at org.eclipse.jetty.http.HttpGenerator.flushBuffer(HttpGenerator.java:914) 
at org.eclipse.jetty.http.AbstractGenerator.blockForOutput(AbstractGenerator.java:507) 
at org.eclipse.jetty.server.HttpOutput.write(HttpOutput.java:147) 
at org.eclipse.jetty.server.HttpOutput.write(HttpOutput.java:107) 
at sun.nio.cs.StreamEncoder.writeBytes(Unknown Source) 
at sun.nio.cs.StreamEncoder.implWrite(Unknown Source) 
at sun.nio.cs.StreamEncoder.write(Unknown Source) 
at java.io.OutputStreamWriter.write(Unknown Source) 
at org.apache.solr.util.FastWriter.flush(FastWriter.java:141) 
at org.apache.solr.util.FastWriter.write(FastWriter.java:55) 
at org.apache.solr.response.JSONWriter.writeStr(JSONResponseWriter.java:449) 
at org.apache.solr.response.JSONWriter.writeKey(JSONResponseWriter.java:103) 
at org.apache.solr.response.JSONWriter.writeSolrDocument(JSONResponseWriter.java:346) 
at org.apache.solr.response.TextResponseWriter.writeDocuments(TextResponseWriter.java:275) 
at org.apache.solr.response.TextResponseWriter.writeVal(TextResponseWriter.java:172) 
at org.apache.solr.response.JSONWriter.writeNamedListAsMapWithDups(JSONResponseWriter.java:183) 
at org.apache.solr.response.JSONWriter.writeNamedList(JSONResponseWriter.java:299) 
at org.apache.solr.response.JSONWriter.writeResponse(JSONResponseWriter.java:95) 
at org.apache.solr.response.JSONResponseWriter.write(JSONResponseWriter.java:60) 
at org.apache.solr.servlet.SolrDispatchFilter.writeResponse(SolrDispatchFilter.java:698) 
at org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:426) 
at org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:197) 
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1419) 
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:455) 
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137) 
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:557) 
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231) 
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1075) 
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:384) 
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193) 
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1009) 
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135) 
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:255) 
at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:154) 
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116) 
at org.eclipse.jetty.server.Server.handle(Server.java:368) 
at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:489) 
at org.eclipse.jetty.server.BlockingHttpConnection.handleRequest(BlockingHttpConnection.java:53) 
at org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:942) 
at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:1004) 
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:640) 
at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235) 
at org.eclipse.jetty.server.BlockingHttpConnection.handle(BlockingHttpConnection.java:72) 
at org.eclipse.jetty.server.bio.SocketConnector$ConnectorEndPoint.run(SocketConnector.java:264) 
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608) 
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543) 
at java.lang.Thread.run(Unknown Source) 

Caused by: java.net.SocketException: Software caused connection abort: socket write error 
at java.net.SocketOutputStream.socketWrite0(Native Method) 
at java.net.SocketOutputStream.socketWrite(Unknown Source) 
at java.net.SocketOutputStream.write(Unknown Source) 
at org.eclipse.jetty.io.ByteArrayBuffer.writeTo(ByteArrayBuffer.java:375) 
at org.eclipse.jetty.io.bio.StreamEndPoint.flush(StreamEndPoint.java:164) 
at org.eclipse.jetty.io.bio.StreamEndPoint.flush(StreamEndPoint.java:182) 
at org.eclipse.jetty.http.HttpGenerator.flushBuffer(HttpGenerator.java:838) 

【问题讨论】:

  • 对于这么小的索引来说,这是一大堆堆。您是否有数百万个小文档和一个大的 filterCache?当 Solr 内存使用量持续增长时,大型缓慢填充的缓存通常是问题。

标签: java memory solr jvm


【解决方案1】:

如果 solr 和 java 版本分别为 >5.5 和 >1.8.0_5,我建议通过 ConcurrentMarkSweep 为 solr 配置 G1GC。

要配置 G1GC,请遵循以下参数

GC_TUNE="-XX:+UseG1GC -XX:+PerfDisableSharedMem -XX:+ParallelRefProcEnabled -XX:+UnlockExperimentalVMOptions -XX:G1HeapRegionSize=32m -XX:MaxGCPauseMillis=500 -XX:G1NewSizePercent=5 -XX:G1MaxNewSizePercent=30 -XX:InitiatingHeapOccupancyPercent=45 -XX:G1MixedGCLiveThresholdPercent=65 -XX:+UseLargePages -XX:+AggressiveOpts"

【讨论】:

  • 基本上,限制最大堆大小在这里会有所帮助。 InitiatingHeapOccupancyPercent 可以根据应用要求进行调整。
【解决方案2】:

根据我的经验,逐渐无响应可能是 JVM 调整不佳的症状。我建议使用带有 VisualGC 插件的 VisualVM 等工具监控 JVM,或者将 GC 记录到文件中并使用众多可用工具之一对其进行分析。

来自维基:

https://wiki.apache.org/solr/SolrPerformanceProblems

当你有一个大堆(大于 2GB)时,垃圾收集 停顿可能是一个主要问题。这通常是由偶尔引起的 需要必须“停止世界”的完整垃圾收集——暂停 所有程序执行以清理内存。主要有两个 解决方案:一种是使用像 Zing 这样的商业低暂停 JVM,它 确实带有价格标签。另一个是调整你拥有的免费 JVM 已经得到了。 GC 调优是一种艺术形式,适合一个人 可能不适合你。

除非您仔细观察,否则很难确切地知道发生了什么。考虑到堆的大小,您可能需要尝试使用常见参数,例如 NewSize 或尝试使用收集算法(例如,ConcurrentMarkSweep 可用于最小化暂停)。

【讨论】:

  • 过去几天我们一直在密切观察我们的 GC 日志。 GC 暂停和 Solr 变得无响应之间似乎没有直接关联。完全 GC 暂停并不总是与 Solr 变得无响应时同时发生或发生在类似的时间范围内。 Solr 白天几乎没有错误。只有在没有任何核心索引作业或没有多次点击时,它才会在晚上变得无响应。仍在尝试找出为什么 JVM 的内存利用率会达到如此高的大小(高达 30 GB),总索引大小高达约 1.5 GB