背景:
晚上收到报警,说线上的一个solr的collection挂掉了,赶紧打开远程服务起查看服务器的状态,果然业务方查询全部超时,增量更新也宕机了,从异常信息上来看是集群中没有可用的节点可以使用,看到这样的问题,第一想到的是要重启一下服务器。悲剧的是重启完服务器,服务只正常了15秒钟,转而又全部宕机。
判断是VM的堆内存溢出了,看了一下虚拟机启动参数 -Xmx4400m -Xms4400m(服务器是8G内存)
,临时的解决方案是增加内存,设置为-Xmx6400m -Xms6400m,设置完成,迅速重启服务器之后,观察了一会,core节点果然是不会挂了,但,通过命令工具 jstat -gcutil 命令查看VM fullgc的状态,观察到Full GC的频率是比较高,只是服务器勉强不会挂罢了。
同事告诉我他们团队刚刚上了一个新的查询需求,这个提示我是不是因为的查询里面设置了什么查询条件的原因,随即仔细查看了一下日志,果然在查询日志中观察到了有两个查询中带sort的参数,需要排序的字段在在schema field节点只是设置了indexed=true而没有设置docValues=true ,瞬间明白了为什么会OOM。
原因分析:
究其原因是客户端查询请求中需要sort的字段在schema field定义中,开启了indexed=true ,但是没有开启docValue=true,这样solr在对命中结果集进行排序时候,会将docid对应的value预先加载内存中,如果一个core中文档数有2000w条的话,试想一个long字段类型的field,在内存中就需要2000w*8个字节的内存,大概152兆内存,而且这个内存块需要随着文档内容更新,频繁刷新,内存频繁OOM也可想而知了。
在solr5.0开始,框架中引入了docvalue机制,按照我现在的理解,这种存贮格式有以下三个特点:
- 这始终列存储,所以通过docid取单列中的内容比基于行存储的document中的内容要要快上好多倍
- 存储中的内容在物理上是按序排列的,利用这个特性,在文档排序时,只需要通过docid取对应的所在存储上的偏移量offset,通过这个offset偏移量就能判断两个值的大小,这样就能省去额外的IO开销,具体可以查看org.apache.solr.response.SortingResponseWriter这个类。基于此,solr框架可以衍生出很多非常酷的功能,比如基于"/export"的流式导出功能,和基于"/export"的stream expression功能。
- 存储内容不是依赖于内存的,这个和老版本的fieldcache机制有本质区别。
以下是查询中使用了sort字段,solr的执行栈路径视图:
从调用路径来看,最终会调用FieldCacheImpl的getNumerics的方法,如下:
@Override public NumericDocValues getNumerics(LeafReader reader, String field, Parser parser, boolean setDocsWithField) throws IOException { if (parser == null) { throw new NullPointerException(); } // schema field 上是否开启了docValue=true final NumericDocValues valuesIn = reader.getNumericDocValues(field); if (valuesIn != null) { // Not cached here by FieldCacheImpl (cached instead // per-thread by SegmentReader): return valuesIn; } else { final FieldInfo info = reader.getFieldInfos().fieldInfo(field); if (info == null) { return DocValues.emptyNumeric(); } else if (info.getDocValuesType() != DocValuesType.NONE) { throw new IllegalStateException("Type mismatch: " + field + " was indexed as " + info.getDocValuesType()); } else if (info.getIndexOptions() == IndexOptions.NONE) { return DocValues.emptyNumeric(); } return (NumericDocValues) caches.get(Long.TYPE).get(reader, new CacheKey(field, parser), setDocsWithField); } }
通过代码了解到,先调用LeafReader的getNumericDocValues的方法,结果是否为空取决于schema中的field定义是否设置docValue=true设置,如果开启了docvalue这里就能直接取得docValue对象,不然的话就通过预先在cache中准备的五种基于索引term的,field加载策略:
private Map<Class<?>,Cache> caches; FieldCacheImpl() { init(); } private synchronized void init() { caches = new HashMap<>(6); caches.put(Long.TYPE, new LongCache(this)); caches.put(BinaryDocValues.class, new BinaryDocValuesCache(this)); caches.put(SortedDocValues.class, new SortedDocValuesCache(this)); caches.put(DocTermOrds.class, new DocTermOrdsCache(this)); caches.put(DocsWithFieldCache.class, new DocsWithFieldCache(this)); }我就纳闷了,solr5.0中既然已经有docvalue机制,为什么还要在框架中保留这些通过term预加载到内存的fieldcache机制,因为一旦用户需要使用排序,功能而又在schema中忘记定义docvalue为true,一旦文档数量多,很有可能导致OOM的,也许solr的开发者为了版本向下兼容的原因吧。
问题解决:
那如何解决用户索引结构不当使用导致的OOM问题呢,是通过在wiki中标注,应该如何小心的配置schema,来防止出现类似的问题。这就像在市区的马路上,通过在马路当中画上双黄线,来明令告知驾驶者不要越过双黄线逆向行驶,但事实是在高峰期,只要没有监控的地方总有胆子大的驾驶者要越过双黄线,解决办法就是,要像高速公路上在马路中间建造隔离带,强行防止开到逆向车道上去,但是这个成本确实是有点高,但是非常有效。我们在做平台式的产品中也需要借鉴类似经验,需要在平台产品中构筑起一个个轨道,保证用户在既定的轨道上操作,如果用户试图跳出既定轨道,我们就要通过友好的反馈消息告知他已经偏离了轨道需要及时纠正。这样一种办法,可定比在wiki中写开发规约之类的东西有效,友好得多。
所以我在solr容器启动的时,执行了一个将solr框架预先准备的cache清空的操作,后续如果有操作试图不通过docvalue机制来执行sort之类的操作就一律报错,这样在开发过程中就避免的因为不合理设置schema导致的错误,代码如下:
RemoveFieldCacheListener:
public class RemoveFieldCacheListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { RemoveFieldCacheStrategy.removeFieldCache(); } @Override public void contextDestroyed(ServletContextEvent sce) { } }RemoveFieldCacheStrategy:
import java.io.IOException; import java.lang.reflect.Field; import java.util.Map; import org.apache.lucene.index.BinaryDocValues; import org.apache.lucene.index.LeafReader; import org.apache.lucene.index.SortedDocValues; import org.apache.lucene.uninverting.FieldCacheImpl.Cache; import org.apache.lucene.uninverting.FieldCacheImpl.CacheKey; import org.apache.lucene.uninverting.FieldCacheImpl.DocsWithFieldCache; import org.apache.lucene.util.Accountable; public class RemoveFieldCacheStrategy { @SuppressWarnings("all") public static void removeFieldCache() { try { FieldCacheImpl fieldCacheManager = (FieldCacheImpl) FieldCache.DEFAULT; Field cacheField = FieldCacheImpl.class.getDeclaredField("caches"); cacheField.setAccessible(true); // 防止启动的时候在schema中没有设置 docvalue属性的时候,字段设置了indexed=true // 将doc的term的值预先加载到内存中,防止業務方不適當設置query對象導致服務端oom Map<Class<?>, Cache> caches = (Map<Class<?>, Cache>) cacheField.get(fieldCacheManager); FieldCacheImpl.Cache disable = new FieldCacheImpl.Cache(null) { @Override public Object get(LeafReader reader, CacheKey key, boolean setDocsWithField) throws IOException { throw new IllegalStateException( "you are intending to use sorting,facet,group or other statistic feature,please set field:[" + key.field + "] docValue property 'true'"); } @Override protected Accountable createValue(LeafReader reader, CacheKey key, boolean setDocsWithField) throws IOException { return null; } }; caches.clear(); caches.put(Long.TYPE, disable); caches.put(BinaryDocValues.class, disable); caches.put(SortedDocValues.class, disable); caches.put(DocTermOrds.class, disable); caches.put(DocsWithFieldCache.class, disable); } catch (Exception e) { throw new RuntimeException(e); } } }
完!
相关推荐
Solr,作为一款开源的全文搜索引擎,其核心配置文件包括`schema.xml`和`solrconfig.xml`,它们是Solr工作方式的基础。在深入理解这两个文件之前,我们需要先了解Solr的基本架构。 **1. Solr架构简介** Solr采用...
### Solrconfig.xml 和 Schema.xml 说明 #### Solrconfig.xml 概述 Solrconfig.xml 是 Apache Solr 的核心配置文件之一,主要用于定义 Solr 实例...理解并合理配置这些选项对于充分发挥 Solr 的性能是非常重要的。
【课程大纲】第01讲 solr5简介第02讲 solr5之Schema第03讲 solr5之Solrconfig第04讲 solr5单机安装与配置第05讲 solrj基础(一)第06讲 solrj基础(二)第07讲 solrj之SolrBean第08讲 solrj语法详解第09讲 Solrj之...
当你在尝试启动Solr时遇到404错误,这通常意味着Solr服务没有正确地启动或者配置文件设置不正确。404错误表示“未找到”,在Web服务器中通常意味着请求的资源无法被定位。下面我们将深入探讨如何解决这个问题。 ...
它包括一个默认的配置集,以及一个简单的数据导入处理程序(DIH)示例,帮助开发者了解如何设置和使用Solr。 5. **docs 目录**:包含了Solr的文档,包括用户手册、API参考和教程,对于学习和调试Solr非常有用。 6....
这涉及到Schema设计(如哪些字段应被索引,哪些应被存储),配置优化(mergeFactor、缓存设置等),内存管理(防止内存溢出,合理分配JVM内存),以及更新频率和查询响应压缩等方面的权衡。 总的来说,掌握Solr的...
合理的Schema设计是确保Solr性能的关键。 5. **请求处理器(Request Handler)**:Solr通过Request Handler来处理HTTP请求,如搜索、添加、删除和更新文档。常见的Request Handler有`/select`(用于搜索)、`/...
Schema是Solr的核心配置之一,用于定义索引字段、数据类型、分析器等,它允许用户自定义字段的属性,以满足不同数据的处理需求。 1.2.3 查询 Solr提供丰富的查询语法,包括布尔运算、短语匹配、范围查询等,还支持...
5. **example** 文件夹:提供了一个简单的Solr实例,包括了如何设置和运行的基本示例,对于初学者来说非常有用。 6. **contrib** 文件夹:这个目录包含了一些社区贡献的模块,它们可能提供了额外的功能或者对Solr的...
Apache Solr是一款开源的企业级搜索平台,由Apache软件基金会维护。它是基于Java的,提供了高效、可扩展的全文检索、数据分析和分布式搜索功能。Solr-8.11.1是该软件的一个特定版本,包含了从早期版本到8.11.1的所有...
1. **修改 schema.xml 文件**:打开 `D:\solr\home` 目录下的 schema.xml 文件,增加或修改以下字段类型定义: ```xml <fieldType name="textComplex" class="solr.TextField" positionIncrementGap="100"> ...
2. **配置Solr Schema**:在Solr的Schema.xml文件中,需要为需要分词的字段指定`<analyzer>`标签,并在其中使用IK分词器。例如: ```xml <fieldType name="text_ik" class="solr.TextField" positionIncrementGap=...
当某个节点上的SolrCore出现问题时,集群应能自动将请求路由到其他健康的节点,保证服务的连续性。 10. **版本控制** 使用版本控制系统(如Git)管理SolrCore的配置文件,可以帮助跟踪改动历史,便于回滚到之前的...
ikanalyzer 是一个专门为Java开发的中文...总之,ikanalyzer-solr8.4.0 是 Solr 8.4.0 版本下用于中文分词的重要工具,通过合理的配置和使用,可以显著提高 Solr 对中文文本的处理能力,从而提升搜索质量和用户体验。
- 根据系统负载和性能需求,调整 Solr 的配置参数,例如增加索引段大小、调整缓存设置等。 以上就是 Solr 4.4.0 版本的主要知识点,以及如何在 Linux 环境下进行安装和部署到 Tomcat。通过熟练掌握这些步骤,你将...
docker配置solr登录密码文件,内含配置密码的文件 、web.xml的文件 ,详情可以去看我的博客,博客地址:https://blog.csdn.net/huyande123/article/details/97110784
接着,我们需要修改 Solr 的 `schema.xml` 文件,添加一个新的字段类型,指定使用 IKAnalyzer 进行中文分词。完成这些修改后,重启 Tomcat 使更改生效。 在维护 Solr 时,可能需要进行一些性能优化。对于 Tomcat,...
4. **Schema设计**:Solr使用Schema.xml文件来定义索引字段,包括字段类型、分词器、过滤器等,这对于优化搜索性能至关重要。 5. **RESTful API**:Solr 8.8.2支持JSON、XML等多种格式的HTTP接口,便于通过编程方式...
在Solr的Schema设计中,可以为需要分词的字段指定`ikanalyzer`作为分析器,这样在索引和查询时,Solr就会使用ikanalyzer进行分词操作。 总之,ikanalyzer-solr中文分词包为Solr提供了一种强大的中文处理能力,使得...
2. 配置Solr schema:确保Solr的Schema.xml文件包含了需要索引的所有字段,包括用于增量检测的字段。 3. 启用DeltaImport:在Solr的请求处理器中启用DeltaImport,以便能够通过HTTP请求触发增量导入。 四、定时...