Chef中收敛性和幂等性的区别

Difference between convergence and idempotence in Chef

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

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

让我们从更基本的幂等开始。我们将忽略幂等的数学用法,而是关注配置管理人员在谈论它时的意思。即:"multiple applications of the same action do not have side effects on the system state." 幂等运算的一个简单示例是 mkdir -p:

mkdir -p /var/lib/statedir/myapp

无论我们运行 这个命令多少次,它都会导致创建那棵树。关于幂等操作的另一种说法是,"running the tool over and over doesn't change the system after the first time."

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

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

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

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

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

为了更深入地了解 Chef 的工作原理,它在 Chef 运行 中有一个 "compile" 阶段和一个 "converge" 阶段。在 "compile" 阶段,它评估节点上的 Ruby 配方,它正在寻找它添加到 "resource collection." 的资源对象 一旦它评估了所有配方,它就会进入"converge" 阶段,它遍历资源集合,采取适当的操作将资源置于所需状态,从而创建用户、写入文件、安装包等等。

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

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

一个步骤是 idempotent 如果在一个系统(其底层状态没有改变)上多次执行该步骤后,结果与该步骤相同执行一次。

没有幂等性的收敛

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

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 个周期。您可以说一个进行昂贵测试的幂等 test-and-repair 操作比另一个进行廉价测试的操作 "less idempotent",即使 "less idempotent" 不是事实。

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

这就是数学逃脱黑板时发生的事情。

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

定义

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

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

当资源在 Chef 的上下文中被描述为幂等时,这意味着后续的 Chef 运行s 在资源已经被放入在 运行.

末尾的 x/y 资源更新 消息中,不要将所需状态计为 "updated"

请注意,默认情况下,大多数内置资源都满足幂等性的最终、最严格定义,您可以使用 only_if and not_if guards and converge_if_changed.

在您自己的配方和自定义资源中实现它

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

令人困惑的是,您在 Internet 上找到的 "idempotent" 的大多数定义 与我刚才给出的任何一个都匹配。我不是相信专家 所说 的定义,而是通过观察他们 实际使用 术语的方式来推断它。发现有人给出了 "idempotent" 的定义,然后在几段之后以明显与该定义不一致的方式使用这个词,这是非常常见的。

为了探索这一点,让我们首先探索存在于配置管理领域之外的 "idempotent" 的定义。维基百科上的 https://en.wikipedia.org/wiki/Idempotence 列出了很多这样的定义。在配置管理上下文中最常被(错误地)给出幂等性含义的如下:

  • 在数学中,函数 f 被认为是幂等的,如果 f(f(x)) = f(x) 对于x.
  • 的所有可能值
  • 在数学中,大量其他类型的数学对象如果满足某种正式定义或其他定义(通常具有共同主题 "doing an operation repeatedly has the same effect as doing it once"),则被认为是幂等的。
  • 在编程中,说一个函数或过程是幂等的意味着以下两种情况之一:
    1. 在函数接受一个参数和returns一个值的情况下,与数学意义完全相同。
    2. 对于有副作用的函数,调用一次函数后,后续调用将保持系统状态不变。

大量混淆的来源给​​出了这些定义之一作为配置管理上下文中 "idempotent" 的含义,然后迅速继续以明确表明它不是真正的术语的方式使用该术语他们正在使用的定义。一些例子:

  • 佩斯的。他在那里声称:

    A step is idempotent if, after multiple executions of the step on a system (whose underlying state has not changed), the result is the same as if the step had been executed once.

    但接着将此作为非幂等步骤的示例:

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

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

  • Mischa Taylor 和 Seth Vargo 的书学习 Chef:配置管理和自动化指南。在那里,他们声称:

    When Chef code is idempotent, it can run multiple times on the same system and the results will always be identical, without producing unintended side effects.

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

    Does our recipe pass the idempotency test? Sadly, no. ... Chef mistakenly thinks there’s still stuff it needs to do—2/3 resources updated in this second run. If the recipe were truly idempotent, we’d see 0/3 resources updated. Chef would inspect the state of the system, recognize that nothing had changed since the last run—no one touched the node between the two runs—and perform no resource updates

    同样,当一个配方多次 运行 时,他们基于系统状态不变来陈述幂等性的定义,但实际上 使用 这个词来意味着避免了不必要的工作。

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

    Idempotence is simply a word that describes an operation that will have the same effect whether you run it once or 10,001 times. Adding one is not idempotent because the result keeps incrementing, but multiplying by one is idempotent because the answer is the same no matter how many times you multiply it!

    然后他给出了幂等性的这个例子,虽然它与上面给出的定义一致,但有点可疑-因为它专注于后续执行不做冗余工作,而不是它们达到相同的结果:

    Imagine a time when you were 12 and your mom asked you to take out the trash. Being the good kid you were, you dropped the GameBoy and jumped right up to do as you were asked, yeah?

    But then 30 minutes later when she walked back through the living room and saw you curled up on the couch playing "Super Mario Land," she told you again to take out the trash. I strongly suspect that you did not leap up to go take out an empty trash bag. Instead you said, "Already did it, Mom!" That's idempotence. The effect of being told once to take the trash out is the same as the effect of being told twice. You didn't do it again, because it had already been done.

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

    So how about that time you were chastised for writing non-idempotent execs? People new to Puppet generally have shell scripts they're replacing, and they write code that looks sort of like this:

    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'],
    }
    

    So what's wrong with that? It works, right? Download the tarball, extract it, install the thing, then clean up after yourself. It looks like it should run perfectly, assuming no typos or network issues. And it will. But it will run perfectly every time Puppet runs. In other words, it will download and run the installer script every thirty minutes!

    但是结果是一样的,本!早些时候,这就是您告诉我们幂等性定义所围绕的细节!

    显然,Ben 确实 应用了幂等性的 "avoid redundant work" 定义,尽管他声称如此。

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

是的。这样的操作不会使系统进入指定的结束状态,但 确实 避免了连续 运行 上的冗余工作。 gives an example of such an operation, and Thinking Like A Chef 提供另一个:

A system can be idempotent without being convergent. For example if we had the pseudo code if file X does not exist, write the current timestamp to file X that would be idempotent, but it can’t really be said to converge on a particular end state.

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

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

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

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

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

时都会做不必要的重新下载文件的工作

就其价值而言,我感到沮丧的是,配置管理社区挪用了一个在更广泛的编程世界中已经具有明确含义的术语,然后将其用于相关但仍然 清楚不同的 方式,从来没有提供正式的定义来说明它在他们的世界中意味着什么。搜索 Chef 文档 (https://www.google.co.uk/search?q=site%3Ahttps%3A%2F%2Fdocs.chef.io+idempotent) 可以找到该术语的许多用法,但没有定义。当术语 floating around 的大多数定义与用法不匹配时,这个主题让人感到困惑也就不足为奇了。

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

“idempotently” ... means that the actor does as little as possible to achieve the desired state.

他在 an IRC conversation from 2015 中写道:

Idempotent means not taking actions when they aren't needed, convergent means it "settles" on a specific final state.

除了这个人,我几乎找不到任何人对这个术语给出的定义与整个配置管理社区似乎使用它的方式相匹配。