背景:
晚上收到报警,说线上的一个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 solrconfig 配置文件解析 solr schema solrconfig 配置文件解析
3.4.1 Solr Schema 设计(如何定制索引的结构?) 34 3.5 如何进行索引操作? 36 3.5.1 基本索引操作 36 3.5.2 批量索引操作 37 3.6 如何进行搜索 39 3.6.1 搜索语法 39 3.6.2 排序 42 3.6.3 字段增加权重 42 3.6.4 ...
docker配置solr登录密码文件,内含配置密码的文件 、web.xml的文件 ,详情可以去看我的博客,博客地址:https://blog.csdn.net/huyande123/article/details/97110784
solrconfig.xml和schema.
solr.warsolr.war包solr.war包solr.war包solr.war包solr.war包solr.war包solr.war包solr.war包solr.war包solr.war包solr.war包solr.war包solr.war包solr.war包solr.war包solr.war包solr.war包solr.war包solr.war包...
包括solr的所有资源文件文件清单如下: IKAnalyzer.cfg.xml ik-analyzer-solr5-5.x.jar ...managed-schema mysql-connector-java-5.1.7-bin.jar solrconfig.xml data-config.xml ext.dic stopword.dic
solr-ik中文分词器资源包,包括ext.dic,,IKAnalyzer.cfg.xml,,ik-analyzer-solr5-5.x.jar,,managed-schema,,solr-analyzer-ik-5.1.0.jar,,stopword.dic
solr
solr
他的主要特性包括:高效,灵活的缓存功能,垂直搜索功能,高亮下试搜索结果,通过索引复制来提高可用性,提供一套强大的data schema 来定义字段,类型和设置文本分析,提供基于web的管理界面等。
solr安装设置资料solr安装设置资料
solr文档
solr搜索框架的中文分词器文件及配置详解供大家下载,亲测可用....编辑cor下路径的managed-schema文件(solr-8.1.1\server\solr\configsets\_default\conf下拷贝到solr_home的具体CORE名称文件夹下的schema文件)
5.1 schema.xml 9 5.1.1 文件分析 9 5.1.2 文档注释 13 5.2 solrconfig.xml 16 6.Solr缓存 18 6.1 filterCache 18 6.2 queryResultCache 18 6.3 documentCache 19 7.solrj wiki 19 7.1 SolrJ/Solr cross-version ...
solr manageschema 配置文件,增加了分词器后的配置文件
solr技术文solr技术文solr技术文
Solr定时更新Solr定时更新
完全配置好的solr容器,直接修改web.xml设置一下solr core路劲即可
如何使用solr搭建服务器
Solr 依存于Lucene,因为Solr底层的核心技术是使用Lucene 来实现的,Solr和Lucene的本质区别有以下三点:搜索服务器,企业级和管理。Lucene本质上是搜索库,不是独立的应用程序,而Solr是。Lucene专注于搜索底层的...