规模 Pipelines

流水线的主要瓶颈之一是它 FREQUENTLY 将临时数据写入磁盘,以便于运行流水线能够处理意外的Jenkins重启或系统崩溃。对于许多用户来说,这种持久性是有用,但是它的性能成本是一个问题。

流水线现在包含了一些特性,通过减少写入磁盘的数据的量以及写入磁盘的频率 使用户提高耐用的性能— 以一个小的成本。在一些特殊情况下,如果Jenkins突然关闭,用户没有获得写入数据的机会,就可能无法恢复或可视化正在运行的流水线。由于这些设置包括速度与持久性的权衡,他们最初是选择性加入的。 为了启用性能优化模式, 用户需要明确设置流水线的 Speed/Durability Setting 。 如果没有明确的选择, 流水线目前默认为 "最大持久性" 设置并像过去一样写入磁盘中。 在相同的插件版本中有一些 I/O 优化, 但好处要小得多。

如何设置速度/持久性设置?

有 3 种方式配置持久性设置:

  • Globally, 在 "管理Jenkins" > "系统配置"下你可以选择一个全局默认 durability设置 , 标记 "流水线速度/持久性设置"。 你可以使用下面这些更具体的设置覆盖这些内容。

  • Per pipeline job: 在作业配置的顶部, 标记 "自定义流水线速度/持久性级别" - 它会覆盖全局设置。或者, 使用 "属性" 步骤 - 该设置将会应用到该步骤执行后的下一次运行(相同的结果)。

  • Per-branch for a multibranch project: 配置自定义分支属性策略 (在SCM下)并为自定义流水线速度/持久性级别添加属性。它会覆盖全局设置。 你还可以使用 "属性" 步骤来覆盖设置,但请记住,你可能需要再次运行该步骤来撤销该设置。

持久性设置将会影响下一次适用的流水线运行, 而不是立即。 该设置将会显示在日志中。

更高性能的持久性设置能帮助我吗?

  • 是的, 如果你的 Jenkins 实例使用 NFS,磁存储, 同时运行许多流水线, 或者显示高的 iowait.

  • 是的, 如果你运行带有许多步骤(超过几百个)的流水线。

  • 是的, 如果你的流水线存储大型文件或复杂数据到脚本的变量中, 保存这些变量在将来使用的范围内, 然后运行步骤。 这听起来很奇怪,但是发生的比你想象的要多。

  • 例如: 带有一个大的 XML/JSON文件的readFile 步骤 ,或者使用来自解析 One of the Utility Steps这样的文件的配置信息。

  • 另一个常见的模式是包含来自许多分支 (日志, 结果, 或统计数据)的数据的"summary" 对象。由于你将经常通过添加/附加或 Map.put() 操作添加它,通常这是可见的。

  • 数据的大数组或配置信息的 Map是这种情况的另一个常见示例。

  • 不, 如果你的流水线花费几乎所有的时间等待shell/批处理脚本完成。这不是万能的 "go fast" 按钮!

  • 不, 如果流水线将大量数据写入日志(日志记录不变)。

  • 不, 如果你不使用流水线, 或者你的系统被其他因素加载。

  • 不, 如果你没有为流水线启用更高性能的模式。

为什么放弃持久性设置"权衡?"

Stability of Jenkins ITSELF is not changed regardless of this setting - 它只适用于流水线。最坏的情况是类似于自由构建—​运行不能持久存储数据的流水线可能无法恢复或显示在 Blue Ocean/阶段视图等,但会显示日志。这 only 影响到运行的流水线,而且只有当Jenkins被突然关闭,并且在它们完成之前没有优雅地关闭。

"graceful" shutdown是Jenkins完全关闭进程的地方, 比如访问 http://[jenkins-server]/退出, 或者使用正常的服务关闭脚本(如果 Jenkins健壮)。 发送一个 SIGTERM/SIGINT 到 Jenkins会触发一个优雅的关闭。 注意:运行流水线不需要完成(你不需要use /safeExit来关闭)。

"dirty" shutdown 是当 Jenkins没有进行正常的关机过程时。如果进程被强制终止,就会发生这种情况。最常见的原因是使用 SIGKILL 终止 Jenkins 进程或杀死运行Jenkins的容器/VM 。只要Jenkins 进程能够恢复,,简单的停止或暂停容器/VM 不会造成这种情况。由于灾难性的系统操作故障(包括 Linux OOMKiller攻击Jenkins的java 进程以释放内存),脏关闭也有可能会发生。

Atomic writes:**except** "最大持久性"之外的所有设置都避免了原子写入 —这意味着如果操作系统运行Jenkins失败, 写到磁盘的缓存数据不会被刷新, 它将会丢失。 这种情况非常少见, 容器或虚拟化操作停止操作系统或断开存储可能会造成这种情况。 通常这些数据会被很快地刷新到磁盘, 所以数据丢失的窗口是简短的。 在 Linux 上,刷新到磁盘可以通过运行’sync’强制执行。在一些汉奸的情况下,这也会导致无法加载的构建。

使用持久性配置的配置要求

  • Jenkins LTS 2.73+ 或以上版本 (或者 weekly 2.62+)

  • 下面的all流水线插件 , 至少安装指定的最低版本:

  • 流水线: API (workflow-api) v2.25

  • 流水线: Groovy (workflow-cps) v2.43

  • 流水线: Job (workflow-job) v2.17

  • 流水线: Supporting APIs (工作流支持) v2.17

  • 流水线: 多分支 (工作流多分支) v2.17 - 可选, 只需要为多分支流水线启动该设置。

  • 重启主机来使用更新的插件 - 注意: 你需要使用这些所有插件。

持久性配置是什么?

  • P性能优化模式 ("PERFORMANCE_OPTIMIZED") - Greatly 减少磁盘 I/O。 如果流水线没有完成 ,Jenkins 没有优雅地关闭, 它们可能会像上面的自由式项目一样丢失数据 — 在上面查看细节。

  • 最大持久性 ("MAX_SURVIVABILITY") - 像之前的流水线中所做的那样, 最慢的选项。 使用它来运行你最重要的流水线。

  • 不那么持久, 晒微快一些("SURVIVABLE_NONATOMIC") -每一步都写入数据,但是避免了原子写入。 这比更大耐久性模块要快, 尤其是在网络文件系统上。它带有一个额外的风险(在上面的 "为什么我放弃了: 原子写入"有详细说明)。

推荐的最佳实践和持久性配置

  • 对大多数流水线使用 "性能优化" 模式 ,尤其是基本的构建测试流水线或任何可以在需要时再次运行的东西。

  • 使用 "最大持久性" 和 "不那么持久" 的流水线模式 ,你需要你需要有保证的执行记录(auditing). 这些记录运行在每一步。

  • 当流水线修改关键基础设施的状态时,使用 "最大持久性" 和 "不那么持久"。比如, 用于产品部署。

  • 为持久性设置设置"性能优化"的全局默认值 (见上文), 然后 在特定的流水线作业或多分支流水线的分支 ("主分支" 或发布分支)中设置 "最大持久性"。

  • 你可以强制地让流水线暂停来保存数据。

其他规模建议

  • Whenever possible, run Jenkins with fast SSD-backed storage and not hard drives. This can make a huge difference.

  • 一般来说,将工具和作业联系起来。当使用构建代理运行一个复杂的过程时, 写一个简短的 Shell/Batch/Groovy/Python 脚本。 Good examples 包括处理数据, 与REST API交互, 和 解析/模板 大型的 XML 或 JSON 文件。 shbat 有助于调用这些步骤, 尤其是 returnStdout: true 返回该脚本的输出并将其保存为变量(脚本化流水线)。

  • 流水线 DSL 不是为任意的网络和计算任务 - 它是为CI/CD 脚本编写的。
  • 如果条件允许 ,使用流水线插件和脚本安全的最新版本,这些包含了定期的性能提高。

  • 尝试通过减少运行的步骤数量和使用更简单的 Groovy 代码来简化脚本化流水线的代码。

  • 如果可以的话,合并相同类型的顺序步骤, 比如通过使用 Shell步骤 来调用helper脚本而不是运行多个步骤。

  • 尝试通过流水线限制写入日志的数据量。如果你正在编写几MB的日志数据, 比如来自构建工具, 将它写入到外部文件, 压缩它, 并将它存档为构建组件。

  • 在使用超过6MB堆的Jenkins时,使用 建议的垃圾收集调优选项 来减少垃圾收集的暂停时间和开销。