分享

基于lucene的SOLR系统架构说明

 niefeng2011 2014-02-12

使用Solr作为lucene的服务端。
目前服务器上使用了master/slave的架构来部署solr服务器,以jetty作为web container。

暂时需要完全自己手动建立索引:
具体的servlet container的各种配置,可以参见其wiki,比较具体。
客户端推荐使用solrj,也可以在wiki里边找到相关文档。 http://wiki./solr/FrontPage

目前测试的结果是百万级的数据,普通索引的搜索都能达到毫秒级,个位或者两位数,主要的消耗在建立索引上,Lucene建立索引是采用删除然后添加的方式,所以没有办法增量的添加索引,也没有部分修改文档内容,一切都要全新建立。
理想中的最终架构如下:

  • 做Master&Slave,读写分离
  • 对slave做Distributed Search,实现负载均衡
  • 对单个solr instance启用Multicore,在集中的索引服务器上处理多个应用的不同索引。
  • Solrj使用,用来在程序里边实现客户端的各种操作(已经集成到utils工程里,有例子可参考)

Master&Slave

为了实现读写分离,solr支持master/slave模式,master负责建立索引,并同步到slave索引服务器,而slave用作查询。

读写分离最重要的配置就是对索引进行同步,当主索引更新后,能够自动同步到从服务器。
Solr支持两种索引同步的技术:

  • Collection
  • 对于可以进行hard links修改的操作系统,可以通过ssh/rsync进行同步。
  • 优点:不需要在应用程序层次运行,使用脚本进行远程同步,与操作系统结合紧密,可能效率比较快。
  • 缺点:对操作系统依赖,需要能够建立快照(snapshot,一种hard link),同时在配置的时候需要external scripts支持,同步的时候要通过系统验证。
  • Replication
  • 在比较新的版本后才支持的,一种java实现的同步机制。
  • 优点:跨平台,与操作系统无关,使用HTTP协议进行索引数据的同步,配置简单,只要在主从服务器的solrconfig.xml里边增加一个requesthandler 名字为replication
  • 缺点:可能效率不会太高。未知
  • 目前当前系统采用replication作为索引同步。
  • 在此基础上,使用了solr的repeater技术,能够对多个slave服务器进行复制,配置简单,只要将一台机器的replication配置为既是master又是slave就可以了。主要是为了避免多个slave服务器都从一个remote master服务器获取数据,占用大量带宽,所以,我们将一个slave服务变为repeater.
  • solr比较需要内存,尽量分配大一些,否则可能出现,get lockType time out等等奇怪的现象,还有尽量显示声明index的lockType。

Distributed

分布式搜索,将大索引分成相对小的索引,通过分布式搜索,然后合并结果,提高速度,应用于索引文件太大的情况。
主要分为分布式插入索引以及查询两个方面。

  • Distributed Index
  • 将建立以及更新索引的请求hash到不同的服务器上,一般可以采用uniqueID.hashCode()%n的方式,n为最终索引服务器的数量。
  • 可以进化为Solr Cloud,以集群的方式提供索引服务。
  • Distributed Search
  • 针对两种情况,一种是索引已经做了分片,另外就是每个服务器上都是完整的索引文件,只是为了更高的可靠性或者容错。
  • 简单的分布式查询不需要做特别的配置,只需要在查询的时候使用shard参数,将查询请求分发到不同的shard,然后再将请求合并即可。
  • 如果需要让服务器在接受到查询请求后自动使用shards分发,需要修改默认的SearchHandler,在默认的参数列表里边增加shard.qt和shards参数
  • 同时在那些被做为shards检索的服务器里边,除了也需要跟主查询服务器一样有默认的shards参数,还需要增加新的SearchHandler,名字为shard,用来处理shard查询请求。
  • 在索引文件很大的情况不推荐shards搜索,这样服务器会向每个shard服务器发送两次请求,先根据ID分,然后发送查询请求,最后还要负责合并查询结果。
  • 分布式查询根主从的架构不冲突,可以并存。

Multicore

多核可以实现在一个solr instance里边处理多个应用的不同的索引,不需要通过启动多个服务器来处理不同的索引。
不推荐多个core操作一个索引文件。
这样的话反而不如集中配置一个单独的core来操作数据更好,效率会慢。

Solrj

两种调用方式,大体就是集中式或者嵌入式。

  • 集中式
  • 只有一组索引服务器,对不同的应用提供服务,建立不同作用域的索引,统一架构,统一管理。
  • 一般通过HTTP协议或者其他等remote方式访问服务,读写。
  • 嵌入式
  • 每个服务启动自己的索引服务器,作为当前应用服务的一部分运行,不需要建立http连接,直接访问。
  • 效率稍高,但不利于统一管理,长期弊大于利。
  • 当前架构使用集中式,通过Multicore可以分别对不同的索引提供服务,并能够根据具体需要,对不同的core启动主从,或者分布式索引等
  • 后期应用数量以及索引数量多了之后,比较好处理。
  • 集中式索引服务的调用方式:
  • CommonsHttpSolrServer solrCore = new CommonsHttpSolrServer (url);
  • UpdateResponse response = solrCore.addBean (New SolrAccountInfo());//该类通过annotation的方式可以与索引的schema文件相对应,这样就可以直接对bean粒度的对象进行曾删改,当然也可以自己组织document结构(xml/json)来进行各种操作。
  • SolrQuery query = new SolrQuery ("weiboAccountID:1806619535");
  • SolrQuery具有一系列的方法,比如排序,分组,数量限制,偏移值,统计等功能,以下简单展示。
  • query.setSortField ("fansCount", ORDER.desc); //排序
  • query.setFacet (true);query.addFacetField ("location");//分组搜索,并且默认按照location统计结果倒序排列,如果需要反向排序,需要:query.setFacetSort ("location");
  • query.setFacetLimit (20);//分组搜索结果限制,默认是根据数量倒序排列
  • query.setRows (0);//如果只需要分组排列,就不需要一般的结果了,设为0
  • QueryResponse qr = solrCore.query (query); //最终执行搜索
  • 取得搜索结果
  • qr.getBeans (SolrAccountInfo.class);
  • 取得分组统计结果
  • List<Count> counts = qr.getFacetField ("location").getValues ();
  • 每个Count对象,包含了一个key,一个value,比如北京(12),南京(10)等等,有对应的接口读取。

UpdateResponse response = solrCore.deleteById ("wlsailor|tencent"); //不用解释,看名字。。。
删除还可以根据查询语句来直接批量删除。
solrCore.commit (); //没有配置autocommit的情况下,需要手动执行该方法,所有改变才能生效
solrCore.roleback(); //回滚

 

当前每个solr实例都建了两个索引,以备后期扩展。
以后会架设多个Slave服务器,通过shard将请求分发到不同的索引服务,以目前的结构,每个slave服务器都保存了完整的索引,容错能力较强,
当索引文件太大需要分片的时候,则可能需要做分布式的索引,在索引写入的时候就hash到不同的服务。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多