亿级数据的高并发通用搜索引擎架构设计(转-张宴)
[文章作者:张宴 本文版本:v1.0 最后修改:2008.12.09 转载请注明原文链接:http://blog.zyan.cc/post/385/]
曾经在七月,写过一篇文章──《基于Sphinx+MySQL的千万级数据全文检索(搜索引擎)架构设计》,
前公司的分类信息搜索基于此架构,效果明显,甚至将很大一部分带Where条件的MySQL
SQL查询,都改用了Sphinx+MySQL搜索。但是,这套架构仍存在局限:一是MySQL本身的并发能力有限,在200~300个并发连接下,查询
和更新就比较慢了;二是由于MySQL表的主键与Sphinx索引的ID一一对应,从而无法跨多表建立整站查询,而且新增加类别还得修改配置文件,比较麻
烦;三是因为和MySQL集成,无法发挥出Sphinx的优势。
最近,我设计出了下列这套最新的搜索引擎架构,目前已经写出“搜索查
询接口”和“索引更新接口”的beta版。经测试,在一台“奔腾四 3.6GHz
双核CPU、2GB内存”的普通PC机,7000万条索引记录的条件下,“搜索查询接口”平均查询速度为0.0XX秒(查询速度已经达到百度、谷歌、搜
狗、中国雅虎等搜索引擎的水平,详见文章末尾的“附2”),并且能够支撑高达5000的并发连接;而“索引更新接口”进行数据分析、入队列、返回信息给用
户的全过程,高达1500 Requests/Sec。
“队列控制器”这一部分是核心,它要控制队列读取,更新MySQL主表与增量表,更新搜索引擎数据存储层Tokyo Tyrant,准实时(1分钟内)完成更新Sphinx增量索引,定期合并Sphinx索引。我预计在这周写出beta版。
图示说明:
1、搜索查询接口:
①、Web应用服务器通过HTTP POST/GET方式,将搜索关键字等条件,传递给搜索引擎服务器的search.php接口;
②③、search.php通过Sphinx的API(我根据最新的Sphinx 0.9.9-rc1
API,改写了一个C语言的PHP扩展sphinx.so),查询Sphinx索引服务,取得满足查询条件的搜索引擎唯一ID(15位搜索唯一ID:前5
位类别ID+后10位原数据表主键ID)列表;
④⑤、search.php将这些ID号作为key,通过Memcache协议一次性从Tokyo Tyrant中mget取回ID号对应的文本数据。
⑥⑦、search.php将搜索结果集,按查询条件,进行摘要和关键字高亮显示处理,以JSON格式或XML格式返回给Web应用服务器。
2、索引更新接口:
⑴、Web应用服务器通过HTTP POST/GET方式,将要增加、删除、更新的内容告知搜索服务器的update.php接口;
⑵、update.php将接收到的信息处理后,写入TT高速队列(我基于Tokyo Tyrant做的一个队列系统);
注:这两步的速度可达到1500次请求/秒以上,可应对6000万PV的搜索索引更新调用。
3、搜索索引与数据存储控制:
㈠、“队列控制器”守护进程从TT高速队列中循环读取信息(每次50条,直到末尾);
㈡、“队列控制器”将读取出的信息写入搜索引擎数据存储层Tokyo Tyrant;
㈢、“队列控制器”将读取出的信息异步写入MySQL主表(这张主表按500万条记录进行分区,仅作为数据永久性备份用);
㈣、“队列控制器”将读取出的信息写入MySQL增量表;
㈤、“队列控制器”在1分钟内,触发Sphinx更新增量索引,Sphinx的indexer会将MySQL增量表作为数据源,建立增量索引。Sphinx的增量索引和作为数据源的MySQL增量表成对应关系;
㈥、“队列控制器”每间隔3小时,短暂停止从TT高速队列中读取信息,并触发Sphinx将增量索引合并入主索引(这个过程非常快),同时清空
MySQL增量表(保证了MySQL增量表的记录数始终只有几千条至几十万条,大大加快Sphinx增量索引更新速度),然后恢复从TT高速队列中取出数
据,写入MySQL增量表。
本架构使用的开源软件:
1、Sphinx 0.9.9-rc1
2、Tokyo Tyrant 1.1.9
3、MySQL 5.1.30
4、Nginx 0.7.22
5、PHP 5.2.6
本架构自主研发的程序:
1、搜索查询接口(search.php)
2、索引更新接口(update.php)
3、队列控制器
4、Sphinx 0.9.9-rc1 API的PHP扩展(sphinx.so)
5、基于Tokyo Tyrant的高速队列系统
附1:MySQL FullText、Lucene搜索、Sphinx搜索的第三方对比结果:
1、查询速度:
MySQL FullText最慢,Lucene、Sphinx查询速度不相上下,Sphinx稍占优势。
2、建索引速度:
Sphinx建索引速度是最快的,比Lucene快9倍以上。因此,Sphinx非常适合做准实时搜索引擎。
3、详细对比数据见以下PDF文档:
![](http://zyan.cc/template/RuiPai/images/download.gif)
附2:国内各大中文搜索引擎搜索速度分析:
以“APMServ张宴”为关键字,比较在各大中文搜索引擎的搜索速度:
1、百度:
①、第一次搜索
②、第二次搜索
分析:百度对第一次搜索的搜索结果做了Cache,所以第二次查询非常快。
2、谷歌:
①、第一次搜索
②、第二次搜索
分析:谷歌也对第一次搜索的搜索结果做了Cache,但两次查询跟百度同比,都要慢一些。
3、搜狗:
①、第一次搜索
②、第二次搜索
③、第三次搜索
分析:搜狗疑似对第一次搜索的搜索结果做了短暂的Cache,第二次搜索速度非常快,第三次搜索的速度比第二次搜索的速度慢。搜狗第一次搜索的速度跟百度差不多。
4、中国雅虎:
①、第一次搜索
②、第二次搜索
分析:搜索结果没有做Cache。中国雅虎的搜索速度跟百度第一次搜索的速度差不多。
5、网易有道:
①、第一次搜索
②、第二次搜索
分析:有道对第一次搜索的搜索结果做了Cache。但是,跟谷歌一样,两次搜索同比都要较百度、搜狗、中国雅虎慢一些。
![给他/她发邮件 Email](http://zyan.cc/template/RuiPai/images/email.gif)
![访问他/她的主页 Homepage](http://zyan.cc/template/RuiPai/images/homepage.gif)
ttserver对php内容无法反序列化,不支持压缩,这两点也很讨厌。
要是没有这几个问题就好了。
![smile](http://zyan.cc/images/emot/smile.gif)
一个人将记录写到了缓存,数据库中并更新索引,
另一个人通过索引从缓存或数据库中读出记录.
![grin](http://zyan.cc/images/emot/grin.gif)
搜索引擎Cache命中率一般在60%略高的样子,索引所用的内存都是几百G几百G的
你这个只对增量增加敏感,好像删除的话不能更新索引吧?
不过不得不赞一下你这个也相当棒:)
所以,相对而言,我的这套索引单台机器支撑1亿索引,达到Google/Baidu/Sogou的查询速度,算不错了。
至于和Lucene的比较,Sphinx拥有下列与Lucene所对应的权重计算模式,那个PDF文档已经在各种类型下与Lucene进行比较:
SPH_RANK_PROXIMITY_BM25, default ranking mode which uses and combines both phrase proximity and BM25 ranking.
SPH_RANK_BM25, statistical ranking mode which uses BM25 ranking only (similar to most other full-text engines). This mode is faster but may result in worse quality on queries which contain more than 1 keyword.
SPH_RANK_NONE, disabled ranking mode. This mode is the fastest. It is essentially equivalent to boolean searching. A weight of 1 is assigned to all matches.
SPH_RANK_WORDCOUNT, ranking by keyword occurrences count. This ranker computes the amount of per-field keyword occurrences, then multiplies the amounts by field weights, then sums the resulting values for the final result.
SPH_RANK_PROXIMITY, added in version 0.9.9, returns raw phrase proximity value as a result. This mode is internally used to emulate SPH_MATCH_ALL queries.
SPH_RANK_MATCHANY, added in version 0.9.9, returns rank as it was computed in SPH_MATCH_ANY mode ealier, and is internally used to emulate SPH_MATCH_ANY queries.
增 量索引能够实现索引的增加、更新。索引的删除更简单,Sphinx支持属性标记,假如正常状态is_delete属性为0,那么删除就将 is_delete属性标记为1,属性标记是在内存中进行的,在Sphinx停止时自动写入磁盘,非常快,因而删除索引可以说是实时的。在合并索引时,通 过--merge-dst-range参数,即可排除掉被标记为删除的索引。
我发现凡带 [ ] 号的会对检索结构有严重干扰.
我也想知道?