在测试 GitLab 实例中生成混沌
正如亚马逊网络服务(AWS)CTO Werner Vogels 的名言所说,一切都会失败,时时刻刻都在失败。
作为开发者,考虑软件可能出现的故障模式与考虑正常运行模式同样重要。这样做可能意味着,要么是少数用户遇到零散的 500 错误这种小故障,要么是影响所有用户长时间的网站完全瘫痪,两者之间有天壤之别。
套用 托尔斯泰 的说法,所有正常的服务器都一样,但所有故障的服务器各有各的故障方式。幸运的是,我们有办法尝试模拟这些故障模式,而混沌端点就是协助这一过程的工具。
目前,有四个端点用于模拟以下条件:
- 慢速请求。
- CPU 密集型请求。
- 内存泄漏。
- 意外的进程崩溃。
启用混沌端点
出于显而易见的原因,这些端点在 production 环境中默认不启用。
它们在 development 环境中默认启用。
您必须使用密钥令牌来保护对混沌端点的访问。 除非您完全清楚自己在做什么,否则不应在生产环境中启用它们。
可以通过 GITLAB_CHAOS_SECRET 环境变量设置密钥令牌。
例如,使用 GDK 时,
可以通过以下命令实现:
GITLAB_CHAOS_SECRET=secret gdk start将 secret 替换为您自己的密钥令牌。
调用混沌
启用混沌端点并重启应用程序后,您就可以开始使用这些端点进行测试。
默认情况下,调用混沌端点时,接收请求的 web worker 进程会处理它。这意味着,例如,如果调用了 Kill 操作,处理请求的 Puma worker 进程就会被终止。要在 Sidekiq 中测试这些操作,可以将每个端点的 async 参数设置为 true。这会在 Sidekiq worker 中运行混沌进程。
内存泄漏
要模拟应用程序中的内存泄漏,请使用 /-/chaos/leakmem 端点。
请求完成后,内存不会被保留。请求完成后,Ruby 垃圾回收器会尝试回收这些内存。
GET /-/chaos/leakmem
GET /-/chaos/leakmem?memory_mb=1024
GET /-/chaos/leakmem?memory_mb=1024&duration_s=50
GET /-/chaos/leakmem?memory_mb=1024&duration_s=50&async=true| 属性 | 类型 | 必需 | 描述 |
|---|---|---|---|
memory_mb |
integer | 否 | 应泄漏多少内存,单位为 MB。默认为 100 MB。 |
duration_s |
integer | 否 | 内存应保留的最小持续时间,单位为秒。默认为 30 秒。 |
async |
boolean | 否 | 设置为 true 以在 Sidekiq 后台 worker 进程中泄漏内存 |
curl "http://localhost:3000/-/chaos/leakmem?memory_mb=1024&duration_s=10" \
--header 'X-Chaos-Secret: secret'
curl "http://localhost:3000/-/chaos/leakmem?memory_mb=1024&duration_s=10&token=secret"CPU 旋转
此端点尝试在给定时间内完全使用单个核心,使用率为 100%。
根据您的 rack 服务器设置,您的请求可能在预定时间后超时(通常为 60 秒)。
GET /-/chaos/cpu_spin
GET /-/chaos/cpu_spin?duration_s=50
GET /-/chaos/cpu_spin?duration_s=50&async=true| 属性 | 类型 | 必需 | 描述 |
|---|---|---|---|
duration_s |
integer | 否 | 核心被使用的持续时间,单位为秒。默认为 30 秒 |
async |
boolean | 否 | 设置为 true 以在 Sidekiq 后台 worker 进程中消耗 CPU |
curl "http://localhost:3000/-/chaos/cpu_spin?duration_s=60" \
--header 'X-Chaos-Secret: secret'
curl "http://localhost:3000/-/chaos/cpu_spin?duration_s=60&token=secret"DB 旋转
此端点尝试在给定时间内完全使用单个核心,并交错执行 DB 请求。 此端点可用于模拟并发运行时将执行权让渡给其他线程的情况。
根据您的 rack 服务器设置,您的请求可能在预定时间后超时(通常为 60 秒)。
GET /-/chaos/db_spin
GET /-/chaos/db_spin?duration_s=50
GET /-/chaos/db_spin?duration_s=50&async=true| 属性 | 类型 | 必需 | 描述 |
|---|---|---|---|
interval_s |
float | 否 | 每次 DB 请求的间隔时间,单位为秒。默认为 1 秒 |
duration_s |
integer | 否 | 核心被使用的持续时间,单位为秒。默认为 30 秒 |
async |
boolean | 否 | 设置为 true 以在 Sidekiq 后台 worker 进程中执行操作 |
curl "http://localhost:3000/-/chaos/db_spin?interval_s=1&duration_s=60" \
--header 'X-Chaos-Secret: secret'
curl "http://localhost:3000/-/chaos/db_spin?interval_s=1&duration_s=60&token=secret"休眠
此端点类似于 CPU Spin 端点,但模拟的是处理器外部的活动,例如对后端服务的网络调用。它会休眠指定的 duration_s 时间。
与 CPU Spin 端点一样,如果 duration_s 超过配置的限制,这可能导致您的请求超时。
GET /-/chaos/sleep
GET /-/chaos/sleep?duration_s=50
GET /-/chaos/sleep?duration_s=50&async=true| 属性 | 类型 | 必需 | 描述 |
|---|---|---|---|
duration_s |
integer | 否 | 请求休眠的持续时间,单位为秒。默认为 30 秒 |
async |
boolean | 否 | 设置为 true 以在 Sidekiq 后台 worker 进程中休眠 |
curl "http://localhost:3000/-/chaos/sleep?duration_s=60" \
--header 'X-Chaos-Secret: secret'
curl "http://localhost:3000/-/chaos/sleep?duration_s=60&token=secret"终止
此端点使用 KILL 信号模拟 worker 进程的意外终止。
由于此端点使用 KILL 信号,进程没有机会进行清理或关闭。
GET /-/chaos/kill
GET /-/chaos/kill?async=true| 属性 | 类型 | 必需 | 描述 |
|---|---|---|---|
async |
boolean | 否 | 设置为 true 以向 Sidekiq 后台 worker 进程发送信号 |
curl "http://localhost:3000/-/chaos/kill" --header 'X-Chaos-Secret: secret'
curl "http://localhost:3000/-/chaos/kill?token=secret"退出
此端点使用 QUIT 信号模拟 worker 进程的意外终止。
与 KILL 不同,QUIT 信号还会尝试写入核心转储。
更多信息请参见 core(5)。
GET /-/chaos/quit
GET /-/chaos/quit?async=true| 属性 | 类型 | 必需 | 描述 |
|---|---|---|---|
async |
boolean | 否 | 设置为 true 以向 Sidekiq 后台 worker 进程发送信号 |
curl "http://localhost:3000/-/chaos/quit" --header 'X-Chaos-Secret: secret'
curl "http://localhost:3000/-/chaos/quit?token=secret"运行垃圾回收器
此端点触发处理请求的 worker 上的 GC 运行,并返回其 worker ID 和 GC 统计信息作为 JSON。这在独立模式下运行 Puma 时特别有用,因为否则无法预先知道处理请求的 worker。
端点:
POST /-/chaos/gc示例请求:
curl --request POST "http://localhost:3000/-/chaos/gc" \
--header 'X-Chaos-Secret: secret'
curl --request POST "http://localhost:3000/-/chaos/gc?token=secret"示例响应:
{
"worker_id": "puma_1",
"gc_stat": {
"count": 94,
"heap_allocated_pages": 9077,
"heap_sorted_length": 9077,
"heap_allocatable_pages": 0,
"heap_available_slots": 3699720,
"heap_live_slots": 2827510,
"heap_free_slots": 872210,
"heap_final_slots": 0,
"heap_marked_slots": 2827509,
"heap_eden_pages": 9077,
"heap_tomb_pages": 0,
"total_allocated_pages": 9077,
"total_freed_pages": 0,
"total_allocated_objects": 14229357,
"total_freed_objects": 11401847,
"malloc_increase_bytes": 8192,
"malloc_increase_bytes_limit": 30949538,
"minor_gc_count": 71,
"major_gc_count": 23,
"compact_count": 0,
"remembered_wb_unprotected_objects": 41685,
"remembered_wb_unprotected_objects_limit": 83370,
"old_objects": 2617806,
"old_objects_limit": 5235612,
"oldmalloc_increase_bytes": 8192,
"oldmalloc_increase_bytes_limit": 122713697
}
}