【问题标题】:Design patterns/guidelines on creating application/product configurations创建应用程序/产品配置的设计模式/指南
【发布时间】:2015-02-24 18:15:11
【问题描述】:

我想知道是否有用于创建“应用程序配置”结构、数据和文件的设计模式、指南或文档化/最佳实践。 我意识到这个问题在一些帖子中已经部分触及,但我希望以下问题能促使从另一个方面看待这个话题。

  • 基本上什么样的分析会创建配置结构?
  • 需要考虑什么样的力量?
  • 什么时候开始应用程序配置分析/创建;它是对主要设计活动的事后思考或后续行动(由应用程序设计决定)还是与主要设计和本身的结构化/架构工作相互依赖?
  • 以一种方式而不是另一种方式构建配置数据有哪些优缺点。
  • 需要捕获或了解什么样的需求(灵活性、覆盖能力、缺乏重复、选择等)
  • 开发不良应用程序配置的成本是多少?

我特别感兴趣的是开发配置设置的层次结构。

是否有任何具有足够复杂程度的实际项目可以研究其配置?

我的问题不是针对文件的格式或类型(是否使用平面 ini,还是 json、xml,...),而是首先针对如何进行配置。

谢谢

【问题讨论】:

  • 这是一个有趣的问题。我构建的大多数系统都可以满足客户的需求,因此在我看来,这里没有可以应用的通用公式。

标签: design-patterns configuration configuration-files


【解决方案1】:

许多应用程序被多次部署(即安装、配置和运行)。例如,一个应用程序可能部署在开发者的机器上;然后在一台或多台测试机上(使用诸如 UAT、Staging 或 pre-production 之类的名称);然后可能在多台生产机器上。生产中的多次部署可能出于多种原因,例如:

  • 您想要部署服务器应用程序的多个副本,然后使用负载平衡技术将客户端请求路由到这些服务器副本。
  • 您希望在贵公司设有办事处的每个地理位置部署应用程序的单独实例。
  • 您的应用程序具有插件架构,并且您想要部署该应用程序的多个实例,每个实例都有一组不同的插件。

对于应用程序的每次部署,您可能需要有一组“大部分相似但略有不同”的配置文件。如果您使用复制和粘贴方法来创建这些多组配置文件,这可能会导致维护问题。我知道减少这个问题的两种方法。

第一种方法是使用Config4* 作为您的配置文件语法(免责声明:我是 Config4* 的主要维护者),因为它的语法提供了多种方式,例如“if-then-else”和"include" 语句使配置文件能够适应其部署环境,同时仍然重用常见的 name=value 设置。我建议您阅读 Config4* 入门指南 (PDF) 的第 2 章 (HTML) 和第 3 章 (HTML) 以大致了解其语法和 API。不幸的是,墨菲定律指出,您的应用程序将使用一些第三方库,这些库使用 Config4* 以外的其他内容(例如 XML 或 Java 属性文件)进行配置,因此 Config4* 不会帮助您。不过,我认为还是值得阅读上述文档,因为 Config4* 的某些功能可能会提供一些思考。

第二种方法是为每种配置文件编写一个“模板”,其中模板主要包含纯文本,但带有一些占位符。这是一个示例模板配置文件,使用符号${foo} 表示占位符。

serverName  = "${serverName}"
listenPort  = "${serverPort}"
logDir      = "/data/logs/${serverName}";
idleTimeout = "5 minutes";
workingDir  = "/tmp";

如果您对应用程序使用的所有配置文件都这样做,那么您可能会发现对模板配置文件执行全局搜索和替换,并使用相对较少的占位符的值将产生就绪-为特定部署运行配置文件。我在一个项目中使用了这种方法,其中每个部署有超过 2000 行配置文件,大约有 60 个部署,因此产生了超过 100,000 行配置文件。应用于模板文件的搜索和替换数据的行数比从中生成的准备部署配置文件少了大约 50 倍,因此更容易维护。如果您正在寻找一种简单的方法来对模板文件中的占位符执行全局搜索和替换,那么您可能需要考虑Apache Velocity。

与您是手写配置文件还是从模板生成配置文件无关的是配置文件中数据的运行时验证问题。不幸的是,相对较少的配置文件格式提供模式验证。我所知道的只有以下几种。 Config4* 提供了一个易于使用的模式验证引擎(在上述文档的第 3 章中进行了讨论)。还有一个schema validation language for JSON。当然,还有很多 schema validation languages for XML,但它们通常有一个陡峭的学习曲线。

【讨论】:

  • 感谢 Ciaran 的详细回复。这是一个好的开始,您所说的内容和提供的参考资料值得深思。
【解决方案2】:

确实应该在运行时(在应用程序启动期间)而不是在应用程序构建/编译阶段读取配置。您的二进制文件应该始终相同,无论它们在哪里运行。

在启动期间应用程序应该收到正确的配置(来自文件系统、环境变量、配置服务器等)。另一种可能性是(从同一来源)接收有关应使用哪个配置的信息,然后加载已捆绑在您的包中的正确配置。第二个选项不太灵活,但可能更容易开始。

能够覆盖开发环境中的特定配置(例如通过命令行)非常有用。有时您也可以使用它来快速调试生产问题。但总的来说,我会避免继承和覆盖部分配置,因为它很快就会变得难以管理和查看整套可用属性。我建议将配置分成两部分。一 - 在所有环境中通用(常量、路径、公司的邮件服务器等),二 - 在不同运行时(url、数据库密码等)之间变化的东西

并且您必须牢记测试。您的组件必须在集成测试期间正确初始化。提前或以后考虑它,您将不得不与您的框架进行斗争

【讨论】:

    【解决方案3】:

    我从 Ciaran McHale 的回答中得到的基本观点是,如果一个包的最终用户可能有多个部署,那么该包应该带有一个界面来有效地生成不同的配置文件。您的问题是应该指导配置文件的底层结构的原则。即使我们创建了一个接口,这个问题仍然是相关的,因为它将有助于接口的设计和实现。一个非主观的关键点是配置过程是通用代码对其环境的适应,我们总是可以将环境分为两部分:数字或服务器领域和非数字或应用领域。因此,配置值可以分为三类是一个普遍且非主观的事实:仅依赖于服务器的那些,仅依赖于应用程序的那些以及依赖于两者的那些。我认为将这三个类别分开在不同的文件中很重要,特别是如果它们是直接管理的,没有接口。同样,每个文件都应该划分为与包交互的环境的不同部分相对应的部分:数据库、电子邮件服务器等。如果需要配置模块,它们就像环境的一部分对于核心 - 同样的原则适用。我的观察是,一些大型系统甚至会为每个部分使用不同的文件。例如,Apache 对不同的站点和不同的模块有不同的 conf 文件。我想到的另一点是,作为一等对象的函数没有理由不用作配置值:如果一个函数需要在不同的服务器或不同的应用程序中进行不同的定义,那么它就是一个配置价值。我想不出任何其他一般原则。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多