不停服务 ElasticSearch 集群物理拆分

February 18, 2016
作者:星爷
出处:http://lxWei.github.io/posts/Elasticsearch%E9%9B%86%E7%BE%A4%E7%89%A9%E7%90%86%E6%8B%86%E5%88%86.html
声明:转载请注明作者及出处。

背景

公司使用 Elasticsearch 来做全文检索和大数据量的结构化查询,由于历史包袱,只有一个 Elasticsearch 集群,各个业务线都随便使用该集群,没有有效的管理和制约,比较混乱。而且,随着数据量的暴增,开始出现性能瓶颈,比如一个慢查询拖慢整个集群状态,甚至搞挂整个集群,所以开始着手对集群进行系统改造。

老系统

下图是老系统:

老系统架构

可以看到,系统就一个 Elasticsearch 集群,所有 index 公用一个集群,当集群出现问题时,会影响所有 index,甚至导致全站挂掉。其次,一个集群涉及到的 index 太多,涉及的业务线太多,当我们需要对集群进行改造、升级时,会带来极大挑战。

基于此,需要将 Elasticsearch 物理拆分成多个集群。

新系统

新系统如下图所示,重构时顺便做了其他修改,但跟本文无关,所以先隐掉。

新系统架构

客户端请求,经过中间的处理,转发到不同的 Elasticsearch 集群,各个集群物理隔离,这样,即使集群挂了,也只影响一小部分。

行动

拆分策略

确定要物理拆分集群后,首先要确定的是按照什么标准拆分,最重要的是哪些 index 应该放在一个集群。

首先想的是根据访问量来划分,保证每个集群的访问量基本相等。后来考虑到不同 index 的访问量是变化的,不可能每个集群的访问量都一直一样,而且,对于出现了访问量激增的情况下,我们可以通过增加机器来改善,所以,该方案没有意义。

然后,考虑根据优先级划分,将 index 分为高、中、低三个优先级,使每个优先级都分散在不同集群,这样,即使某个集群挂掉,也不至于所有高优先级的 index 涉及的业务挂掉。该方案也没有实施,一是优先级并不好确定,其次,优先级会动态变化,同时,会有index被删除,也会有index加入。

最后,我们按照业务线划分,同一业务线的 index 部署在同一集群,这样,便于维护。

index 迁移

确定了拆分策略,到落实阶段了,问题便成了怎么迁移,我们分两种方案迁移。

写入少且量小的 index

对于这种index,比如有的 index 就百万、千万级数据量,同时,每天就写入一次,这种 index,我们采用的策略是直接从老集群把数据迁移到新集群,现在有不少工具可以实现这种功能,比如 elasticdump,就可以一行命令把 index 给迁移到新集群。

写入多或量大的 index

对于这种 index,我们采用重建 index 的方式,因为我们不可能停止服务,所以,我们采用的是全量 index + 增量 index 的方式,当新集群上 index 完成后,将业务切到新集群。

  1. 全量 index:使用 es-hadoop 来做。
  2. 增量 index:在开始全量 index 前,监听 binlog,将消息丢进 NSQ,停止消费对应channel;当全量 index 完成后,开始消费该channel,当消费完成后,索引重建完毕。

全量 index 和增量 index 都需要对业务相当了解,在写HQL和消费 NSQ 消息脚本时,可以寻求业务部门相助。

问题

  1. 全量 index 时,如果数据量太大,是可能造成写入失败的。在这种情况下,一是优化新建 index 性能,二是分批次新建 index。
  2. 全量 index 需要编写 HQL,增量 index 需要将 DB 数据变动写入 NSQ,还要写消费脚本,针对每个 index 都需要这两个脚本,如果 index 变动或者涉及到的数据来源发生变动就需要重新对应脚本,会比较繁杂,所以,还缺少高效的全量 index 和增量 index 方案,如果有好的方案,记得告诉我。
  3. 缺乏有效的测试方案,在整个 index 迁移过程中,主要采用抽样对比新老集群数据来测试,一定要仔细!
  4. 沟通,仔细、耐心。

失败的拆分方案

最后,提供一种失败的拆分方案,大家就不要尝试了,血的教训。

Elasticsearch 提供了 index shard allocation 功能,我们可以利用该功能对 Elasticsearch 集群进行逻辑拆分。比如,我们可以给每个 Elasticsearch 节点打上标签,然后将不同业务涉及的 index 指定到不同节点,这样,虽然还是一个物理集群,但是,从逻辑上来说,可以理解为几个集群。按理来说,如果某个 index 特别大,或者有慢查询,是不会影响其他业务线的 index 的。但是,该方案有个很严重的问题,当我们人为让 index 在一个集群内不同节点之间迁移时,集群为了均衡数据,其他 index 也会迁移,这样,集群内部网络带宽占用就会很高,而且,Elasticsearch 没有提供控制集群内部迁移速递的 API,此时,集群处于极不稳定状态,特别是整个集群的数据量大的时候。我们遇到过集群内部网络带宽用尽,集群节点间的心跳无法正常接收,从而造成脑裂,一度不停选举master,整个集群挂掉的情况。即使采用数据迁移完成,由于没有物理隔离,还是有整个集群挂掉的可能性的,所以,还是物理拆分吧。