Tag: beta技术沙龙

beta技术沙龙:大型网站的Lucene应用

beta技术沙龙越办越有意思了,上次错过了阙宏宇的mod_cache(还有关于线程进程的讨论)就很可惜,这次关于Lucene的演讲,是无论如何不应该错过了。

到目前为止,全文检索已经完全不算高技术门槛了,记得以前看过一本书里面写:“今天,任何程序员,都可以很容易地构造一个全文检索应用”。是的,全文检索的基本原理大家都知道差不多了,剩下的只是实践。我见过纯粹自己开发的,具有AS(Advanced Search)、BS(Basic Search)、DI(Digest)等结构,“像模像样”的全文检索架构,不过应用更多的,却是在开源项目上完善、定制而来的,Apache的Lucene就是众多开源全文检索项目中,名气最大、资格最老、应用也最广泛的一个。本期beta技术沙龙,讲的就是大型网站中lucene的应用,主讲人是手机之家团队的唐福林(“手机之家”总是有些东东来共享,比如上次的DAL,这真是不错)。

众所周知,用Lucene构造一个“索引-查询”的应用是非常简单的,搭好环境,参照(修改)示范代码,很容易就可以成功。但是,要构造一个真正大规模、稳定、可靠的应用,就不说这么简单。程序的编写、模块的分布、架构的设计,都有许多费心思的讲究。按照PPT提供的数据,手机之家目前的Lucene应用,采用的是Lucene 2.4.1 + JDK 1.6(64 bit)的组合,运行在8 CPU, 32G内存的机器上,数据量超过3300万条,原始数据文件超过14G,每天需要支持超过35万次的查询,高峰时期QPS超过20。单看这些数据可能并没有大的亮点,但它的重建和更新都是自动化完成,而且两项任务可以同时运行,另一方面,在不影响服务可靠性的前提下,尽可能快地更新数据(如果两者发生冲突,则优先保证可用性,延迟更新),其中的工作量还是非常大的。

演讲的主要内容都PPT里,非常丰富,我就不再赘述了。要补充的是,这份PPT做得非常清楚,需求-目标-进度-设计-上线-测试-上线,整个流程非常清楚,给出的数据同样非常精当,我想,这也反映了手机之家团队的开发规范。

因为对Lucene的使用稍微有些经验,我在这里补充几句,权当狗尾续貂:

  1. 在大规模的应用中,Lucene更适合用于狭义的“搜索”,而不应当负责数据的存储。我们看看Lucene的源代码也可以知道,Document和Field的存储效率是不够好看的。手机之家的团队也发现了这一点,他们的办法是,用Lucene存放索引,用Memcache + Berkeley DB(Java Edition)负责存储。这样有两个好处,一是减小了Lucene的数据规模,提高了程序的效率;另一方面,这套系统也可以提供某些类似SQL的查询功能。实际上,Lucene Project自己似乎也注意到了这个问题,在Store中新增了一个db选项,其实也是利用的Berkeley DB。如果仅仅用Lucene存放索引,而不存放Document,并且合理配置,一台机器可以支持几十G甚至上百G的索引;如果需要用Lucene存放索引,最好在读取时使用FieldSelector,只读取需要的Field,如果使用恰当,性能会有10%左右的提升。
  2. 在大规模应用中,Cache是非常重要的。PPT中也提到,可以在程序提供服务之前,进行几次”预热“搜索,填充Searcher的Cache。据我们(银杏搜索)的经验,也可以在应用程序中,再提供针对Document的Cache,这样对性能有较大的改善(同一个JVM内部的Cache,速度更快一些)。Lucene自己似乎也注意到了这个问题,在2.4版本中提供了Cache,并提供了一个LRU Cache实现。不过据我们测试,在极端情况下,这个Cache可能会突破大小限制,一路膨胀最后吃光内存,甚至从网络上找的许多LRU Cache实现在极端条件下都有可能出现这样的问题(这也是我们百思不得其解的地方:反复检查程序的逻辑都没有问题),最终自己写了一个LRU Cache,并修改多次,目前来看是稳定的。
  3. 在编写Java服务程序的时候,记得设置退出的钩子函数(RunTime.getRunTime.addShutdownHook)是一个非常好的习惯。许多Java程序员都没有这种意识,或者有,也只是写一个finalize函数,结果程序非正常退出时,可能造成某些外部资源的状态不稳定。拿Lucene来说,之前的IndexWriter是默认autoCommit的,这样每添加一条记录,就提交一次,好处是如果中断,则之前添加的记录都是可用的,坏处则是,索引的速度非常低。在新版本中autoCommit默认为False,速度提升明显(我们测试的结果是,提高了大约8倍),但如果中途异常退出,则前功尽弃。如果我们添加了退出的钩子函数,捕获到退出信号则自动调用writer.close()方法,就可以避免这个问题。
  4. 目前的Lucene是兼容JDK 1.4的,它的binary版本也是JDK1.4编译的,如果对性能要求比较高,可以自行下载Lucene Source Code,用更新版本的JDK编译出.jar文件,据我测试,速度大约有30%的提升。
  5. 如果对并发的要求较高,可以考虑采用多IndexSearcher的技术,也就是在一个应用服务中,开启多个IndexReader(可以对同样的索引开启多个),每个IndexReader再生成一个IndexSearcher,将这些Searcher放在一个“池”里头,给搜索请求调用。这样可以大幅度提高并发的性能,代价是在写程序的时候就要考虑到这一点,进行相应的调整。

P.S. 据我观察,国内公司内部的项目,一般取的名字都中规中矩,以’er’结尾的比较多,多是Indexer, Crawler, Layer之类。好像很少有外国那种“天马行空”的奇特名字,譬如Hadoop(这是一个“没来由”的名字)、Lucene(这是个少见的姓)。国内我接触过不多,以前抓虾有个重要的DB叫tudui(“土堆”),目前银杏有个项目叫LaserTank,都是跟实际用途毫不相关的,印象反而深刻。

老高之野望

本期beta技术沙龙的主题是“手机之家新系统介绍及架构分享 ”。手机之家是老高(高春辉)一手创办的网站,在我的印象里,上一次记得高春晖还是他的“高春辉的个人主页”,之后,好像就一直在折腾手机之家。现在的手机之家,每天PV超过700万,作为一个手机专业网站,相当了得(从我看到的数据,远远超过友人网)。

因为堵车的缘故,我赶到活动现场,演讲已经过去了大半,只抓住个尾巴。不过,手机之家有7年的发展经验,浓缩到这小小的讲座,即便只窥到一鳞半爪,也是很有启发的。

印象比较深刻的一点是Cache的结构。通常,Cache都被“扁平化”为单层的key-value对,这样的好处是,Cache的用户都可以方便地使用,没有太多的限制;而坏处在于,数据的结构被完全拆散了,同一个对象可能会按照不同的key来存储,而且各个对象之间的关联完全不存在了。
对这个问题,手机之家的解决办法是,在Cache和应用程序之间增加一个管理层,将程序员与Cache隔离开来,程序员可以不关心Cache的机制,只需要按照namespace(也就是划分层级的规范)来开发就可以。这个管理层,可以实现对Cache中对象的批量操作,也可以在某个对象发生变化之后,更新相关联的对象(直接更新父节点)。
这种办法的效果不错,而且演讲结束之后,还有朋友专门提出关于namespace的问题,看来,大家都觉得这思路很巧妙。

另一点印象就是老高他们重点介绍的DAL,也就是Data Access Layer,它把存储和缓存整个装到一起,与业务逻辑层完全隔离——业务逻辑单元完全只需要按照DAL设定的“增、删、改、查”四个接口操作数据就可以了。虽然普通的DBMS(譬如最常见的MySQL)也提供了这四种操作的接口,但相比DAL,一方面缺乏高效的缓存管理,另一方面,在大负载量、大容量下应用,还需要做许多工作;而有了DAL,前端程序不但不需要关心表的设计和结构,甚至连表的切分都不需要关心,相当省心。目前的DAL可以应付手机之家的现状,但PPT中也介绍了DAL 2.0的若干构想,包括提供类似Lucene(也就是全文检索)的查询功能,以及拆分核心功能、兼容插件的架构。
看得出来,DAL好像要从一个为手机之家打造的模块,变成“通吃(兼容)各家网站”的工具,在过去,有手机之家的经验做积累,对于未来的走向,也有明确的规划。我觉得,这是一条有风险、也有前途的路:一方面,对于通用组件的开发,我时常感到头痛,也许是经验不够的缘故,事先定义好的接口,往往(必然)被新冒出的需求所困扰,或者修改接口,或者眼睁睁把新需求踢出自己的“一亩三分地”,承认自己干不了;另一方面,之前固然有LiveJournal造出memcached的例子,但这样的几率实在是不高,况且,国内开源软件的氛围也与国外大不相同。
不过,无论如何,我都很佩服老高的这种“野心”:敢想才能敢干,而且,如果DAL真的能成功,成为“现成”的解决方案,就能省下大量的资源,投入到更有意义更有价值的地方,这绝对是一件功德无量的事情。

有兴趣的朋友,可以参考活动的PPT🙂

手机之家的架构分享
beta沙龙-手机之家架构的发展和变化
与”手机之家新系统介绍及架构分享”有关

P.S.手机之家还在招聘 PHP/Java 人手,有意者给老高发邮件: gaochunhui (AT) gmail.com

Beta技术沙龙记

俗话说“无巧不成书”,还真是这样。上周末的“巧”,就是RSS:周六跟抓虾的朋友们聚餐,周日下午Beta技术沙龙的主题就是“网易有道RSS阅读器”。

Beta技术沙龙在詹膑老师的“奇遇花园咖啡馆”举行。在车水马龙的西直门,能找到这样一个安静的地方,实属不易(当然也很难找,我们开玩笑说还应该开一家“齐秦菜园餐馆”)。装修也别有味道:明亮的落地窗,颀长的红色窗帘,极高的天花板……第一次去的时候,我瞥见高架上堆放着一排白色的书:“看那样子,应该是川端康成的《雪国》和《伊豆的舞女》吧?”,詹老师微笑颔首。

“有道”这个品牌,最早应该是作为博客搜索引擎出现的,07年末又诞生了有道阅读器。如今RSS在线阅读器日趋流行,有道赶上了好时候,又可借助网易的资源,相对其它一些阅读器,条件好得有点让人嫉妒,但是能在一年多的时间里做到今天这样的程度,也确实下了不少工夫。此次来的三位嘉宾,胡琛、王焱和刘懿,分别从运营、技术和产品三方面介绍了有道阅读器,包括遇到的问题,解决的办法,对未来的思考……看得出来,他们的准备非常认真仔细。
当然,既然名为“技术沙龙”,参与者最关心的,还是技术的方面:系统的架构是怎样的、采取了怎样的策略、出现问题如何解决……看他们的PPT,我最深刻的感觉是“天下大同”:各家的技术,或许细节上有所差异,但总的思路和方向,大抵不会相差太远。当然,最让我羡慕的还是他们可以使用网易的存储系统,轻松备份超过20T的数据,高枕无忧,这太让人嫉妒了(曾经有天晚上,我因为太困误删了极为重要的用户数据。当时已经十一点半,就准备休息了,结果惊出一身冷汗。而且之前没有及时备份,所以只能想法从四处导出数据“拼”回来,折腾到四点才算写完恢复程序,让它正常运行,第二天总算没让用户发现,那次事故印象太深刻了)。

整个沙龙的气氛轻松而随意。主题演讲结束之后,主持人说:“下面大家自由开小会吧”,于是会场瞬间热闹起来。坊间传言:“沙龙的成功程度,取决于小会的热闹程度”,这样看来,沙龙是很成功了。

这次活动还有点小意外——有位素不相识的朋友(原来是Robin)很意外“没想到《精通正则表达式》的译者也在场”。是的,我们都没想到,这倒正合咖啡馆的名字:奇遇花园。

现场图片(如果这是一张世界地图,我就在新西兰的位置:))