通过上一篇的几个优化方案,我们的索引速度其实已经能得到很大的提升了,从最初的平均每台机器7000TPS/S,大概能到2.5WTPS/S。但是这个速度远远还达不到我们的需求,最关键的时候随着节点数增加并不能速度并不能线性增加,然后又做了许多其他方面的尝试,其中路由方式是比较大的一个方向,本篇将重点介绍这一方案。
前面介绍了solr在创建索引库的时候可以指定多个shard来同时索引数据,那么问题来了,文档是通过何种规则讲数据负载均衡到每个分片之上的呢,solr提供了两种路由方式:哈希路由(composite),指定路由(implict)。其中哈希路由,创建collection的时候需要明确指定shard数量,后期shard可以进行分裂(split)操作,但是不能增加或者删除shard。solr默认的就是采用这种路由模式,利用计算文档ID的哈希值,来判断将此文档索引到哪个分片之上,这样做的好处是可以使得每个shard上数据负载均衡,但在追求极限速度之下,会浪费掉不少时间。第一,计算hash值需要耗时;第二,数据在各个分片之间迁徙分发需要消耗网络以及内存资源。所以我们选择了直接路由模式。工作模式如下图,透过collection,直接指定分片载入数据:
直接路由模式顾名思义,指定索引具体落在路由到哪个shard,该模式同样在创建collection时需要具体指定shard数量,后期可以动态追加分片以及删除分片,但是如果一个分片过大时不能进行分裂的。需要注意的是:
1)索引要特殊方式通过以下URL新建
http://xxxx.xxxx.xxx.xxx:port/solr/admin/collections?action=CREATE&name=implicit1&shards=shard1,shard2,shard3&router.name=implicit
2)在solr4.x版本中通过更改schemal.xml在5.0以上更改managed-schema文件添加以下字段定义:
<field name="_route_" type="string"/>
3)利用SolrJ添加文档的时候需要加入以下字段:
doc.addField("_route_","shard_x")
通过直接路由的模式,我们可以每个线程操作一个shard,如果物理机上有多块硬盘,就可以每个硬盘上部署一个solr节点,这样多块硬盘之间的索引性能是互不影响的,我们就可以随着节点数的增加而线性增长。带来的问题就是可能会导致数据分布不均,而使某个分片过载,不过我们系统中数据中间件使用的是apache kafka,一个topic设置了多个partiton,在这一层报文已经做了一次均衡路由,每个partiton消费出来的数据负责写一个solr的shard,所以不用担心这个问题,后面有机会介绍下kafka消息中间件。
通过具体测试,指定路由速度相比于哈希路由,在单节点下速度并没有提升,但是在多节点下,集群的吞吐量有明显的提升,可以真正做到水平拓展,对于物理机数量充足的情况下,可以满足每天海量索引的更新。下一篇将继续介绍如何利用solrj客户端来提高单节点的速度,这样整个集群的吞吐量又能进一步提高。