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.其餘,待想到了再補充