声明:
本文转自我的个人博客,有兴趣的可以查看原文。
转发请注明来源。
背景
公司使用 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 完成后,将业务切到新集群。
- 全量 index:使用
es-hadoop
来做。 - 增量 index:在开始全量 index 前,监听
binlog
,将消息丢进NSQ
,停止消费对应channel
;当全量 index 完成后,开始消费该channel
,当消费完成后,索引重建完毕。
全量 index 和增量 index 都需要对业务相当了解,在写HQL和消费 NSQ
消息脚本时,可以寻求业务部门相助。
问题
- 全量 index 时,如果数据量太大,是可能造成写入失败的。在这种情况下,一是优化新建 index 性能,二是分批次新建 index。
- 全量 index 需要编写 HQL,增量 index 需要将 DB 数据变动写入 NSQ,还要写消费脚本,针对每个 index 都需要这两个脚本,如果 index 变动或者涉及到的数据来源发生变动就需要重新对应脚本,会比较繁杂,所以,还缺少高效的全量 index 和增量 index 方案,如果有好的方案,记得告诉我。
- 缺乏有效的测试方案,在整个 index 迁移过程中,主要采用抽样对比新老集群数据来测试,一定要仔细!
- 沟通,仔细、耐心。
失败的拆分方案
最后,提供一种失败的拆分方案,大家就不要尝试了,血的教训。
Elasticsearch 提供了 index shard allocation 功能,我们可以利用该功能对 Elasticsearch 集群进行逻辑拆分。比如,我们可以给每个 Elasticsearch 节点打上标签,然后将不同业务涉及的 index 指定到不同节点,这样,虽然还是一个物理集群,但是,从逻辑上来说,可以理解为几个集群。按理来说,如果某个 index 特别大,或者有慢查询,是不会影响其他业务线的 index 的。但是,该方案有个很严重的问题,当我们人为让 index 在一个集群内不同节点之间迁移时,集群为了均衡数据,其他 index 也会迁移,这样,集群内部网络带宽占用就会很高,而且,Elasticsearch 没有提供控制集群内部迁移速递的 API,此时,集群处于极不稳定状态,特别是整个集群的数据量大的时候。我们遇到过集群内部网络带宽用尽,集群节点间的心跳无法正常接收,从而造成脑裂,一度不停选举master,整个集群挂掉的情况。即使采用数据迁移完成,由于没有物理隔离,还是有整个集群挂掉的可能性的,所以,还是物理拆分吧。