http://www.tuicool.com/articles/NZ7v6b数据库
阿里集团各大业务快速发展过程当中都对搜索服务不少刚性的须要,而这样的搜索需求有着很是明显的特征:快速支持、低成本、实时性和稳定性。缓存
快速支持:性能优化
业务需求急迫、须要一周甚至几天内完成索引服务搭建、测试、上线环节。服务器
低成本:架构
搜索需求方要求接入便捷,低成本的机器和运维成本。框架
实时性:运维
搜索需求方的业务数据发生变化,须要实时在索引中进行更新可见,而这个过程一般须要稳定的保证在100ms内。异步
稳定性:分布式
搜索服务集群不会由于升级、运维操做或者若干台机器的宕机致使搜索服务不稳定。oop
阿里的业务基本动辄就是上10亿上百亿规模,那么如何能行之有效的管理索引和保障搜索性能将是一个很是具备挑战性的工做。
互联网业务负责,那么涉及到须要进行检索的源数据可能来自多个数据库多个表,也就意味着索引数据源可能来源于多库多表,而且表和表之间还有1:N,N:N的关系。而使用过Lucene的同窗们都知道,对于基于Lucene为引擎内核的更新都是完整记录更新,因此对于咱们产品来讲构建索引时候避免不了多表join凑整更新问题。
在阿里的众多搜索需求场景下,不少时候是把搜索服务当作数据库使用,也就意味着一个页面上产生的更新操做,页面跳转后就能看到最新更新的结果,那么对于咱们搜索服务来讲须要在毫秒级别将更新结果可见。
阿里的业务对稳定性的要求是很是高的,因此对于升级、扩容、机器宕机等状况都不能影响正常的搜索和更新服务。
电商业务一年下来有很是多的大促活动,而一旦有大促活动,搜索的QPS将会比日常翻几倍。因此若是以大促的成本去衡量支持服务,整个服务所须要的机器在平时将很是空闲,从而形成了成本极大浪费。那么针对这种状况,就须要咱们提供一种灵活的能够在线伸缩服务吞吐量的技术:即大促前临时加机器来支持突增的流量,大促后随时下线扩容机器,而整个过程不影响正常的搜索服务。
由于本文篇幅有限,在这里我只会着重介绍:实时性、高可用性在咱们产品中的一些技术实践。
在介绍咱们产品方案以前,首先介绍下业内常见的实时解决方案,见图1-1实时架构图:
图1-1
该方案通常是由:
基于该方案能够带来的最大的优点是内存索引能够合并到主索引,避免了索引碎片,从而能够屏蔽全量索引从新构建和保障搜索服务的性能稳定性。可是这种方案仍然会存在如下问题:
因此为了单纯追求系统某个指标值(如永远不须要作全量),而牺牲掉系统稳定性是得不偿失的。固然上述某些缘由可能在一些好的硬件配置机器下并不会暴露的特别明显,可是从技术架构的机器成本上考虑的话,上述设计方案就不是一种特别合适的方案。那么咱们产品平台便采起了一种更低成本更稳定的实时架构方案来解决上述问题,其主要思路:
基于上述的思路,我将着重在实时更新处理、实时索引体系两个方面来跟你们介绍下咱们产品。
大型分布式系统中故障很常见,设想一下,若是内存索引没有刷写,服务器就宕机了。内存中没有写于硬盘的数据就会丢失。因此咱们的分布式实时搜索产品应对的办法是在写内存索引以前先写入WAL(Write-Ahead Logging,预写式日志)。其写入流程以下:
如上所示,在修改内存索引元素以前,要确保与这一个修改相关的操做日志必需要刷入磁盘中。若是检索服务器宕机,没有从RamIndex刷写入Disk的数据将能够经过回放WAL来恢复。而这个过程并不须要人为参与,检索节点内部机制中有恢复流程来处理。
通常而言搜索系统是须要将WAL日志刷入磁盘才能够构建内存索引的,可是若是每一个事务都要求将日志当即刷入磁盘,系统的吞吐量将会不好。所以,对一致性要求很高的应用,须要当即刷入;相应地,对一致性要求不高的应用,能够考虑不要求当即刷入,首先将WAL日志缓存到内存缓存区中,按期刷入磁盘。可是这种作法有一个问题,若是搜索应用系统意外故障,可能丢失最后一部分更新操做。
批提交(Group Commit,如图1-2批处理流程图)技术是一种有效的优化手段。WAL日志首先写入到系统内容缓存区中:
当知足以上两个条件中的某一个时,将日志缓存区中多个事务的操做一次性刷入磁盘,接着一次性将多个事务的修改操做逐个返回客户端操做结果。批提交技术保证了WAL日志成功刷入磁盘后,才返回操做结果保障数据的不丢失,虽然牺牲了写事务延时,但大大提升了系统吞吐量。
图1-2
考虑数据写入须要实时可查,那么更新的数据都是在内存索引中,那么可能出现一些问题:
故障恢复时须要回放全部WAL,效率较低。若是WAL超过100GB,那么,故障恢复时间根本没法接受。另外内存有限,内存索引须要达到阀值后转储到磁盘。因此,咱们须要在内存索引转储到磁盘的时候,记录checkpoint时刻的日志回放点,之后故障恢复只须要回放checkpoint时刻日志以后的WAL日志,如图1-3检查点方案流程图所示:
图1-3
当机器发送重启,只须要从新加载subindexA、subindexB、subindexC的索引,并重放checkpointC以后的WAL日志,变可以让数据恢复到宕机前一致。
图1-4
根据图1-4实时方案架构图咱们详细说明下实时模式实现流程:
前面咱们说到内存索引一旦达到阀值,将被刷入到磁盘,那么磁盘将会存在不少相似index_0、index_一、index2,index_3的索引碎片。若是不对这些索引碎片进行合并,那么随着这些索引碎片的增长,会致使搜索服务性能下降。因此咱们的产品对索引碎片采起了一种合并策略对其进行按期合并。
图1-5
如图1-5子索引合并流程图所示,内存索引刷入磁盘,将会依次递增的生成index_0,index_1,index_2的磁盘索引碎片。假设当前的合并因子是2,当合并管理器发现存在2个大小一致索引index_0,index_1的时候,变会触发合并操做:index_0和index_1合并成index_3,合并过程当中index_0、index_1依然提供正常服务,当合并操做成功完成,即index_3生成完毕,并对外提供服务。接下来将index_0和index_1的资源引用计数减1,即当基于index_0、index1的查询访问线程结束时,index_0,index_1的资源引用计数为0、索引将正常关闭,这样一个索引碎片合并操做正常结束。可是若是合并过程出现宕机或者异常状况,即当前合并事务未正常结束,那么整个合并过程将会回滚,即index_3被清理,index_0,index_1正常提供服务。固然若是内存索引继续刷到磁盘生成了index_四、index_5,经过合并策略生成了index_6,这个时候发现index_3和index_6又知足了合并条件,那么index_3和index_6又会合并生成index_7。因此经过这种合并策略,小索引碎片逐步会被合并成大索引碎片,可是若是索引碎片越大,那么带来的合并代价也越大,咱们须要设置一个合并阀值,凡是索引碎片达到指定文件大小阀值后,将不会进一步再参与合并,这样就很好的屏蔽了大索引碎片合并代价过大的问题。
由于前面说到咱们产生索引碎片,而这些索引碎片即便进行了碎片合并而减小碎片数,可是一旦当碎片达到必定大小后就不适合继续进行合并,不然合并代价很大,因此咱们没法避免的会由于碎片问题而致使更新实时性和查询QPS性能损耗问题。因此咱们的解决的办法就是经过一段时间对具体业务所有源数据进行一次构建全量索引DUMP工做,用构建好的新的全量主索引去替换原来老的主索引和磁盘索引,从而让实时更新、搜索服务性能恢复到最佳。
阿里的业务数据规模都很庞大,动辄就上10亿到百亿,那么咱们若是使用Solr原生的基于检索服务节点的索引构建模式会带来2个很大问题:
因此基于上述缘由咱们的搜索平台实现一个分布式全量索引任务调度框架来解决搜索业务全量索引构建的问题。
图1-6
如图1-6 DUMP中心架构图所示简单描述下一个业务全量索引构建的流程:
那么经过这种离线的分布式索引构建中心具体为搜索业务带来什么呢,主要在如下几个方面体现:
咱们产品在solr和Lucene上作了不少优化来适应一些业务的需求,本文篇幅有限,因此在这里我主要挑出一个比较有表明性的优化实践:Cache改造。
用过solr的同窗们都知道全部的Cache都是由SolrIndexSearcher来管理的,如图1-7 Searcher结构图所示:
图1-7
而在咱们的实时模式下须要让更新的数据实时可见,那么必须近实时的用新的SolrIndexSearcher-new去替换SolrIndexSearcher-old。(如图1-7)而这样实时的替换 也就引起以下问题:
因此基于如上的问题,终搜产品从新设计了一些Cache,将Cache的管理由SolrIndexSearcher迁移到IndexReader层中来,如图1-8 Cache结构图所示:
图1-8
首先,先阐述下咱们这种优化思路的前置条件,前文中提到咱们内存索引会直接刷磁盘而不用合并到主索引中,这样在磁盘存在的主索引、子索引对应的内存视图对象IndexReader在任什么时候候都不须要从新打开,而以IndexReader管理的Cache一旦建立后将不会被失效,而须要涉及到预加载Cache的过程只是在刷入磁盘或者系统从新启动过程当中一次将配置涉及到的Cache都预加载到内存中,那么以前存在的频繁失效致使GC、预加载慢引发实时性的若干问题都将不复存在。
因此经过将Cache从Searcher层迁移到IndexReader层的设计使得实时模式下的引擎在复杂的统计查询下性能也能获得很好的保证。
本文中咱们深刻的探讨了一种高稳定性实时搜索引擎系统实践,这些实践内容也依托于咱们的产品服务于阿里众多业务线。而目前咱们的产品搜索服务集群已经将近700台,接入业务范围也涵盖整个阿里集团。而这些业务特别是在数据量和访问量的成倍增加的状况下,咱们产品更加须要关注
归根结底其实这些要求是对搜索服务系统的易扩展提出了更高的要求,即如何提供一种无缝的在线扩容方案达到搜索服务吞吐量无上限的目标,而这个目标也正是咱们产品目前正在重点关注的方向,而关于这块的内容但愿有机会在新的文章中跟你们作深刻探讨。
柳明(花名:洪震),阿里技术专家,阿里一站式搜索服务平台TSearcher的负责人。目前关注于分布式、高性能、高稳定性的搜索服务领域。