设计应用程序以支持配置更改而无需重新启动
Designing application to support config changes without restart
有哪些方法可以将应用程序设计为无需重新启动应用程序即可更改配置?
一种方法是只拥有一个带有配置的平面文件,然后应用程序在需要特定值时从配置中读取并且从不在内存中存储任何配置值。
另一种选择是允许应用程序加载一次配置文件并将值存储在内存中,然后定期重新加载配置文件以防发生变化。
碰巧我最近更新了我的一个免费软件包来做到这一点。我采用的方法略有不同。
1) 我的应用程序加载其配置、解析它并将其存储在内存中。每次应用程序需要某些配置设置的值时,我不会读取配置设置。
2) 但是,除了配置设置,我还存储了配置文件本身的时间戳。
3) 当应用程序响应事件而醒来,并且有事情要做时,它会检查配置文件的时间戳。如果它没有改变,则不采取进一步的行动。 stat(2) 系统调用轻量级、廉价且快速,并且增加的开销很少。
4) 如果stat(2)
告诉我配置文件的时间戳已经改变,应用程序会再次读取配置文件。
配置文件作为其格式的一部分,包括一个明确的 "end of configuration" 标记。如果我的应用程序没有看到它,这意味着我应该出去玩下一张彩票,因为我设法遇到了一个极其罕见的竞争条件,在这种情况下,当我的应用程序以某种方式结束读取一个新的配置文件时正在被我同时编辑配置文件的编辑器保存!
如果代码没有看到 "end of configuration" 标记,则在应用程序下次唤醒并检查配置文件的时间戳之前不会采取进一步的操作。
5) 读取并解析新的配置文件后,我验证新的配置设置。一些内部健全性检查发生在这里。如果完整性检查失败,则在向系统日志报告错误后不会采取进一步操作。
6) 只有在完整性检查通过后,previously-stored 配置设置和值才会被从新配置文件中读取的更新值以及新配置文件的更新时间戳所取代。下次再见。
P.S。保存的配置设置受互斥锁保护。当应用程序需要检查特定配置设置的值时,它会持有互斥量。第 6 步还获取足够长的互斥锁,以用 newly-validated 更新的配置设置替换当前配置设置。
为避免轮询,请考虑使用来自操作系统的通知来了解您的配置文件何时被修改。大多数操作系统都提供可以执行此操作的 API:
- Linux: inotify
- Windows: ReadDirectoryChangesW
- Mac: FSEvents
Sam Varshavchik 的回答包含很多好的建议。但是,还有一点值得一提...
您的配置 class 的 public API 将提供一种或多种 lookup()
风格的方法,用于检索配置值。为确保线程安全,您必须确保这些lookup()
方法return底层配置值的深拷贝(而不是pointer/reference) .例如,如果 returning 一个字符串,那么 return 类型应该是 std::string
而不是 const std::string &
或 const char *
.
有哪些方法可以将应用程序设计为无需重新启动应用程序即可更改配置?
一种方法是只拥有一个带有配置的平面文件,然后应用程序在需要特定值时从配置中读取并且从不在内存中存储任何配置值。
另一种选择是允许应用程序加载一次配置文件并将值存储在内存中,然后定期重新加载配置文件以防发生变化。
碰巧我最近更新了我的一个免费软件包来做到这一点。我采用的方法略有不同。
1) 我的应用程序加载其配置、解析它并将其存储在内存中。每次应用程序需要某些配置设置的值时,我不会读取配置设置。
2) 但是,除了配置设置,我还存储了配置文件本身的时间戳。
3) 当应用程序响应事件而醒来,并且有事情要做时,它会检查配置文件的时间戳。如果它没有改变,则不采取进一步的行动。 stat(2) 系统调用轻量级、廉价且快速,并且增加的开销很少。
4) 如果stat(2)
告诉我配置文件的时间戳已经改变,应用程序会再次读取配置文件。
配置文件作为其格式的一部分,包括一个明确的 "end of configuration" 标记。如果我的应用程序没有看到它,这意味着我应该出去玩下一张彩票,因为我设法遇到了一个极其罕见的竞争条件,在这种情况下,当我的应用程序以某种方式结束读取一个新的配置文件时正在被我同时编辑配置文件的编辑器保存!
如果代码没有看到 "end of configuration" 标记,则在应用程序下次唤醒并检查配置文件的时间戳之前不会采取进一步的操作。
5) 读取并解析新的配置文件后,我验证新的配置设置。一些内部健全性检查发生在这里。如果完整性检查失败,则在向系统日志报告错误后不会采取进一步操作。
6) 只有在完整性检查通过后,previously-stored 配置设置和值才会被从新配置文件中读取的更新值以及新配置文件的更新时间戳所取代。下次再见。
P.S。保存的配置设置受互斥锁保护。当应用程序需要检查特定配置设置的值时,它会持有互斥量。第 6 步还获取足够长的互斥锁,以用 newly-validated 更新的配置设置替换当前配置设置。
为避免轮询,请考虑使用来自操作系统的通知来了解您的配置文件何时被修改。大多数操作系统都提供可以执行此操作的 API:
- Linux: inotify
- Windows: ReadDirectoryChangesW
- Mac: FSEvents
Sam Varshavchik 的回答包含很多好的建议。但是,还有一点值得一提...
您的配置 class 的 public API 将提供一种或多种 lookup()
风格的方法,用于检索配置值。为确保线程安全,您必须确保这些lookup()
方法return底层配置值的深拷贝(而不是pointer/reference) .例如,如果 returning 一个字符串,那么 return 类型应该是 std::string
而不是 const std::string &
或 const char *
.