ElasticSearch大版本升级踩坑记

作者: 采菊东篱下 | 来源:发表于2017-09-18 12:19 被阅读4490次

    大版本升级,从ES 2.1到ES5.5,两年的数据,每天15GB,5个节点,前后历时一个月左右。

    限制条件:

    1. 升级过程有新的数据不断进来,不能停止整个集群,否则会丢失数据。
    2. 没有额外的机器搭建一个全新的ES5集群,只有一个机器供缓冲使用。
    3. 一个临时的ES5节点cpu 8核,内存32GB,10T 磁盘,升级完成后需要释放掉这台机器。
    4. 很多线上的服务依赖于目前的ES2提供服务,线上服务不能中断。

    记录一下整个流程。

    首先是做决定到底是采用全集群方式升级还是平滑方式升级。

    升级方案选择

    全集群升级

    1.关闭shard分配,防止关闭一个节点后ES集群误认为node故障,在剩余节点上执行 shard 恢复,如果数据过多,可能会由于产生大量IO造成ES集群挂起。

    PUT _cluster/settings
    {
      "persistent": {
        "cluster.routing.allocation.enable": "none"
      }
    }
    

    2.执行同步刷新, 这样集群重新启动后shard恢复更快。

    POST _flush/synced
    
    

    3.关闭集群中所有的ES进程。

    4.安装ES5,并且修改配置文件,配置好data路径。不要直接指向2.x的路径,否则一旦升级失败,老数据无法恢复。

    5.配置好路径后将2.x的data目录copy到新的路径下。

    6.启动ES5 集群,等待集群状态变为green即可

    优点

    简单,速度快,一步到位

    缺点

    • 由于ES2.x到ES5.x内部结构变化较大,升级过程不可控,中间可能会有大坑或者升级失败
    • 目前ES存储的数据结构有需要改进的部分(比如某些字段类型,analyzed等),这样升级后还是原来的结构,后续可能还需要对数据进行reindex。

    Reindex 平滑升级

    这种升级方式其实就是对所有的数据做一次重新处理然后自己通过http接口重新写入到新的 ES5缓冲节点,然后再将原来的ES2的节点逐台加入的新的集群,之前的数据和配置都清空。

    程序大致流程

    ES2 -> scanner -> redis -> reindex -> ES5

    引入Redis作为中间缓冲的考虑:

    1. 数据量巨大,索引过程很难保证一次成功,基于scroll方式取数据无法保证顺序,所以一旦中途失败无法判断offset,为了不丢不重复,只能从头再来
    2. 需要对每一个doc进行特有字段的部分处理, Redis中缓存的是处理后的doc
    3. ES的查询速度和索引速度不一致,从ES2读取数据经过处理后写入ES5整个流水线耗时太长,容易网络超时失败

    升级方案踩坑记

    经过内部讨论决定采用平滑升级的方式。

    • 使用python将每天的数据从ES2->ES5,每天大概2000万条数据,使用官方的elasticsearch python库每次到几百万数据的时候就会出现连接超时,由于没有offset机制,所以只能删除从头再来。后来基于requests库自己封装scroll API来进行reindex,有时发现1000多万的时候scroll API就返回没有谁了,后来经过调试发现不能只是简单的根据hits的条数是否为0来判断数据是否全都读取完毕。这里官方文档中并没有提及,最终添加了好几个判断条件和错误处理,终于可以完整的读完所有数据,一条不差。

    • 中间引入了redis作为缓存,防止reindex程序中间挂了,从头再来。es2->redis->es5,由于读的速度远远大于写的速度,而且只有一台es5节点,所以需要开多个进程往es5中写。突然有一天发现es5挂掉了,查找原因,发现redis的内存已经占满了所有机器的内存,操作系统自动杀掉了es5节点。于是加入流控机制,一旦redis中的数据超过限制,那么读取程序需要挂起。

    • 数据全都写入到ES5的临时节点后,开始一台一台的升级ES2。之前在ES2的升级过程中通过yum安装ES时发现ES已经从5.5.1升级到了5.5.2,ES对于版本的控制非常严格,虽然可以同时正常的查询工作,但是之前的数据都是5.5.1版本,无法在5.5.2版本的node上写入数据,没办法,只能先升级原先的es5tmp节点到5.5.2版本,由于是小版本升级,直接yum update然后重新启动节点即可。

    • 数据的存储之前并没有采用LVM管理,所以添加一块磁盘,需要修改ES的配置文件,然后重新启动机器,这次升级顺便将所有的ES的数据盘配置为LVM方式。由于之前已经有一部分数据写入到了新加入的非LVM节点上,所以需要将其中的shards再写回到es5tmp临时节点,查看文档,发现使用cluster.routing.allocation.exclude._ip设置可以达到要求,设置完成后分片会自动写回到临时节点上。LVM磁盘配置好后,重新加入集群,使用cluster.routing.allocation.include._ip设置后发现并没有作用,经过尝试发现,必须cluster.routing.allocation.exclude._ip设置为空字符串,同时cluster.routing.allocation.include._ip也必须设置为空。等待所有的ES2的节点都加入集群后,将临时节点的ip设置到exclude中,这样所有的shards和副本都会自动转移到新的节点上。

    • 由于内存和资源限制,整个升级过程是每次打开一个月的index,所有的主分片都从临时节点转移后,再设置replica个数为1,等所有副本都完成后,close这个月的所有index,然后开始下一个月。这样整个过程只保留了当前最新的一个月的数据(供在线服务使用)和正在进行中的那个月的数据,整个集群压力较小。

    • 升级完成后安装Kibana,发现ES已经升级到5.6了,不想折腾ES的各个节点升级到5.6,所以通过yum安装5.5.2的Kibana。

    • 升级完成后http query的接口已经完全变了,所有之前依赖es2的查询接口都需要重写。

    • 所以的kibana和ES节点都监听内网地址,不安装x-pack,通过部署一个nginx的代理和简单的用户名密码认证来做简单的安全验证。使用cerebro(之前的kopf)来对集群的状态进行简单的监控和更新配置。

    • 中间还包括了logstash配置更新,kibana配置更新,ES->Hadoop的代码更新不再一一细说。

    知识点总结

    整个过程涉及到的知识点如下:

    1. python requests库使用。
    2. es scroll API使用。
    3. yum 安装特定版本软件包以及配置清华源。
    4. 阿里云系统盘镜像创建以及替换部署。
    5. lvm管理多个磁盘。
    6. systemctl 使用以及service配置文件。
    7. es index template 配置。
    8. nginx basic auth反向代理配置。
    9. es hadoop map reduce API使用。
    10. python redis 使用。
    11. Logstash,ES,Kibana 安装部署以及配置。

    相关文章

      网友评论

      • 73ef935177e4:后来经过调试发现不能只是简单的根据hits的条数是否为0来判断数据是否全都读取完毕。这里官方文档中并没有提及,最终添加了好几个判断条件和错误处理,终于可以完整的读完所有数据,一条不差。

        楼主,,都添加了那些判断??方便说一下吗?
        caster0x:@大胡桃夹子 非常感谢!最近在预研升级的事,这个问题很重要!
        73ef935177e4:@大胡桃夹子 好的,,谢谢,之前没有留意过。
        采菊东篱下:添加两个判断,一个是看返回的status是不是429,还有一个就是只有
        len(hits) == 0 and shards_successful == shards_total
        这两个同时满足才能算全部scroll完毕,如果只判断hits的个数为0,那么超过1000万的时候基本都不会成功。不知道是我的es2集群设置的有问题还是在连续的大查询压力下es本身的问题。
      • 采菊东篱下:ES版本迭代太快了,跟不上节奏

      本文标题:ElasticSearch大版本升级踩坑记

      本文链接:https://www.haomeiwen.com/subject/rwbvsxtx.html