需求

为我们的应用添加配置文件是一个很常见的需求,功能也很容易实现,但当需求变得复杂时,就会让人有点头疼了。

首先大概列举一下我的需求:

  • 支持多种运行模式,可以快速切换不同模式下配置
  • 配置文件最好可以存储成人类可读且修改方便的格式(若有强大GUI支持这条可以不满足)
  • 支持远程配置分发和更新
  • 支持动态调参
  • 支持GUI配置界面
  • 支持配置文件历史,运行时转储
  • 开发成本低

调研

我现在使用ros/ros2作为通信中间件,ros/ros2本身提供parameter server,可以极大程度的覆盖我的需求,但是这个方案不在考虑之类,因为我的计划是尽量和ros/ros2解耦,实际上我已经计划好完全抛弃ros/ros2了。

不得不说这个问题我真的纠结了好久,因为这个需求不是核心算法,我真的不想在这上面花费太多时间,我调研了一下确实有一些开源方案可用,形如Apollo以及Nacos等等,都是挺好的东西,可惜都不是很满足我的需求。

随后我断断续续又做了一些调研,按照时间顺序呈现一下我调研到的可选方案:

  • etcd
    这个方案并没有让我纠结太久,功能上完全满足了,但是应用成本稍高,不予采用。

  • NATS
    这个方案很棒了,生态也很好,我基本就快要敲定是它了,但是我的性格往往是再多走一步,不会因为当前方案已经很好了就彻底停止探索,所以继续往下看。

  • Zenoh
    作为ros2目前唯一的非DDS中间件,这个工具我此前就已经知道了。
    说句题外话,这有一份ros2 RMW替代方案研究报告,结论正是Zenoh,在ros2 kilted中也较为完整的支持了rmw_zenoh_cpp.
    Zenoh的未来我很看好,但是作为开发配置系统的基石来说做不到开箱即用,开法成本会比NATS高一点,但是我看中的是其未来能在整个自动驾驶系统中发挥更多更大的作用,这样的话使用Zenoh等于作了技术铺垫,同时也有利于后续使用Zenoh开发更多功能后,配置系统能够天然融入,这样的话付出一点开发成本我是可以接受的。

目前我的配置文件全部使用yaml格式存储(自ros开始形成的路径依赖),在我进行上述调研时,了解到yaml与toml的一些差异:

  • toml设计更简洁、更规范化,yaml历史更悠久、更灵活
  • toml可以无损与JSON互转,yaml由于其支持锚点、引用等特性不能保证此功能

我几乎没有使用JSON的经验(当然改过一些应用的JSON配置,没有深入研究过),但是要知道JSON本身的生态完整,可以与JSON互转意味着配置可以序列化传输,支持JSON Schema校验等。rust等一系列较为现代化的工具选择toml作为配置文件格式我相信也是考虑到了toml的一些优势吧。至于yaml支持的一些更灵活的功能(事实上我还真的尝试过),可以说但凡你需要yaml的引用等功能,你都可以用其他方式实现类似效果,而且你需要该功能的可能性也很小,亦或是你需要重新考虑下你的系统是不是过度设计了以至于需要用到这些功能(当然这不是对yaml灵活性的否定,任何技术都有其价值,实际应用时也不必教条)。

总之,我决定使用toml作为配置系统的基底。

灵机一动

那么为什么不干脆直接让应用读取toml配置,并且让应用监听toml文件是否被修改,如果被修改就重新加载配置达到动态调参的目的呢?

这个方案存在缺陷。

如果在一开始给我这个方案,我是不能接受的。

事实上,我暂时连让应用监听toml文件在运行时是否被修改都不打算实现,目前我只会在架构内应用配置文件格式从yaml换成toml.

因为配置系统不是目前具备重要性的开发事项,我应当把时间更高效的利用在价值高的事情上,只有当配置系统实际产生功能需求时,我才需要去实现具体的功能接口,不管是监听toml文件变动,还是接入NATS/Zenoh等工具。

为此,我的代码实现要高内聚低耦合,方便后期快速迭加功能,这是另外一个话题了。

因为经过调研,目前我已经基本明确了后续配置系统框架的设计思路,从yaml切换到toml是目前必须要做的第一步,这和直接确定靠文件驱动应用配置动态更新的方案是有本质不同的,顶层设计的维度不同。

从NATS/Zenoh到文件驱动配置动态更新,这怎么不算第一性原理的应用呢?哈哈哈哈哈哈哈哈。

Categories:

Updated: