Botposter.com集群ETCD2.3.7升级至3.0实录

7月1日,为庆祝我党生日,ETCD隆重发布了3.0版本。Botposter.com也在第一时间对集群进行了升级。本文是升级过程的记录与总结(文中假设读者已经使用或测试过ETCD V2,若有不妥请见谅)。node

Botposet.com是一款与HubSpot相似的营销自动化SAAS产品,所有使用golang开发。git

说明

在Botposter.com中,ETCD主要用于如下两个职责:github

  • master选举golang

  • 集群信息保存服务器

早期曾使用ETCD的TTL来实现master心跳检测,因为性能缘由在Botposter.com上个月的重构中取消了这种用法。这也刚好简化了升级难度,由于ETCD v3对TTL有重大改动。架构

准备

资料准备

迁移工做的主要参考如下两篇资料:mvc

https://github.com/coreos/etcd/blob/master/Documentation/op-guide/v2-migration.mdtcp

https://github.com/coreos/etcd/blob/master/Documentation/upgrades/upgrade_3_0.md分布式

测试环境

开始升级前须要搭建测试环境,过程很是简单,这一点ETCD作得很是好,V3版本与V2版本不管从安装方式和配置参数彻底一致。ide

安装参考连接:https://github.com/coreos/etcd/releases

配置参考连接:https://github.com/coreos/etcd/blob/master/Documentation/op-guide/clustering.md

配置好测试环境后,使用etcdctl测试ETCD V3是否能够正常使用。 这里须要注意,必定不要忘记在环境变量中加入ETCDCTL_API=3 。不然在操做V3时,不管使用SET,GET都没有任何数据返回,也没有错误返回。建议ETCD V3能够提供错误提示。我在这里耽误了一些时间,由于想固然的觉得,使用ETCD V3和ETCDCTL V3是默认匹配的。
ETCDCTL的文档连接:https://github.com/coreos/etcd/blob/master/etcdctl/README.md#migrate-options

注意:我在第一次使用etcdctl member list命令(全部的命令都会出错,此处以member list举例)的时候,返回下面错误代码:

grpc: addrConn.resetTransport failed to create client transport: connection error: desc = "transport: dial tcp 127.0.0.1:22379: getsockopt: connection refused"; Reconnecting to {"127.0.0.1:22379" <nil>}

单独运行etcdctl命令,会返回etcdctl的使用帮助,其中有一行:

--endpoints=[127.0.0.1:2379,127.0.0.1:22379,127.0.0.1:32379]    gRPC endpoints

原来默认gRPC的endpoints有三个,解决这个问题的已知办法有两个:
一是在etcdctl命令行中加入--endpoints参数

etcdctl --endpoints=127.0.0.1:2379 member list

二是在etcd启动参数中增长其它端口

-listen-client-urls http://127.0.0.1:2379,http://127.0.0.1:22379,http://127.0.0.1:32379

在Botposter.com中暂时使用第二种方法。由于迁移时间有限,没有继续查看是否能够修改gRPC的默认--endpoints。

API V2与V3区别

  • 事务:ETCD V3提供了多键条件事务(multi-key conditional transactions),应用各类须要使用事务代替原来的Compare-And-Swap操做。

  • 平键空间(Flat key space):ETCD V3再也不使用目录结构,只保留键。例如:"/a/b/c/"是一个键,而不是目录。V3中提供了前缀查询,来获取符合前缀条件的全部键值,这变向实现了V2中查询一个目录下全部子目录和节点的功能。

  • 简洁的响应:像DELETE这类操做成功后将再也不返回操做前的值。若是但愿得到删除前的值,可使用事务,来实现一个原子操做,先获取键值,而后再删除。

  • 租约:租约代替了V2中的TTL实现,TTL绑定到一个租约上,键再附加到这个租约上。当TTL过时时,租约将被销毁,同时附加到这个租约上的键也被删除。

与Botposter.com有关的改动只有平键空间,由于系统中使用ETCD目录结构保存了master,node和task的所有信息。
从官方文档的表述看,事务和租约值得测试并用于优化V2的用法。

客户端代码升级

平键空间

将原代码中包含如下代码的部分都修改成

&client.GetOptions{Recursive: true}

都修改成

clientv3.WithPrefix()

数据类型

在V2版本中,resp.Node.ModifiedIndex的数据类型为uint64,V3中revision为int64。
由于在Botposter.com使用了resp.Node.ModifiedIndex做为全局序列标识,因此,须要将原系统中的数据类型修改成int64。

Compare-And-Swap

在V2的一种典型用法就是Compare-And-Swap,在Botposter.com中也使用这种方法实现了分布式锁,实现方法是在SET操做时增长下面的操做:

&client.SetOptions{PrevExist: "false"})

即,只有当前key不存在时,才能写入成功。

在V3中,改成由事务实现。具体代码以下:

kvc := clientv3.NewKV(&cli)
r, _ := kvc.Txn(context.Background()).
    If(clientv3.Compare(clientv3.CreateRevision(key), "=", 0)).
    Then(clientv3.OpPut(key, v)).
    Commit()

Txn的具体用法参考:https://godoc.org/github.com/coreos/etcd/clientv3#example-KV--Txn

Node

在V2中,get操做response回来的value保存在response.node.value,若是是一个directory,返回的结果集保存在response.node.nodes中。

V3作了大幅修改,由于V3中再也不有directory,全部的key都是flat key,因此,全部get操做的返回值都保存在GetResponse.Kvs(数据类型是[]*mvccpb.KeyValue)中。并且V2中,keynotfound等错误在V3中都再也不保留,V3中,当查询的key不存在时,GetResponse.Count为0,len(GetResponse.Kvs)也为0,Get操做返回的error为nil。因此在V2中的代码如

response.Node.Value

须要改成

GetResponse.Kvs[0].Value

另外值得注意的是,V3中的key和value的返回值都是[]byte类型,这能够减小不少string与[]byte的数据类型转换操做。

ETCD升级

ETCD升级很简单,先按照安装参考连接:https://github.com/coreos/etcd/releases ,下载并解压文件。
由于Bostposter.com集群有自动恢复机制,因此使用离线升级的方式,在全部服务器运行脚本:

service etcd stop
cp etcd /usr/local/bin
service etcd start

ETCD的全部启动参数都不须要修改,升级时间不超过1秒。
ETCD升级后,升级集群服务的代码,只有在升级流程容器时须要重启2000多个流程,所有恢复时间大概在1分钟左右。

至此,升级工做所有完成。对系统功能和集群都作了测试,没有出现任何问题。

感觉

下面说说升级到ETCD V3后的感觉,时间有限没有作精确测试,没有数据支撑略显不够严谨。

首先,V3服务器端的内存比V2占用得更高,至少高50%。尤为是压力增大时,内存占用飙升得很快,压力减少后几分钟内存会释放出来。

其次,Client使用后必定要Close,由于在V2时,Botposter.com中使用了sync.pool来保存Client。当升级到V3后,操做频繁时池化的Client会占用很是多的内存,由于没有作具体测试,还不清楚一个Client占用多少内存。目前的解决办法是Client再也不池化,并且使用后当即Close。

第三,V3的API更加合理,直接的结果是代码量减小了,异常处理也变得更简单。

第四,从升级后的总体表现看,V3的性能比V2要不少。

总体来讲,在有条件的状况下,我建议升级至ETCD V3。时间仓促,若有笔误请你们及时指出,谢谢。

内容为做者原创,未经容许请勿转载,谢谢合做。


关于做者:
Jesse,目前在Joygenio工做,从事golang语言开发与架构设计。
正在开发维护的产品:www.botposter.com

相关文章
相关标签/搜索