Chef中收敛与幂等的区别

Posted

技术标签:

【中文标题】Chef中收敛与幂等的区别【英文标题】:Difference between convergence and idempotence in Chef 【发布时间】:2015-08-17 09:31:47 【问题描述】:

Chef中收敛和幂等的基本区别是什么?

【问题讨论】:

【参考方案1】:

收敛和幂等不是 Chef 特有的。它们通常归因于配置管理理论,但也用于其他领域,尤其是数学。

让我们从更基本的幂等开始。我们将忽略幂等的数学用法,而是关注配置管理人们谈论它时的含义。即:“同一动作的多次应用对系统状态没有副作用”。幂等操作的一个简单示例是mkdir -p

mkdir -p /var/lib/statedir/myapp

无论我们运行该命令多少次,都会创建该树。关于幂等操作的另一种表述方式是,“反复运行工具不会在第一次之后改变系统。”

现在将其与收敛进行对比。一般而言,融合意味着将[人或]事物聚集在一起。在配置管理中,融合意味着使系统状态符合定义的策略。也就是说,仅当需要进行更改时才对系统进行更改。一个收敛运算的简单例子是:

if [ ! -d /var/lib/statedir/myapp ]; then
  mkdir -p /var/lib/statedir/myapp
fi

这是收敛的,因为我们只在所需目录不存在时才执行 mkdir 命令。我们也将其称为“测试和修复”操作。也就是说,我们测试我们正在管理的特定事物的当前状态,然后如果它不处于该状态,则使用特定的命令或操作对其进行修复。这就是 Chef 在幕后使用这样的资源所做的事情:

directory '/var/lib/statedir/myapp' do
  recursive true
end

我们(Chef)谈论这个的方式是,Chef 采取幂等动作将系统收敛到各种资源声明的状态。 Chef 中的每个资源都是声明性的,并对资源的当前状态进行测试,然后修复系统以匹配该状态。

为了更深入地了解 Chef 的工作原理,它在 Chef 运行中有一个“编译”阶段和一个“收敛”阶段。在“编译”阶段,它评估节点上的 Ruby 配方,并寻找添加到“资源集合”中的资源对象。一旦它评估了所有的配方,它就会进入“收敛”阶段,在这个阶段它迭代资源集合,采取适当的行动将资源置于所需的状态,从而创建用户、写入文件、安装包,等等。

【讨论】:

这真是一个很棒的解释!!我知道厨师中的收敛概念,但不知道幂等性。谢谢你的表达。 :) -1。我觉得这不是一个特别清楚的解释;它使幂等性和收敛性听起来基本上是同一件事,因为您用作这两个概念示例的命令在语义上是相同的。一个幂等但非收敛命令的示例(或收敛但非幂等命令,如果这样的话甚至有意义的话)会增加清晰度。【参考方案2】:

免责声明:我是配置管理社区的局外人,我花了几个小时的阅读才弄清楚接下来的内容。我在这个答案中批评了配置管理社区,所以你应该知道他们的世界不是我的世界,我现在的工作中什至没有使用任何配置管理工具,我只是根据我能找到的东西来判断他们在谷歌上。

定义

说一个操作是收敛的大致意味着它将它管理的系统的任何部分置于指定的状态。

当配置管理人员说一个操作是幂等的时,他们通常的意思是,如果你在运行一次之后再次运行它,第二次运行将立即终止,而不会做任何多余的工作。

当一个资源在 Chef 的上下文中被描述为幂等时,这意味着在资源已经进入所需状态之后后续 Chef 运行不会将其视为“已更新” " 在运行结束时的 x/y 资源更新 消息中。

请注意,大多数内置资源默认满足这个最终的、最严格的幂等性定义,您可以在自己的配方和自定义资源中使用only_if and not_if 守卫和converge_if_changed 来实现它。

一些评论,以及关于其他定义的注释

令人困惑的是,您在互联网上找到的大多数“幂等”定义与我刚刚给出的任何一个都匹配。我不是相信专家的定义是什么,而是通过观察他们实际使用该术语的方式来推断它。发现有人给出“幂等”的定义,然后在几段后以明显不符合该定义的方式使用该词,这是非常常见的。

要探索这一点,让我们从探索配置管理领域之外存在的“幂等”定义开始。许多这样的定义列在***https://en.wikipedia.org/wiki/Idempotence。在配置管理上下文中最常被(错误地)赋予幂等性含义的含义如下:

在数学中,如果 f(f(x)) = f(x) 对于 x 的所有可能值,则称函数 f 是幂等的。 在数学中,如果满足某种正式定义或其他定义,则大量其他类型的数学对象被称为幂等(通常具有“重复执行操作与执行一次具有相同效果”的共同主题) . 在编程中,说函数或过程是幂等的意味着以下两种情况之一:
    对于接受参数并返回值的函数,与数学含义完全相同。 对于具有副作用的函数,在调用该函数一次后,后续调用将保持系统状态不变。

大量混淆的来源将这些定义中的一个定义为配置管理上下文中“幂等”的含义,然后立即继续使用该术语,明确表明这并不是他们真正的定义使用。一些例子:

佩斯的competing answer to this very question。他在那里声称:

如果在一个系统(其基础状态未更改)上多次执行该步骤后,结果与该步骤已执行一次相同,则该步骤是幂等的。

然后继续举一个非幂等步骤的示例:

rm -rf /var/log/myapp
mkdir -p /var/log/myapp

显然,这一步确实符合 Pace 的幂等性定义,因为连续多次运行它会使我们进入与运行一次相同的最终状态(即,/var/log/myapp 存在且为空的状态)。但是,它在第​​二次运行时会做多余的工作,因此佩斯将其描述为非幂等的。

Mischa Taylor 和 Seth Vargo 的书Learning Chef: A Guide to Configuration Management and Automation。在那里,他们声称:

当 Chef 代码幂等时,它可以在同一个系统上运行多次并且结果始终相同,不会产生意外的副作用。

但后来,评论他们的示例食谱之一:

我们的配方是否通过了幂等性测试?可悲的是没有。 ... Chef 错误地认为它仍然需要做一些事情——在第二次运行中更新了 2/3 资源。如果配方真的是幂等的,我们会看到 0/3 的资源被更新。 Chef 会检查系统的状态,发现自上次运行以来没有任何变化——没有人触及两次运行之间的节点——并且不执行任何资源更新

再一次,他们根据系统状态在多次运行配方时保持不变来说明幂等性的定义,但实际上使用这个词表示避免了不必要的工作。 p>

Ben Ford 在 Puppet 博客上的 Idempotence: not just a big and scary word,他首先给出了幂等性的定义...

幂等性是一个简单的词,用于描述无论您运行一次还是 10,001 次都会产生相同效果的操作。加一不是幂等的,因为结果一直在递增,但是乘一是幂等的,因为不管乘多少次,答案都是一样的!

然后他给出了这个幂等性的示例,虽然它与上面给出的定义一致,但有点可疑——因为它侧重于后续执行不做多余的工作,而不是在他们身上达到相同的结果

想象一下,当你 12 岁时,你妈妈让你倒垃圾。作为一个好孩子,你放下了 GameBoy,然后跳起来按照要求做,是吗?

但 30 分钟后,当她走过客厅,看到你蜷缩在沙发上玩“超级马里奥大陆”时,她再次告诉你倒垃圾。我强烈怀疑你没有跳起来拿出一个空垃圾袋。相反,你说,“已经做到了,妈妈!”这就是幂等性。被告知一次倒垃圾的效果与被告知两次的效果相同。你没有再做一次,因为它已经完成了。

最后,他抛开了他的定义,并给出了一个他声称不是幂等的操作示例,尽管重复执行它达到相同的结果:

那么,那段时间你因为编写非幂等的执行者而受到批评呢?刚接触 Puppet 的人通常有他们要替换的 shell 脚本,他们编写的代码看起来像这样:

exec  '/usr/bin/curl http: //server.net/packages/package.tar.gz -o /tmp/package.tar.gz ': 

-> exec  'tar -xf /tmp/package.tar.gz -C /tmp/package': 

-> exec  '/tmp/package/installer.sh': 

file  '/tmp/package':
    ensure  => absent,
    force   => true,
    require => Exec[ '/tmp/package/installer.sh'],


file  '/tmp/package.tar.gz':
    ensure  => absent,
    force   => true,
    require => Exec[ '/tmp/package/installer.sh'],

那有什么问题呢?它有效,对吧?下载压缩包,解压,安装,然后自己清理。假设没有拼写错误或网络问题,它看起来应该可以完美运行。它会的。但每次 Puppet 运行时它都会完美运行。换句话说,它会每三十分钟下载并运行一次安装脚本!

但结果是一样的,本!之前,这就是你告诉我们幂等性的定义所围绕的细节!

显然,Ben 确实应用了幂等性的“避免冗余工作”定义,尽管他声称这样做。

一个运算可以是幂等但不收敛的吗?

是的。这样的操作不会使系统进入指定的最终状态,但确实避免了连续运行的冗余工作。 Pace's answer 给出了这样一个操作的例子,Thinking Like A Chef 提供了另一个例子:

一个系统可以是幂等的而不是收敛的。例如,如果我们有伪代码if file X does not exist, write the current timestamp to file X,那将是幂等的,但不能真正说它收敛于特定的最终状态。

我能想到的可以描述为幂等但不收敛的操作的最佳实际示例是使用典型的包管理器的install 命令安装包:

如果未安装软件包,则安装最新版本,但是 如果已安装旧版本,则不会更新它。

状态(你得到的包的版本)不是由配方决定的,所以它可以说是不收敛的,但它成功地避免了不必要的工作。

一个运算可以收敛但不是幂等的吗?

是的,绝对!一个简单的例子是上面已经引用过的 Ben Ford 的例子,它无条件地将文件下载到某个本地路径。它是收敛的,因为最终状态始终相同(文件存在),但不是幂等的,因为它每次运行时都会重新下载文件。


对于它的价值,我觉得令人沮丧的是,配置管理社区已经使用了一个在更广泛的编程世界中已经具有明确含义的术语,然后将其用于相关但仍然明显不同 方式,而没有提供它在他们的世界中意味着什么的正式定义。搜索 Chef 文档 (https://www.google.co.uk/search?q=site%3Ahttps%3A%2F%2Fdocs.chef.io+idempotent) 会发现该术语的许多用途,但没有定义。当浮动一词的大多数定义与用法不符时,这个话题会让人感到困惑,这并不奇怪。

我只找到了一个人,他给出了与幂等性的使用方式一致的定义,那就是 coderanger(又名 Noah Kantrowitz)。在我之前引用的Thinking Like A Chef 中,他写道:

“幂等” ... 表示参与者尽可能少地完成所需的状态。

他在an IRC conversation from 2015 中写道:

幂等意味着在不需要时不采取行动,收敛意味着它“解决”在特定的最终状态。

除了这个人之外,我真的找不到其他人对这个术语的定义与整个配置管理社区似乎使用它的方式相匹配。

【讨论】:

喜欢你的想法!我们要求数据库升级脚本是幂等的(即可重新运行,允许发散);不需要收敛(即重新/计算所需状态)。 " idempotent="4.2 价格标记脚本是否已在此数据库上运行?" converent="价格是否反映了 4.2 版中引入的新加价?"两者是独立的,但可以结合起来达到所需的状态。 combine=如果目标是将数据初始化到“4.2”状态,则不要多次运行价格脚本。 converent=>如果目标是执行定价策略,则运行多次,无论是什么版本。 多么棒的答案!精确剖析了“幂等”这个词在配置管理实践中是如何被用来表示一些不同的东西的,尽管人们用同样的词来定义“幂等”。这个答案也让我立刻明白了为什么他们需要“收敛”这个词——因为一旦“幂等”最终意味着“不报告更改/不重做工作”,这使得“幂等”对于说“导致相同的最终状态”,突然间你必须找到另一个意思相同的词。 当有人告诉我我的 Ansible playbook 不是幂等的时,我第一次尝到这种味道,我想“什么!?它在重新运行时弄乱了所需的状态!?这是我需要的一个严重错误修理!” - 结果他们只是意味着报告的某些步骤“已更改”而不是“未更改”。 (公平地说,这仍然是一个错误,只是一个肤浅的错误 - 在结果状态未更改时报告更改是一种误导,用户必须能够相信报告的结果并不表示状态已更改,除非状态实际上以某种方式更改很重要。)【参考方案3】:

@Mark Amery 要求提供一个更令人满意的示例来说明两者之间的区别,因此我会尽力提供。

如果在步骤成功结束时系统已进入已知状态,则该步骤是收敛

如果在系统(其基础状态未更改)上多次执行该步骤后,结果与该步骤已执行一次相同,则该步骤是幂等。 p>

没有幂等性的收敛

收敛但非幂等的步骤是:

rm -rf /var/log/myapp
mkdir -p /var/log/myapp

在步骤成功结束时,我们知道/var/log/myapp 是一个存在的空目录。

它不是幂等的,因为它每次都会炸掉/var/log/myapp 目录。幂等性是可取的,因为它减少了系统上不必要的流失。显然,任何写入/var/log/myapp 目录的应用程序都不会对上述步骤感到满意。

没有收敛的幂等性

一个幂等但不收敛的步骤是:

test "$(ls -A /home/foo 2>/dev/null)" || tempfile -d /home/foo

仅当/home/foo 中没有文件时,该脚本才会在/home/foo 中创建一个具有随机名称的文件。这是幂等的,第一次运行后目录不会为空,所以以后的运行什么都不做。

但是,它不是收敛的。您不能说此步骤将系统置于任何已知状态,因为创建的文件将具有随机名称。

需要收敛,因为它有助于生成处于相同状态的系统,因此更有可能表现出可预测的行为。

请注意

这些术语就像抽象,它们不精确并且可能泄漏。例如,您可以声明一个操作不是幂等的,因为它占用了 CPU 周期。您可以说,一个执行昂贵测试的幂等测试和修复操作比执行廉价测试的另一个操作“不那么幂等”,即使“不那么幂等”不是事实。

您可以尝试说明安装 mysql 版本 X 的步骤不收敛,因为在不同机器上运行时,它会在文件上留下不同的时间戳。或者,您可以说我在上面发布的步骤是收敛的,因为它使系统处于“/home/foo 存在并且只包含一个文件”状态。

这就是数学脱离黑板时发生的情况。

【讨论】:

但是,但是......您对幂等性的定义不包括“避免不必要的工作”(您的没有幂等性的收敛示例断言为幂等性的一个重要方面)。我认为收敛是关于在规范的多个方面应用幂等性,直到不需要进行进一步的更改。这就像试图将车轮的一转(幂等性)与汽车旅行(收敛性)进行比较。并且您的短语“因此表现得更可靠”可能会更好地表述为“因此更有可能表现得更可预测”。很好的尝试:-) 恐怕我不得不不同意。消除额外的工作通常是幂等的好处,但我不认为这是必要的要求。我的示例谈到减少不必要的流失,我的意思是减少不必要的更改,因为这些可能会带来冲突或错误的风险。我也不同意需要幂等性来定义收敛。我认为这两者通常是互补的,但我觉得我的定义更准确。我同意你的措辞。我会把它清理干净。欢迎您就其他两点提交您自己的答案。 我和@barny 在一起;您所谓的“没有幂等性的收敛”示例实际上完全满足您自己对幂等性的定义,这使得答案的一部分自相矛盾。不过,没有收敛的幂等性的例子是有道理的,而且很有启发性! 嗯,我想我对这个例子的想法是,任何时候你执行那个操作,你都有使用/var/log/myapp 使任何应用程序崩溃的风险。换句话说,该操作有一个副作用,使其成为非幂等的。 @Pace 但是如果一个应用程序在两次运行之间已经启动并将内容放入/var/log/myapp,那意味着系统的“基础状态”已经改变,不是吗?这意味着,根据您的定义,使应用程序崩溃并不违反幂等性。

以上是关于Chef中收敛与幂等的区别的主要内容,如果未能解决你的问题,请参考以下文章

(转)理解POST和PUT的区别,顺便提下RESTful

源码分析ElasticJob任务错过机制(misfire)与幂等性

基于CAP组件实现补偿事务与幂等性保障

分布式系统互斥性与幂等性问题的分析与解决

分布式系统互斥性与幂等性问题的分析与解决

post和get的区别