Solr自己的性能不错,可是在使用过程当中,仍是会遇到一些使用错误,或是没考虑到的地方;在出现瓶颈时,能够首先考虑哪些点呢?下面就来看一下Solr官方的总结,我的以为总结的很好。SOLR+LUCENE的官网仍是挺给力的。
对Schema设计的考虑
索引域的数量增加会很大程度的影响如下的内容:
引用
索引期间的内存使用
段的合并时间
优化(optimization)时间
若是设置omitNorms="true" ,则能够减少对这些影响
批注:若是设置Norms,则会影响评分的标准,但会大大的增大索引文件的大小,若是对该字段没有需求,建议关掉
存储域
经过查询结果获取存储域的值是一个至关大的开销。若是文档的数据特别大,或者一些数据存储到了分布式的磁盘中(须要更多的IO来查询域)时,那么花费将会很大。这在存储大数据时很容易被考虑到,尤为是整个文档内容的存储。
考虑将大数据的存储放到solr以外。若是非要这么作,那么能够考虑使用压缩域,这将会用CPU的开销来换取IO的开销。
若是你并不须要使用全部的存储域,容许延迟加载(enableLazyFieldLoading)将会是很好的方式,因为是对那些压缩的字段。
批注:延迟加载在查询期间颇有用,尤为是须要对某些字段做额外的处理时,它既能减小内存使用,又加速了程序的处理。另外,尽可能减少索引的大小绝对不是坏事。
SOLR配置考虑
mergeFactor
mergeFactor大体决定了段的数量。mergeFactor的值告诉lucene有多少个段须要进行合并。它能够被认为是一个基本的数量系统。
举个例子,若是你设置mergeFactor为10,每1000个文档时会建立一个新的段到硬盘中。当第10个段被添加时,全部的10个段将被合并为1个段 (包含10000个文档);当这样的10个文档被建立时,它们又会被合并为个包含100,000个文档的段,依次类推(固然也有上限)。这样,在任什么时候候,都不会有多余9个的段(相同索引大小状况下)存在。
该值在solrconfig.xml中的mainIndex设置(它会忽略indexDefaults)。
批注:关于合并的策略,请看我以前的博客:lucene内部的合并策略
mergeFactor Tradeoffs
高值的merge factor(好比25):
引用
Pro:通常会加快索引的速度
Con:低合并延迟,在查询时须要搜索更多的文件,因此会使查询变慢
低值的merge factor(好比2):
引用
Pro:更少的索引文件,加快查询的速度
Con:更多的文件合并,将使索引变慢
批注:通常来讲不须要这么极端,设10便可。保证读速度的同时,也保证合并的速度。
HashDocSet最大值的考虑
SOLR1.4以后不支持了,再也不描述。
cache中autoWarm数量的考虑
当一个新的searcher被打开时,它的cache能够从旧的searcher中从新加载或者自动预热(autowarmd)缓存的对象。autowarmCount是将被拷贝到新searcher中的对象的数量,你须要根据autowarm的时间来设置autowarmCount。如何使用autowarmCount,须要你根据时间和数量来设定。
批注:autoWarm即新的searcher会有多少数据被缓存,若是没有缓存,一些热点数据无疑会变得很慢。因此,合理的这是这个值,能大大加快查询的效率。
缓存命中率
在Solr的admin中监控缓存的统计。增长缓存的大小一般是提升性能的最好方法,尤为是你对一个指定的缓存类型做逐出操做时。请关注filterCache,它也被用来做solr的facetting。
批注:一个典型的场景是范围查询,相似fl=price:[100 TO 200]这样的状况,将数据该范围存储起来时,对其余的一些查询均可以复用这个缓存的数据,很高效。
对排序的域做明确的预热
若是你的工做大多基于排序的方式,那么你最好在“newSearcher”和“firstSearcher”时间监听器中添加明确的预热查询规则,这样FiledCache能够在用户的查询被执行前就将数据加载。
优化的考虑
你可能想在任什么时候候均可以优化你的索引。好比你建立索引后,就没有修改过它。
若是你的索引收到了一串须要更新的流,那么请考虑如下的因素:
引用
1. 若是过多的段被添加到索引中,那么查询的性能将会降低;lucene的段自动合并能将段的数量控制在必定范围
2. auto-warming的时间也会延长,它一般依赖于所作的查询
3. 优化后的第一次分布耗时比以后的分布耗时要长。具体请看
Collection Distribution
4. 在优化期间索引的问题大小会加倍,优化后会回到原始大小或更小
5. 若是能够,请确保没有并发的commit请求,不然会有很大的性能损失
在优化时全部的索引会放到惟一的段中;优化索引会避免“文件打开数过多”的问题。
这里有一篇关于该问题的文章:
ONJava Article
更新和提交的频率
若是slaves收到的数据过频,那么性能必然受损。为了不这个问题,你必须了解slaver的更新机制,这样你才能更好的调整相关的参数(commit的数量/频率、snappullers、autowarming/autocount)以使新数据的写入不会那么频繁。
引用
1. 集合的快照会在客户端运行commit时创建,或者在optimization时;这依赖于在master上的postCommit或postOptimize的钩子方法
2. slaver上的Snappuller会运行corn去检查master上是否有新的快照,若是它找到新的版本,就会把它拿过来并install这些新的数据。
3. 当一个新的searcher被打开时,autowarming会先于Solr的查询请求以前完成。有了预热的缓存,查询的延迟将会小不少。
这里有三个相关的参数:
引用
快照的数量/频率:这取决于客户端的索引。所以,集合的版本号依赖于客户端的活跃度
snappluller:基于cron,他能够精确到秒级别。它们运行时,会获取最近它们没有的集合
缓存预热:在solrconfig.xml中配置
查询响应的压缩
在Solr返回xml应答给客户端以前对其进行压缩有时是值得作的。若是应答结果很是大,或者网络IO有限制,或者没有千兆网卡,请考虑使用压缩机制。
压缩会增长CPU的使用,而且Solr自己也是CPU密集型的应用,因此压缩会下降查询的性能。压缩会使文件减少到1/6的大小,使网络包减少到1/3的大小;相对的,查询的性能会下降15%左右。
请查看你的应用服务器的相关文档(tomcat、resion、jetty...)来获取关于压缩的信息。
索引的性能
通常状况下,一次更新多个文档比一个一个更新要快。
对于这种块级的更新方式,考虑使用
StreamingUpdateSolrServer.java,它提供多线程多链接的方式来更新流数据。
批注:StreamingUpdateSolrServer类相对CommonsHttpSolrServer要快不少,主要在于它将本来单个的文档写入变为了批量写入,加上多线程多链接的方式,性能上快了超多。咱们的测试数据代表,至少要快4-6倍以上。
内存使用的考虑
OutOfMemoryErrors
若是你的solr实例没有足够的内存,那么JVM有时会抛出OutOfMemoryErrors。这并不会对数据有影响,而且solr也会试图优美的恢复它。任何 添加/删除/提交 的命令在异常抛出时均可能不成功;其余不利的影响也可能会产生。对应用而言,若是SimpleFSLock 的锁机制在使用的话,OutOfMemoryError 会致使solr丢失这个锁。若是这发生了,更新索引的结果将会是这样的异常:
- SEVERE: Exception during commit/optimize:java.io.IOException: Lock obtain timed out: SimpleFSLock@/tmp/lucene-5d12dd782520964674beb001c4877b36-write.lock
SEVERE: Exception during commit/optimize:java.io.IOException: Lock obtain timed out: SimpleFSLock@/tmp/lucene-5d12dd782520964674beb001c4877b36-write.lock
若是你想在OOM时看堆的状况,请设置"-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/the/dump"
JVM内存的分配
针对这个错误的最简单方法,在JVM并无彻底使用你的物理内存时,考虑加大JVM的内存容量:
- java -Xms512M -Xmx1024M -jar start.jar
java -Xms512M -Xmx1024M -jar start.jar
影响内存使用的因素
你可能想去减少solr的内存使用。
一个方式就是减少文档的大小。
当运行add命令时,标准的xml更新请求会有两个限制:
引用
1. 全部的文档必须同时放入到内存中。一般,它的取值为sum(域的实际长度,maxFieldLength)。因此,调整maxFieldLength的大小可能会有帮助 2. 每一个<field>...</field>标签都必须放入到内存中,而无论maxFieldLength
注意一些不一样的add请求会在不一样的线程中并发运行。越多的线程,就会致使越多的内存使用。 个人一些其余使用经验: 1.schema中的类型定义很重要,它直接影响了索引的性能 2.尽可能少用filter,虽然它很好用,可是其hashSet的数量若是过多,很容易oom 3. cache的类,都用FastLRUCache吧,LRUCache还有锁,太慢了 4. 经过docId取doc的过程看似日常,可是量大了就是一个灾难,在这点须要根据实际场景考虑 5. 能用缓存的用缓存,不能用缓存的,尝试使用MMapDirectoryFactory,最好是SSD硬盘 6.其余,待想到了再补充