灰度发布

背景

应用代码修改的时候,以往是只能kill掉重新提交,这会带来比较大的数据抖动。另一方面,有可能用户只修改了一小部分代码,比如某个component的代码, 这种情况下,可能只想重启这个component。

在这样的背景下,我们开发了灰度发布功能。

功能介绍

灰度发布支持以下功能:

  1. 指定worker列表重启

  2. 指定component重启

  3. 指定component,并指定worker数,重启这个component下的指定数量的worker

  4. 指定worker数,由框架随机选择worker进行重启

  5. 支持回滚

限制

使用此功能前请先了解相关限制:

  1. 需要将TM设置为单独的worker,即topology.master.single.worker必须设置为true。

  2. 修改代码前后,消息流不能有大的变化。即,不能引入一种新的grouping或者新的fields、stream等,必须保证worker重启后, 各个component能够正常接收解析消息流。如果有大的消息流的变化,建议使用应用热升级功能, 见:http://gitlab.alibaba-inc.com/aloha/jstorm-guide/wikis/How-to-deploy

使用

初始化灰度发布升级请求。

因为要得到新的storm code,这个复用了提交拓扑的命令。

jstorm jar /home/weiyue.wy/sequence-split-merge.jar com.alipay.dw.jstorm.example.sequence.SequenceTopology /home/weiyue.wy/t.yaml -c topology.upgrade=true -c user.defined.log4j.conf=

初始化之后,拓扑状态会变成UPGRADING。

参数说明

topology.upgrade: 开始灰度发布,初始化的时候必须为true。

topology.master.single.worker: 指定TM使用单独的worker,必须为true。

topology.upgrade.worker.num: 指定这一次升级的worker数,默认为1。如果只想初始化,并不想让它自动随机挑选worker,可以设置为0

topology.upgrade.ttl: 灰度发布超时时间,单位为ms。默认为1天(86400 * 1000)。超过1天灰度发布会强行自动结束,拓扑状态从UPGRADING重新变成ACTIVE。

topology.upgrade.workers: 指定worker列表进行灰度发布,格式为host:port,host:port。

topology.upgrade.component: 指定component id进行灰度发布,每次只能指定一个component。

参数优先级说明

topology.upgrade.workers,topology.upgrade.component,topology.upgrade.worker.num这三个参数,都用于挑选worker进行发布。

具体算法优先级如下:

  1. 如果topology.upgrade.workers不为空,则忽略其他参数,挑选指定的worker进行发布,需要注意的是,这些worker发布完之后,这个参数就自动置空了。

  2. 否则查看topology.upgrade.component是否为空,如果不为空,则还需要查看topology.upgrade.worker.num是否为0, 如果不为0,则挑选指定component下topology.upgrade.worker.num进行发布。否则对这个component下所有worker进行发布。

  3. 如果上面两个都为空,随机挑选topology.upgrade.worker.num个worker进行发布。

继续发布

进行了初始化发布之后,有可能需要继续进行灰度发布(比如初始化的时候,只指定了一个worker)。请使用gray_upgrade命令进行继续发布。

jstorm gray_upgrade <topology_name> -w <workers> -n <worker_num> -p <component>

jstorm会记住当前正在进行的发布,所以继续发布不需要重新上传jar。

结束发布

如果所有worker都已经完成了发布,jstorm会自动完成灰度发布,并将拓扑状态置为ACTIVE。

如果想提前完成,请使用complete_upgrade命令。

jstorm complete_upgrade <topology_name>

发布回滚

如果想要回滚,请使用rollback命令。

jstorm rollback <topology_name>

需要注意的是,rollback命令不能挑选worker。它会挑选所有已经发布过的worker,用旧的代码和jar进行回滚。且是不可逆的, 即rollback之后,就不能继续灰度发布,需要重新初始化提交

内部流程

  1. client以提交拓扑的形式提交灰度发布命令(因为需要重新生成storm code,因此复用submitTopology接口), 指定topology.upgrade=true,并上传新的jar包。

  2. nimbus收到请求后,设置灰度发布配置GrayUpgradeConfig,写入到zk中/gray_upgrade/topo-id/节点下。 将config.continueUpgrading设置为true

  3. TM有一个定时线程GrayUpgradeHandler,读取该节点的配置,检测到灰度发布配置且continueUpgrading=true时, 将分配指定workerNum的worker数,添加到zk的/gray_upgrade/topo-id/upgrading_workers节点下。 并将continueUpgrading设置为false(防止自动进行后续的灰度发布)。注意使用单独的upgrading_workers和upgraded_workers的设计, 主要是避免同步问题。如果将这些信息写在upgrade config类中,那可能会涉及到多个supervisor同时更新workers的情况,这样是会有同步问题的。 而使用单独的节点,我们只需要在这个节点下添加/删除子节点,不会有同步问题。

  4. SyncSupervisorEvent会定时检查每个拓扑的这个节点,一旦有数据,就和自身的IP和port list进行对比,如果有属于该supervisor的灰度发布, 就下载最新的storm code和storm jar,然后重启worker。然后将worker添加到zk的upgraded_workers节点下。

  5. GrayUpgradeHandler检测ZK,如果upgraded_workers的worker数>=当前总worker数-1(减去TM本身),则认为此次灰度发布已经完成, 删除zk上的GrayUpgradeConfig、upgrading_workers、upgraded_workers。

  6. 如果只想升级部分worker或特定component,可以用complete_upgrade强制完成升级。

TODO

  1. worker进行升级时是否需要将上游spout先做deactivate,是否需要做graceful shutdown?

  2. supervisor的定时线程周期为10s一次,在大集群中,如果灰度发布的拓扑比较多,会不会因为处理时间比较长而打乱这个定时周期?