solr 1.3 中使用的 cache 是 LRUCache,可以用 memcached 实现 SolrCache,替换 solr 的默认的 LRUCache。
环境描述:有 N 台 solr 的子机(只提供搜索服务,用户搜索请求负载均衡到这些机器,N > 2),solr 默认缓存是 LRUCache。单台机的内存是有限制的,而且每台机的缓存是独立的,而请求是轮询分布到每台机上,所以缓存会有重复、且会浪费。把每台机的缓存都放到 memcached 中,每台子机共同创建缓存,并且可以分享其它机器创建的缓存,再加上 memcached 容量大,命中率会有提升。
于是,我就想用 memcached 来实现 solr 的 queryresultCache,其实其它 SolrCache 也一样吧。实现的过程,发现 solr 相关的某些类不支持序列化的,所以无法保存到 memcached 中。还是先为 solr 打个 patch 吧。补丁文件 solr-memcache.patch 如:
- Index: src/java/org/apache/solr/search/DocSet.java
- ===================================================================
- --- src/java/org/apache/solr/search/DocSet.java (revision 781268)
- +++ src/java/org/apache/solr/search/DocSet.java (working copy)
- @@ -17,6 +17,8 @@
- package org.apache.solr.search;
- +import java.io.Serializable;
- +
- import org.apache.solr.common.SolrException;
- import org.apache.solr.util.OpenBitSet;
- @@ -138,7 +140,7 @@
- }
- /** A base class that may be usefull for implementing DocSets */
- -abstract class DocSetBase implements DocSet {
- +abstract class DocSetBase implements DocSet, Serializable {
- // Not implemented efficiently... for testing purposes only
- public boolean equals(Object obj) {
Index: src/java/org/apache/solr/search/DocSet.java =================================================================== --- src/java/org/apache/solr/search/DocSet.java (revision 781268) +++ src/java/org/apache/solr/search/DocSet.java (working copy) @@ -17,6 +17,8 @@ package org.apache.solr.search; +import java.io.Serializable; + import org.apache.solr.common.SolrException; import org.apache.solr.util.OpenBitSet; @@ -138,7 +140,7 @@ } /** A base class that may be usefull for implementing DocSets */ -abstract class DocSetBase implements DocSet { +abstract class DocSetBase implements DocSet, Serializable { // Not implemented efficiently... for testing purposes only public boolean equals(Object obj) {
我已经放在 google 项目中,可以下载:http://code.google.com/p/solr-side/issues/detail?id=1&can=1。
上面只是先直接看下补丁文件,solr memchached 缓存查询结果的实现也可以在 google 项目中下载:http://solr-side.googlecode.com/files/solr-memcache.zip,全部东西都在这个 zip 里。现讲下怎么用它。
假设已经下载 solr 1.3 并解压到 d:/apache-solr-1.3.0,solr-memcache.zip 解压到 d:/apache-solr-1.3.0/contrib/solr-memcache。
复制 patch-build.xml 和 solr-memcache.patch 到 d:/apache-solr-1.3.0,然后cmd 进入 d:/apache-solr-1.3.0 目录,运行
D:\apache-solr-1.3.0>ant -f patch-build.xml -Dpatch.file=solr-memcache.patch
Buildfile: patch-build.xml
apply-patch:
[patch] patching file src/java/org/apache/solr/search/DocSet.java
BUILD SUCCESSFUL
Total time: 0 seconds
为 solr 1.3 打缓存系列化相关的补丁成功了(ant 为 solr 打补丁的方式请看:http://blog.chenlb.com/2009/02/ant-apply-source-patch-task-demo.html,另一 solr 补丁示例 http://blog.chenlb.com/2009/04/apply-solr-collapsing-patch-remove-duplicate-result.html)。接下来构建 solr 与 solr-memcahce,运行如下:
D:\apache-solr-1.3.0>ant dist
...
现在可以发现已经有 D:\apache-solr-1.3.0\dist\apache-solr-memcache-1.3.0.jar 文件了,同时也有 D:\apache-solr-1.3.0\dist\apache-solr-1.3.0.war 文件(已经打过补丁的)。
把 solr-memcache 安装使用上。把 apapache-solr-memcache-1.3.0.jar 和依赖的 memcached-2.2.jar、spy-2.4.jar(可以在 solr-memcache/lib 下找到) 放到 solr.home/lib 下(我想把它独立没有把它放到 apache-solr-1.3.0.war 里)。
修改 solr.home/conf/solrconfig.xml 配置告诉 solr 怎么使用 Memcached 实现的 Cache。这次实现的目的主要用在 queryresultCache 上。在 solrconfig.xml 的 query 元素内找到 queryresultCache,把原来的注释掉,改如下的:
- <!--
- MemcachedCache params:
- memcachedHosts (required), "," split.
- name (optional) no default.
- expTime (optional) default 1800 s (= 30 minute)
- defaultPort (optional) default 11211
- keyPrefix (optional) default ""
- -->
- <queryResultCache
- class="solr.MemcachedCache"
- memcachedHosts="192.168.0.100,192.168.0.101:1234,192.168.0.103"
- expTime="21600"
- defaultPort="11511"
- keyPrefix=""/>
<!-- MemcachedCache params: memcachedHosts (required), "," split. name (optional) no default. expTime (optional) default 1800 s (= 30 minute) defaultPort (optional) default 11211 keyPrefix (optional) default "" --> <queryResultCache class="solr.MemcachedCache" memcachedHosts="192.168.0.100,192.168.0.101:1234,192.168.0.103" expTime="21600" defaultPort="11511" keyPrefix=""/>
再在 query 元素内(就在 queryResultCache 下面不远处可以找到类似的 listener )新增加如下内容:
- <listener event="newSearcher" class="solr.MemcachedCache" />
- <listener event="firstSearcher" class="solr.MemcachedCache" />
<listener event="newSearcher" class="solr.MemcachedCache" /> <listener event="firstSearcher" class="solr.MemcachedCache" />
用打过补丁的 war 安装到 tomcat (安装可参考:http://blog.chenlb.com/2009/05/apache-solr-quick-start-and-demo.html)。
上面 listener 的内容主要是取得索引版本号。启动运行,效果如下:
多个子机共用一个 memcached 的确可以提高命中率,在我的实际应用环境中,原来命中率在 10% - 15% 左右,用 solr memcached cache 后,提高到了 58% 左右。不过我没测试过它有多少的性能提升(索引比较大,命中的情况,查询时间是可以减少的),主要用它来提高命中率的。
把它用在 documentCache 也应该可以的(我没测试过,因为我觉得 documentCache 没必要用 memcached 除非网络速度快过磁盘),所有我不建议 documentCache 使用它。
我为了以后升级 solr 方便,已经把 solr memcached 实现提交给 solr 官方 jira 里,并且官方已经接受,准备在 solr 1.5 中实现这个功能。请看:http://issues.apache.org/jira/browse/SOLR-1197。