漫谈配置

本文是翻译,版权归原作者所有


2015.4.3~4.4,第二届开发者大会将在斯洛文尼亚的卢布尔雅那举行。Avishai 来卢布尔雅那开发者大会做第二次演讲;这次的话题是关于“工作”的意义。我们问他是否就关心的以及所能涵盖的众多话题写了一点东西,他选中了配置。如果你深入过系统或 app 开发,那么你可能知道正确地配置是多么困难。我们先一阅 Avishai 关于配置方面的作品,看看他所认为的配置是什么样子以及可以被搞定的。

2015.4.3~4.4,第二届开发者大会将在斯洛文尼亚的卢布尔雅那举行

配置是我们通常认为理所当然的一项工作。然而,随着越来越多的配置被加进来,配置将变得难以使用和复杂。对于足够多的配置参数,追踪当前配置“是”什么 是相当有问题的。人们经常由于各种原因错误地配置系统,比如文档缺乏,或不同参数之间的意外交互。有时候,配置本身已经复杂到需要一种语言来表示了,进而抬高了定义配置所需知识的门槛。

尽管配置具有“乏味”的特点,它们在数个小时内就能够、也摧毁过整个公司

又一种配置格式

如果你快速浏览 /etc 目录,将发现一堆使用大量格式的配置文件。那些 ini、toml、json、yam、xml 的 key/value shell 包含文件,还算是相对标准的;如果你看下 sudoers、apt.conf、apache 和 postfix,你将发现更多外观古怪的格式。

不幸的是,我们人类需要记住每种格式的语法,更不要提每种程序配置的其它特性了。例如,不存在配置文件校验的标准,某些程序根本就没有校验!

种类繁多的配置格式让系统管理员倍感头痛。追踪和维护得体的技能也变得困难;某些格式难以用配置管理工具和脚本生成,因此我们必须转而使用容易出错的文本模板。

配置投弹

很多年前就出现 conf.d 模式了,允许不同的模块和包向其它程序注入配置片段。在缺乏 CM 工具【注1】时,它为人类分割大型配置,使得管理更为轻松。

这种模式通常被认为是不错的实践,然而在系统的维护和自动化上,带来了令人惊奇的大量问题。既然配置被合并了,值可被其它文件覆盖,有时候是以意外方式合并的。你修改了一个配置参数,然而程序的行为就像你没有什么改动一样;你 grep 某个目录,在不同的文件里找到了被设计的值,而这个文件不是你控制的。你必须推算出合并顺序,把你的文件挪到更高优先级,这可能覆盖其它参数……现在,你需要再次 debug。

当使用 CM 工具时,这种模式尤其让人恼火——如果你的 CM 工具管理 conf.d 目录下的文件,随后你删除了这些文件资源、而配置文件没有被删除,那么它们只是不再被管理了。还有,手动将文件扔到 conf.d 目录,将覆盖自动化配置,使得标准化服务器上的配置努力化为泡影。

伙计,你刚才重启了吗?

传统上,配置 reload 是通过向进程发送一个 POSIX 信号,通常为 USR1 或USR2。问题在于,信号没有输出,没有明显的反馈来告诉我们 reload 是否成功。或许配置文件是恶意的、或者我们给某些参数设置了不合法的值;或许信号被阻塞了、或许程序没有处理。在我们开始深挖日志文件之前,我们只是不知道,甚至不能确定,因为日志文件缺乏“reload”信息,实际上不代表 reload 没有发生过。最重要的是,很难自动化这种检查,因此大部分情况下,我们只有放弃,并假定配置对程序起作用了,或者采取粗暴的方式,不必要地重启我们的进程。

有疑问时的终极大杀器

某些参数需要重启才能修改,有些则需要 reload。CM 工具无法识别配置文件里要修改了什么参数,以及 reload 是否足以激活修改。结果,我们常常被迫使用核武器——重启。不幸的是,有时候甚至核武器都不够,比如当修改 MySQL innodb ibdata 文件大小时,需要一个停止-维护-启动的过程;这就迫使我们借助核武器的方式,卸下计算机实例以支持配置生效。

我不知道发生了什么

仅仅因为配置文件包含有 X ,实际上不代表被载入了进程。或许文件被修改了,而没有 reload 配置、或者配置路径是错误的,这真的太常见了。那么,你该怎样才能知道服务器上载入了哪些配置?你该如何校验所有服务器的配置是正确的?大多数程序对此没有提供良好的机制。

更好的方式

和大多数程序的可操作方面类似,配置问题能够、也应该被基层工程作品解决,而非事后的权宜之计。企图在核心上解决这种问题的极好例子就是 Netflix Archaius 项目,很多其它项目也遵循这一规则。

有一些简单的设计原则,使得你的程序配置更容易处理。在某种程度,你甚至能够使用 CM 工具将这些原则应用到第三方程序上

  1. 根据配置参数修改的影响,将配置分割为2-3个文件:第一个文件包含需要重启才生效的参数,第二个包含需要 reload 才生效的参数,以此类推。

  2. 避免使用 conf.d 模式。使用你的 CM 工具合并值,并创建较小数量的配置文件——使得 debug 和校验更容易。

  3. 创建配置 API。如果使用 REST,那么 GET 应该返回带有 ETag 头的、配置参数的完整 dump 信息,HEAD 应该返回没有 body 的 ETag 头。ETag 头应该是符合规范顺序的、配置的校验值,可以在所有节点的 in-ram 配置和 CM 的引用版本之间轻松比对。

  4. 如果可能,请使用 REST 配置 API,以使用 POST 或 PUT 请求来 reload 配置。这样,将易于你的 CM 工具校验配置成功载入以及值是否更新了(200/201/202 响应)。如果做不到,就编写小型 reload wrapper,使用程序提供的任意反馈来校验配置被 reload 了。

  5. 当编写新程序时,为配置选择一种可序列化的格式,比如 json、yaml、edn 等。尽管如此,用户直接使用它们还不是十分舒服,记住,使用 CM 工具和简单的工具集,只要转换工具集是现存的,用户就可以使用他们顺手的格式。

  6. 一些程序需要高级配置部署逻辑(比如 logstash),难以映射到序列化的格式;对于这种情况,就把配置看做是一种插件,将变量抽出、放到外部的配置文件里

注1:组态管理(英语:Configuration Management,简称 CM),或译为配置管理,是一个建立系统工程的过程,用来建立与维持一个产品,让这个产品的效能、功能,以及它所要求的物理特性,在它的生命周期中,都能保持稳定与一致性。http://zh.wikipedia.org/wiki/組態管理

译文:漫谈配置 》| 腊八粥