Solr 影响性能的因素。

翻译自

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

schema 设计的注意事项

索引字段

索引字段的数量大大的增加了以下内容:

  • 在索引期间的内存使用量
  • 段合并的时间
  • optimize 的次数
  • 索引的大小

可以通过设置 omitNorms=true 来减少这些影响

存储字段

检索查询结果的存储字段是一笔非常大的开销。这个开销受每个文档所需要存储的字节数量所影响。存储的字节数越高,这些文档将会被稀疏的分布在磁盘上,需要更多的 I/O 来进行检索这些存储字段(通常这个考虑是在存储比较大的字段时,例如整个文档的内容)

可以考虑在 solr 之外存储大字段。如果你倾向于这种形式,那么可以考虑使用压缩域,这样会增加在检索字段时 CPU 的消耗,但是会降低 I/O 的负担以及 CPU 的使用率。

如果你并不是一直都需要使用存储字段,可以让存储字段懒加载,这样有很大的好处,特别是对于压缩字段。

配置注意事项

mergeFactory

mergeFactory 可以大致决定段的数量。

mergeFactory 的值告诉 Lucene 有多少个段之后才把它们合并成一个段。

例如:你设置 mergeFactory=10,每 1000(或者 maxBufferedDocs) 个文档会在磁盘上新建一个段。当第 10 个包含 1000 个文档的段被添加时,所有这 10 个段将会被合并成一个包含 10000 文档的段。当 10 个这样包含 10000 个文档的段被添加时,它们又会合并成一个包含 100000 个文档的段,依此类推。所以,在任何时候,任何索引的大小不会超过 9 个段。

这些值可以在 solrconfig.xml 中 *mainIndex* 部分进行设置(忽略 indexDefaults 部分)

注:mainIndex 跟 indexDefaults 都可以忽略了,现在通过 indexConfig 来设置

mergeFactor 的权衡

mergeFactory 的值较大(例如:25)

  • 利:会提高索引的速度
  • 弊:降低合并的频率,导致索引文件过多,会降低搜索

mergeFactory 的值较小(例如:2)

  • 利:索引文件的数量变少,加快搜索
  • 弊:更多的索引段合并会降低索引

缓存自动预热数量的注意事项

当打开一个新的 searcher 时,它的缓存可以从旧 searcher 的缓存中获取,进行自动预热。autowarmCount 表示多少数目的缓存条目复制到新的 searcher。你可以根据 autowarmCount 的值计算需要多长时间去自动预热。你必须权衡自动预热的时间与自动预热的数量。自动预热的参数在 solrconfig.xml 中设置。

明确 sort field 的预热

如果你有很多字段基于排序,那么在 solrconfig.xml 中通过配置 “newSearcher” 和 “firstSearcher” 的预热查询监听事件,对这些排序字段是有用的。因为在任何查询执行之前 FieldCache 会被优先填充。

optimize 注意事项

你可能想在某些特定的情况下对索引做 optimize 操作。例如:构建了 一次索引之后,再也不修改它。

如果你经常改变索引,而不是 optimize,那么你很可能想要一个比较低的 mergeFactory。如果索引持续的改变,那么 optimize 操作非常昂贵,轻微的性能提醒不会持续很长的时间。在静态索引文件上不值得做这种权衡。

在主从模式中,如果想对 master 做 optimize 操作,让 slave 去提供服务。但是这种会增加复制索引的时间,所以通常是不可取的。

注:你大爷,都是不建议做的。你倒是告诉我什么是建议做的呀。

压缩查询响应

某些情况下,在返回客户端之前,将 XML 的响应信息进行压缩是很有用的。如果响应的内容非常大,网络 I/O 很容易到达瓶颈。所以使用压缩是一个办法。

虽然压缩会增加 CPU 是的使用,但是 Solr 本身就是一个计算密集型的服务。压缩能够降低查询性能。压缩可以使原始文件减少 $\frac{1}{6}$,网络包减少 $\frac{1}{3}$。查询性能会受到 15% 左右的影响。

索引性能

一般来说,一次更新多个文件比一次更新一个文件要快。

减少自动提交的频次,或者完全禁用它们可以加速索引。因为这会增加内存的使用,导致本身的性能问题。例如:过度交换、垃圾回收。

内存使用注意事项

OutOfMemoryErrors

如果你没有足够的内存分配给你的 solr 实例,那么 JVM 会抛出 OutOfMemoryError 异常。当这种情况出现时,不会有数据损坏的风险,Solr 会试图优雅的去恢复(注:真 TM 优雅)。当这个错误发生时,任何正在进行中的 add / delete / commit 操作都不会成功。而且会导致一些其它的问题。例如:如果 SimpleFSlock 锁机制正在使用中,OutOfMemoryError 会导致 solr 丢失索引上的锁。

如果在 OOM 的时候,你想看堆内存的情况,可以设置 “-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/the/dump”。

分配内存给 JVM

解决这个问题有一个很简单的方法,假设 JVM 没有用掉全部的物理内存,那么增加分配给 JVM 的内存。(注:对,这种方式确实是很简单😒)

影响内存的因素

你肯定想减少 solr 实际使用时的内存。(注:这不是废话吗?)

其中一个因素就是提交文档的大小:

当通过 “add” 命令添加文档时,标准的 XML 处理器有两个限制:

  • 所有文档中的字段必须同时添加到内存中。(从技术上来说是:min(<实际域值的长度>, maxFieldLength)。所以通过调节 maxFieldLength 的长度可能会有用)
  • XML 文件中每一个单独的 ... 标签都必须放到内存中

注意:几个不同的 “add” 命令可以同时运行(在不同的线程中)。线程数越多,需要的内存越大。

在索引的时候,内存的使用会随着文档树的增加而增加,直到执行了一个 commit 命令。commit 命令(包括 soft commit)会释放掉几乎所有的内存。为了避免索引期间大量的内存使用以及垃圾回收导致的暂停,可以手动周期性的执行 (soft) commit,或者考虑在 solrconfig.xml 使用 autoCommit 或者 autoSoftCommit