本作品采用知识共享署名 3.0 非移植许可协议授权。 http://creativecommons.org/licenses/by/3.0/legalcode

Designate 的工作者模型

论点:Designate 代码以及作为服务运行的 Designate 中存在不必要的复杂性。将 Designate 打造成为生产者-工作者类型的项目将大大简化开发和运行,并使其更符合其提供的服务的本质(DNS)。

问题描述

designate-pool-manager 在将创建/删除更改推送到名称服务器方面做得相当不错,但此后的过程就有点不尽人意了。

  • 通过异步和同步 RPC 与另一个组件进行轮询以查看状态是否在线。

  • 缓存使用混乱(存储多个键,永久保留一个键,为每种操作类型存储不同的键)。

  • 随着更改数量的增加,定期同步/恢复非常不可靠。

  • update_status 和计算共识的逻辑过于繁重、过于急切且过于复杂。

  • 状态机非常模糊,推送到 central 的状态更新逻辑晦涩难懂。

  • 池管理器绑定到一个池

designate-zone-manager 很好地执行了其管理的区域的定期计时器。但是

  • 一个区域管理器进程负责一组区域,如果该组区域的操作量很大,单个区域管理器进程可能会不堪重负。

  • 我们依赖 tooz 来管理区域管理器进程确保所有区域平衡和覆盖的极其微妙的任务。

  • 某些工作(导出)位于操作的关键路径中,已经蔓延到本不应该处理该工作的组件中。作为适当工作者的替代方案,区域管理器看起来是当前的答案。

designate-mdns 是用 Python 编写的 DNS 服务器。它在处理少量流量时效果很好,但随着流量的增长,我们可能会意识到需要使其更加专业化,作为用 Python 编写的 DNS 服务器应该做的那样。发送 NOTIFY 和轮询更改的逻辑似乎不太可能属于 mdns 的范畴。如果删除了这些部分,designate-mdns 可以重写以利用更好的工具来解决问题。

提议的变更

对 DNS 服务器上实际执行工作以及运行其他任务的基本架构进行更改。本质上,删除 designate-pool-managerdesignate-zone-manager,用 designate-workerdesignate-producer(名称待定)替换它们,并从 designate-mdns 中删除某些逻辑。所有实际的“工作”都将放在可扩展的 designate-worker 进程中,该进程由 API/Central 产生工作,以及 designate-producerdesignate-mdns 回归其根源,仅回答 AXFR。消除涉及 API 的队列上的回调,简化了处理 DNS 服务器的所有组件中的代码。

不需要更改 API 或数据库,只需对 designate-central 进行最少的更改。

对于最终用户而言,此更改的结果将相对简单

  • 可扩展性仅受 DNS 服务器、数据存储和队列的限制。如果 Designate 在任何时候开始在某些方面变慢,除非上述服务存在问题,否则可以通过增加 Designate 进程来解决问题。

  • 容错性。一个或多个 Designate 进程崩溃在几乎所有情况下都不可见。操作员不必担心某个进程崩溃,因为没有一个进程处理其他进程不会处理的职责,只要存在最小的冗余即可。

  • 简单性。Designate 架构变得更加简洁易懂。“池管理器和区域管理器有什么区别?”以及“什么是同步和异步?”这些问题变得不那么模糊,或者完全消失。

  • 从操作角度来看,这为小型部署的更简单场景打开了大门,客户只需要扩展几个组件(甚至在同一台机器上)就可以获得更高的性能。您甚至可以部署仅共享数据存储(db、缓存)并拥有自己的 Designate 组件和队列的应用程序节点。

架构变更

这些是将保留存在的服务

  • designate-api - 用于接收 JSON 并解析 Designate

  • designate-central - 用于验证/存储区域/记录数据并将 CRUD 任务发送到 designate-worker

  • designate-mdns - 仅执行 Designate 数据库中的 AXFR

  • designate-worker - Designate 需要在名称服务器上产生状态的任何和所有任务

  • designate-producer - 用于运行定期/定时作业,并为 designate-worker 产生超出 API 操作正常路径的工作。例如:定期恢复。

其他必要的组件

  • 队列 - 通常是 RabbitMQ

  • 数据库 - 通常是 MySQL

  • 缓存 - (鼓励使用,但不是必需的)Memcached、MySQL、Redis

  • 一个 tooz 后端(Zookeeper、Memcahed、Redis)

不再需要的服务/组件

  • designate-pool-manager

  • designate-zone-manager

Designate 工作者

designate-worker 的职责范围基本上是 Designate 需要采取行动以执行的任何和所有任务。例如

  • 通过后端插件在池目标上创建、更新和删除区域

  • 轮询以确认更改已生效

  • 使用区域/目标的序列号更新缓存

  • 为计费发出 zone-exists 事件

  • 展平别名记录

  • 清理已删除的区域

  • 导入/导出区域

  • 更多

该服务本质上公开了一个庞大的 RPCAPI,其中包含 tasks

与 Designate 当前模型的一个重要区别是,所有这些任务都不会回调。它们都是 fire-and-forget 任务,将被推送到队列并等待工作者操作。

tasks 本质上是函数,在给定相对简单的输入的情况下,可以在名称服务器或 Designate 数据库上产生所需的结果。

缓存

缓存执行与当前池管理器缓存类似的功能。

它将为工作者可以用来确定是否需要继续使用从队列接收到的 task,或者直接放弃并继续下一个任务的每种类型的任务存储状态。

这因任务而异,有些相对简单,知道是否执行到特定序列号的区域更新可以通过查看池中每个目标上的区域序列号来确定。对于 DNSSEC 区域签名,可能会放置一个密钥来指示某个工作者正在处理区域重新签名,因为它是一个更长期的过程。

如果没有这样的缓存,每个工作者都会天真地尝试完成它接收到的每个任务。

任务

每个任务在尽可能的情况下都是幂等的。

Cache 部分所述,在一定程度上,任务可以根据缓存中的信息来了解是否需要完成工作。

但它们也应努力避免重复工作,例如,如果它尝试删除已经消失的区域,它应将区域消失解释为删除成功的信号并继续进行。

总的来说,这些任务将直接从代码中现有位置提取,并且不会发生太大变化。

一个小的变化可能是,在任务过程中,我们可能会重新检查正在进行的工作是否仍然需要完成。

例如:API 客户非常快速地创建了许多记录集。分派到 designate-worker 进程的工作将到达许多不同的位置,并且第一个实际到达名称服务器的更新可能包含将区域更新到最新状态所需的所有更改。其他正在处理的任务应在发送 NOTIFY 之前检查状态是否仍然滞后,并在开始轮询之前再次检查,以便减少自己和名称服务器的不必要工作。

您可以更智能地处理为这些任务丢弃的标记。例如,在区域更新时,您可以将类似 zoneupdate-foo.com. 的密钥放入缓存中,如果其他针对同一区域的 zoneupdate 任务看到该密钥,它们可以知道放弃其工作并继续进行。

designate-mdns 更改

Designate 之前分割的某些元素消失了。工作者服务将发送 DNS 查询,它将执行 CPU 密集型任务,但它将是一个可扩展的地方。通过简单地扩展这些工作者,应该可以拥有一个非常强大的 Designate 架构。

designate-mdns 的整个 RPCAPI 将转移到 designate-worker。这将大大简化它在处于 Designate 管理的区域传输的关键路径中需要执行的工作量。

作为补充说明,这将使这项服务更容易优化,甚至可以用更快的编程语言重写。

Designate Producer

designate-producer 是生活在正常 API 操作路径之外并在某种定时器上运行的产生任务的工作的地方。

zone-manager 服务的主要区别在于,该服务只是生成要执行的工作,而不是实际执行工作。 designate-producer 只是决定需要做什么,并通过 RPC 消息发送到队列,让 designate-worker 实际执行工作。

随着 Designate 的发展,我们已经看到这种需求的增长,并且在未来还会更多。

  • 已删除区域的清除

  • 刷新辅助区域

  • 发出区域存在任务和其他计费事件

  • DNSSEC 区域签名

  • 别名记录展平

我们可以将池管理器中的 periodic_syncperiodic_recovery 任务移动到此服务。

池管理器中的 periodic_syncperiodic_recovery 任务一直难以维护和正确运行。这有很多因素。

将定期过程生成的 tasks 的工作交给 Designate 的唯一组件简化了架构,并允许我们以一种方式解决它所带来的问题,并通常做好一件事。

定时器

该服务本质上是一组定时器,它们以一定的节奏唤醒并创建要放入 designate-worker 进程拾取的队列中的工作。

这里的开销相对较低,因为我们实际上并没有执行工作,而只是安排工作。
这样我们就可以专注于这些过程将放入队列中的工作产生的意外困难问题。

划分工作

为了更清楚地解释,我们遇到的最大的问题是在保证容错性的同时,避免为 designate-worker 进程重复工作。这之前是通过 tooz 使用 Designate 数据库中的区域碎片在 designate-zone-manager 中解决的,并且似乎效果很好。

designate-worker 进程,如上所述,将进行一定程度的优化,以便它们不需要重复工作。但是,如果我们产生过多的垃圾,这些进程将因仅仅是确定是否需要执行工作而而变得迟缓。因此,我们应该努力最大限度地减少我们产生的重复工作量。

队列优先级

此实现的一个潜在复杂性是,随着超出 Designate 关键实施路径的定时器和任务数量的增加,它们可能会妨碍 designate-worker 进程执行最重要的任务,即区域和记录的 CRUD。

我们建议为每种类型的任务创建队列/交换机,这将是监控不同类型任务健康状况的最佳方式,并将定期计时器产生的有时会很长的任务与相对更快、更重要的 CRUD 操作隔离。选择各种选项中的任务的算法可以由特定进程自定义。但一个好的通用默认值是首先处理来自 designate-central 的 CRUD 操作。或者使用加权随机选择算法,其中关键路径 CRUD 操作具有更高的权重。

工作项

  • 启动一个 designate-worker 服务

  • 将 CRUD 区域操作迁移到 designate-worker,并重构缓存实现。

  • 启动 designate-producer 服务

  • 将 Pool Manager 定期任务迁移到 designate-producer,并进行少量修改以确保它们仅为 designate-worker 生成工作。

  • designate-mdns 的 NOTIFY 和轮询功能迁移到 designate-worker

  • 修复 designate-central 中的 update_status 逻辑

  • 将所有任务从 zone-manager 迁移到 designate-workerdesignate-producer 的拆分,其中 producer 在队列上创建工作,worker 执行它。确保在 designate-producer 中使用缓存或其他方法实现可扩展的分布式工作生产逻辑。

  • 弃用 pool-managerzone-manager

  • 盈利!!!

升级影响

升级到包含此更改的下一个版本将引入一些操作更改。主要是在需要部署的服务方面。部署不必是切换,部署 Newton Designate 可以在启用或禁用 worker 的情况下工作。这是因为采取了各种兼容性措施

  • designate-central 将具有可配置的“区域 API”,可以在 designate-pool-managerdesignate-worker 之间切换。如果启用了 worker 进程,central 可以将 c/u/d 区域事件发送到 worker,而不是池管理器。

  • designate-worker 发送 NOTIFY 和轮询 DNS 服务器的能力可以取代一部分 designate-mdns 的职责。对于某些 DNS 服务器,理论上如果 NOTIFY 来自与它区域传输的主服务器不同的服务器,它们将无法正常工作。出于这个原因,designate-worker 发送 NOTIFY 的能力是一个可配置元素。由于 worker 调用后端插件来更新区域,因此这些后端中的通过 mdns 逻辑发送 NOTIFY 可以保留,并且如果操作员选择,worker 中的 NOTIFY 任务可以执行空操作。这两种方式都可行。操作员也可以选择让 MiniDNS 通知调用执行空操作,并允许 worker 进程完成它们。

  • 对于那些选择在 Designate 和 DNS 服务器之间防火墙所有 DNS 流量的人来说,将 designate-worker 进程部署在靠近 designate-mdns 进程的位置是最安全的。以便 designate-worker 执行的 DNS 轮询可以完成,而 designate-mdns 以前执行它。

  • 当定期类型的进程迁移到 designate-producerdesignate-worker 时,它们可以在 designate-zone-manager 中标记为“worker 任务”,可以通过配置标志关闭。

部署 Newton 后,升级到 worker 模型代码的流程可能如下所示

  1. (为了考虑防火墙 dns 流量) 启动与 designate-mdns 进程在同一 IP 上的 designate-worker 进程,通过邻近或代理实现。默认配置仍然允许通过 designate-mdns 发生 NOTIFY 和 DNS 轮询,并且所有其他操作都在 designate-pool-manager 中工作。没有流量会到达 worker。

  2. 切换配置值 designate-worker::enableddesignate-worker::notify 并重新启动 designate-worker

  3. 重新启动 designate-centraldesignate-mdns 进程,以便 mdns NOTIFY 调用执行空操作,并且 central 开始使用 worker 而不是 designate-pool-manager

  4. 切换 designate-zone-manager::worker-tasks 配置标志并重新启动 designate-zone-manager,以便它将定期任务移交给 producer/worker。

  5. 启动 designate-producer 进程,以便 worker 开始执行恢复和其他定期任务。

  6. 停止 designate-pool-manger 进程,如果所有进程都从 designate-zone-manager 迁移出来,也停止它。

里程碑

完成目标里程碑

Newton

作者

Tim Simmons https://launchpad.net/~timsim

Paul Glass https://launchpad.net/~pnglass

Eric Larson https://launchpad.net/~eric-larson