问题描述
现在的搜索架构 QProxy -> Nginx -> Dispatch Nodes -> Search Nodes。
最下层的Search Nodes保持了一个query命中的docList,但是其它信息,比如title,content等展示的内容每次query都需要重新读取,这将依赖于系统的Cache机制。
而最终搜索结果的Cache(xml/json)是没有被cache的。
现在Nginx实现了Dispatch Nodes的fail over和负载均衡,但是目前并没有实现Cache,这次的任务就是实现Nginx层的cache。而QProxy层现在也没有实现Cache,所以这个问题变得非常重要。
已有的解决方案
目前Nginx实现的Cache方法包括:基于memcached的Cache,Proxy_Cache模块,具体参考nginx缓存cache的5种方案 。
Proxy_Cache
优点是:它是Nginx的核心模块,比较稳定。缺点是:它是基于磁盘的Cache,相对于memcached这样的实现来看,速度会慢一些。
Nignx的Memcached模块
优点是:也是Nginx的核心模块。缺点,没有完全实现Memcached的协议,只能读取Memcached的内容,而不能写入
基于HttpMemcached模块的解决方案
由于Nginx的标准Memcached模块不能写入Memcached,所以目前流行的解决方案如下图,Nginx读取Memcached,如果失败,那么把请求转发给后台的服务器,并返回结果。后台服务器处
理结束后,还需要把结果写入Memcached,这样下次Nginx就可以直接读取Memcached的cache了。
具体实现参考Killer Java applications server with nginx and memcached
这个解决方案的缺点是,需要JSP/PHP来写Memcached,这样它必须了解Memcached的位置,不便于把配置和cache信息集成的Nginx这一层。
解决方案
我们现在的解决方案和上图类似,唯一的区别就是Tomcat不用写Cache,而是由Nginx来写入Cache。
为了实现Nginx写入Cache,我们使用了第三方的Nginx模块,章亦春写的NginxHttpMemcModule 和SR Cache模块
另外我们作为Key的url参数比较长,可能会大于Memcached最大的长度250。当然我们可以修改Memcached的头文件memcached.h来解决这个问题:
#define KEY_MAX_LENGTH 250
不过感觉这样不太好,所以使用了MD5为url参数生成指纹来作为memcached的key,这要用到Set-Misc模块 和 Devel_Kit模块
此外为了调试方便,也安装了Echo模块 。
安装配置
安装libevent
安装Memcached需要先安装libevent,所有需要的文件都放在/home/qsearch/memcached里了。
cd /home/qsearch/memcached/libevent-2.0.10-stable
./configure
make -j8
sudo make install
安装Memcached
cd /home/qsearch/memcached/memcached-1.4.5
./configure
make -j8
sudo make install
ldd memcached 或者运行它,比如"error while loading shared libraries: libevent-2.0.so.5",原因是刚安装的libevent.so还没有被系统知道,所以需要/sbin/ldconfig一下
为什么编译的时候没有错误呢?因为编译时会去/usr/lib/下找需要的so,所以能编译通过。而运行时为了效率,系统不会每次都扫描/usr/lib的内容,所以并不知道安装了新的libevent.so,所
以需要ldconfig一下。网上的解决方法 不是好的方法。
如果有老版本的libevent,想用新的版本链接,可以在Makefile里修改这行 LIBS = -L/usr/local/lib/ -levent
安装Nginx
安装的文件都放到/home/qsearch/nginx里,我们选择安装最新稳定版本0.8.54
./configure --prefix=/opt/nginx /
--with-pcre=../pcre-8.12 /
--add-module=../agentzh-echo-nginx-module-53f3dd9 /
--add-module=../simpl-ngx_devel_kit-7dbb4ce /
--add-module=../agentzh-set-misc-nginx-module-3967b60 /
--add-module=../agentzh-headers-more-nginx-module-7bba2a1 /
--add-module=../agentzh-memc-nginx-module-15c9303 /
--add-module=../agentzh-srcache-nginx-module-12e5418
make -j8
make install
配置Nginx
gzip on;
gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript application/atom+xml;
upstream qsearch {
server l-schr1.s.cn5.qunar.com:8080 max_fails=1 fail_timeout=600s;
server l-schr2.s.cn5.qunar.com:8080 max_fails=1 fail_timeout=600s;
server l-schr3.s.cn5.qunar.com:8080 max_fails=1 fail_timeout=600s;
server l-schr4.s.cn5.qunar.com:8080 max_fails=1 fail_timeout=600s;
server l-schr5.s.cn5.qunar.com:8080 max_fails=1 fail_timeout=600s;
server l-schr6.s.cn5.qunar.com:8080 max_fails=1 fail_timeout=600s;
}
上面开启gzip压缩,然后qsearch这个upstream的6台机器是dispatch节点,由Nginx来实现负载均衡和fail-over。上面的配置1次失败就让它休息10分钟
location /solr/travel/ {
charset utf-8; # or some other encoding
default_type text/plain; # or some other MIME type
set $key $query_string;
set_md5 $key;
srcache_fetch GET /memc $key;
srcache_store PUT /memc $key;
more_clear_headers 'Accept-Encoding';
proxy_pass http://qsearch;
}
location /memc {
set $memc_key $query_string;
set $memc_exptime 300;
#memc_pass l-indx5.s.cn5.qunar.com:11211;
memc_pass 127.0.0.1:11212;
}
上面的配置告诉Nginx,如果用户访问/solr/travel/,那么使用query的参数做为key,生成MD5,去/memc获取cache,如 果没有命中,那么走proxy_pass,访问dispatch Nodes。 location /memc 是memcached的配置,比如配置一条cache的过期时间为300s,memcached的地址为127.0.0.1:11212,更多的配置参考 NginxHttpMemcModule的文档。