缘由

因为consul都已经0.8.0了,还是没有动态修改tags的功能(这是一个老生常谈的问题了,不过consul很坚持,哪怕PR都已经做好了,只等着动动拇指了,也还是不行)参见修订,通过api去做的话,又会超级繁琐和比较没办法,所以做了一个工具去处理tags的添加、删除;进一步的,提供一个翻转的功能。

consul service能够带有一组tags,consul的编程接口和API都能够通过tags来筛选services,因此我们通常会将一个服务的实例集群的角色也提供在tags中,例如 role=master,type=disk,rw=readwrite,等等。这时候 LoadBalancer 就能够通过筛选tags来获得可用列表。

例如向 redis 服务发出 rw=readwrite 筛选条件后得到的可用实例表经过 LoadBalancer 处理后对业务层可用,这样业务层就可以写入键值;反过来筛选 rw=readonly 得到的实例表,业务层就可以读取键值,通过 LoadBalancer 附着一个 ReadWriteSpliiter 的架构设计,业务层实质上可以透明地获得负载均衡后的 redis 服务,并且该服务内部隐含地完成了读写分离的 devops 架构。

类似的,DB也可以采用这样的设计方案。

话说回来,也不必鄙视consul坚决不提供tags修改功能或者在service definition中附着一个子K/V,两者各有各的问题,而集中使用单一一个全局的K/V事实上也是相当正确的做法。然而不符合直觉啊,为什么大家总是要想reload一个新tag,而不愿意使用K/V呢,甚至愿意放弃分布锁也要改tag?这是个很严肃的问题。

key+问题

无论如何,回到我们描述的那种策略中,那么这里就存在一个问题了,consul很难动态修改tags,这样的架构设计就难以落地了。

consul确实准许重新注册相同id的实例并能够在这个场景中正确的设置到新tags集合。但那是针对string,而不是key=value。

这时要简单地把key-value应用进去就不那么便利了。不过还是可以有方法。

一种方法是对该设计进行一点点微调,采用 consul 的 KV Store 来保存服务实例的角色,并在高可用切换场景下更新该key。

这个方法成本低廉,而且实际上利用ZooKeeper,Etcd来做服务发现的案子,谁又不是这么做的呢?所谓的成本低廉,是因为 consul v0.6+ 直接提供命令行操作:

consul kv put resources/test-redis/leader 10.0.13.129:6379

毋庸置疑,这也是consul乃至多数情况下所推荐的正确的方法,借助K/V的隐含特性,你能够在大规模分布式场景下(异地数据中心)仍能保证集群的新状态能够在足够快的正确地被更新。

第二种方法呢,就是 consul-tags 这个工具的秀场了。

consul-tags 工具

首先要声明的是,修改tags的设计方案没有事务一致性的保证。不要在诸如订票,电商等关键且高频交易场景中使用本工具和类似的设计方案,它们需要支持分布式锁的K/V Store和事务性的状态切换。

其次我不得不说的是,这种方法在非实时交易的场景中还是足够的安全的了。

consul-tags ms --name test-redis toggle --addr 10.0.13.129:6379 --set role=master --reset role=slave

这条指令能够扫描 test-redis 这个服务的全部实例,并将他们的 tags 复位到 role=slave 的状态,然后对新的 leader 19.9.13.129:6379 所对应的服务实例,则将其tags中 role=xxx 的那一条翻转为 role=master。

consul-tags会将一切麻烦都解决掉,会去检索每个实例的每条tag,找到那些role=xxx的,去掉,然后增加一条 role=master 的 tag,保证不会留下什么 role=slave,role=master,role=slave 的麻烦。

如果你们的tags有自己的规范,并不是“key=value”的格式,也没有关系。例如对于 “key:value” 格式的情况下,上面的命令可以改写为:

consul-tags ms --name test-redis toggle ---delim=: --addr 10.0.13.129:6379 --set role:master --reset role:slave

同时翻转多个tags也是可以的:

consul-tags ms --name test-rmq toggle --addr 10.0.25.36:5672 --set role=master,type=ram --reset role=slave,type=disk

当然,consul-tags 也有常规的tags管理接口:

添加和删除tags

consul-tags ms --name test-redis tags --add tag1,tag2,tag3

consul-tags ms --name test-redis tags --add tag1 --add tag2 --add tag3

consul-tags ms --name test-redis tags --rm tag1,tag2,tag3

添加删除的参数提供方式的相同的,可以用逗号(,)分隔多个tags,也可以多次以–add提供。

列出tags

consul-tags ms --name test-redis tags ls

清空tags

清空功能具有第一优先级。也就是说,同时给出 –clear, –add, –rm 时,首先会执行 –clear,其次执行 –rm,最后才会执行 –add。如果你需要不同的修改顺序,当前只能多次调用 consul-tags。

consul-tags ms --name test-redis tags --clear

通过 service id 修改某个服务的某个特定实例

consul-tags ms --id test-redis-1 tags ls

consul-tags 命令行参数

请通过 consul-tags –help, consul-tags ms –help 来获取可用的 sub-commands, options。

全局选项

   --addr HOST[:PORT], -a HOST[:PORT]  Consul address and port: HOST[:PORT] (No leading 'http(s)://') (default: "consul.ops.local") [$CONSUL_ADDR]
   --port value, -p value              Consul port (default: 8500) [$CONSUL_PORT]
   --prefix value                      Root key prefix (default: "/") [$CONSUL_PREFIX]
   --cacert value, -r value            Client CA cert [$CONSUL_CA_CERT]
   --cert value, -t value              Client cert [$CONSUL_CERT]
   --scheme value, -s value            Consul connection scheme (HTTP or HTTPS) (default: "http") [$CONSUL_SCHEME]
   --insecure, -K                      Skip TLS host verification (default: false) [$CONSUL_INSECURE]
   --username value, -U value          HTTP Basic auth user [$CONSUL_USER]
   --password value, -P value          HTTP Basic auth password [$CONSUL_PASS]
   --key value, -Y value               Client key [$CONSUL_KEY]
   --help, -h                          show help (default: false)
   --init-completion value             generate completion code. Value must be 'bash' or 'zsh'
   --version, -v                       print the version (default: false)

何处取得 consul-tags ?

请移步:

https://github.com/hedzr/consul-tags

给谁用的?

  • 做日常运维的人
  • 尤其是做 DevOps 和 NoOps 的人

版权

  • MIT的,你喜欢就好。

最后

  1. 源代码并未整理,所以可能有点难看。
  2. kv操作部分,是移植的 colebrumley/consul-kv-backup 的源码,因为大家使用了不同的 cli 库的缘故,直接引用他的代码就不行了,只好移植进来做了修改。
  3. consul-tags 其实是我的私有项目的一部分,这就是你看到它有点点怪的原因。
  4. consul-tags 是有用的。我自己在功能上表示是满意的。
  5. 实际用起来好像没有bug,不过我并不做此承诺,当然我觉得可能是没问题的。欢迎发issue。
  6. 因为 acl,token,ssl 部分我并没有建立规划,所以 consul-tags 中的该部分连接性参数也并没有充分测试,不敢保证木有bug。
  7. 改写代码,引入新的实用小刀到里面也是在计划中的,不过到时候或许是另一个工具集了。

PS:

为防误导,复查一遍和加入了一些文字。

修订:

  1. consul 0.6.4 开始,API 新增了 /query 以支持 Prepared Query,这里面既可以修改 Tags,也可以修改 NodeMeta。不过,对于Tags它不支持视为Key-Value来修改,这倒是显而易见的,NodeMeta才是对Key-Value的妥协。
  2. consul-tags现在发了 v0.3.2 版本,主要是支持NodeMeta的修改,方式和consul-tags对Tags的修改模式一样,只是尾随一个 –meta 或者 –both 开关就行了。NodeMeta实际上是附着于每个consul node上的,所以这是个临时性的功能。
  3. 之前理解错误,NodeMeta并不附着于Service Instance之上,因此对于主从切换、读写分离等场景,传统的Tags方案还是继续可用,又或者还是使用K/V中心。