今天早上,我们发现我们的 Web 服务器(称为 host1)的 CPU 利用率和负载大幅增加。总体 CPU 使用率从大约 100% 上升到 500%(16 个内核,32 个超线程),负载从平均 < 1 上升到 ~6。然后它保持在该增加的水平。使用 top,很明显增加的 CPU 使用率全部来自 Apache(httpd 进程)。(我们使用的是 CentOS 7.6 上的 Apache 2.4.39。)
PHP 进程和 mariadb 连接均与基线水平持平。通过服务器网络连接传输的数据保持不变。基于服务器 domlog 行数的每分钟请求数保持不变。磁盘利用率、等待时间或服务时间均未增加。内存使用量也持平。
我检查了负载突然上升时的 Apache 错误日志,没有看到任何新内容,而且 Apache 当时也没有重新启动。
作为测试,我将我们所有的网络流量从 host1 移至一台实际上完全相同的备份服务器 host2。一旦流量迁移完毕,host1 的 CPU 使用率就会降至接近零(此时下降了约 400%),而 host2 上的使用率仅上升到约 80%,大约相当于 host1 在突然上升之前的运行水平。因此,无论发生什么变化,都与该特定服务器有关,而不是与我们网络流量的性质有关。
我检查了两台服务器上的 apache 配置,正如预期的那样,它们是相同的。查看 apache 状态,主机 1 上的并发连接数似乎大约是主机 2 上的两倍。考虑到更高的负载/CPU 使用率,这是意料之中的。处理请求需要更长的时间,因此在相同的吞吐量下,我们有更多的并发连接。主观上,似乎某些请求在主机 1 上在正常时间内返回,而其他请求则比平时花费的时间长得多(秒而不是预期的毫秒)。但这可能是负载增加的原因或结果。
我尝试在 host1 上禁用 mod_security,并排除了这是原因。接下来,我尝试完全重新启动 host1,但在将流量转移回来后,高负载仍然存在。还有什么可能导致特定服务器上的 apache 突然持续使用更多 CPU 并花费更长时间处理相同数量的请求?
编辑:无论就其价值而言,系统和用户的 CPU 使用率都成比例增加。
编辑2:perf top 的结果:
Samples: 905K of event 'cycles:ppp', Event count (approx.): 111054988919
Overhead Shared Object Symbol
16.69% [kernel] [k] system_call_after_swapgs
11.02% [kernel] [k] sysret_check
5.64% [kernel] [k] copy_user_enhanced_fast_string
3.79% [kernel] [k] fget_light
3.04% [kernel] [k] __audit_syscall_exit
3.01% [kernel] [k] generic_file_aio_read
2.51% [kernel] [k] __audit_syscall_entry
1.78% [kernel] [k] sys_lseek
1.63% [kernel] [k] __radix_tree_lookup
1.45% [kernel] [k] sys_read
1.43% libpthread-2.17.so [.] __pthread_disable_asynccancel
1.32% [kernel] [k] touch_atime
1.28% [kernel] [k] ext4_file_read
1.23% [kernel] [k] radix_tree_descend
1.11% [kernel] [k] mutex_lock
1.08% [kernel] [k] vfs_read
1.04% [kernel] [k] file_read_actor
0.95% libapr-1.so.0.6.5 [.] apr_file_read
0.85% [kernel] [k] do_sync_read
0.84% [kernel] [k] __d_lookup_rcu
0.81% [kernel] [k] __x86_indirect_thunk_rax
0.79% [kernel] [k] fsnotify
0.78% [kernel] [k] generic_segment_checks
0.77% [kernel] [k] __check_object_size
0.74% [kernel] [k] current_kernel_time
0.73% libapr-1.so.0.6.5 [.] apr_file_read_full
0.71% [kernel] [k] put_page
0.70% [kernel] [k] ext4_llseek
0.70% php-fpm [.] execute_ex
0.69% libaprutil-1.so.0.6.1 [.] getpage
0.65% [kernel] [k] _cond_resched
0.64% libaprutil-1.so.0.6.1 [.] read_from
0.59% [kernel] [k] strncpy_from_user
0.59% libpthread-2.17.so [.] llseek
0.57% [kernel] [k] __fsnotify_parent
0.57% [kernel] [k] cleanup_module
0.55% [kernel] [k] rw_verify_area
0.55% [kernel] [k] __find_get_page
0.51% [kernel] [k] auditsys
0.51% [kernel] [k] security_file_permission
0.48% php-fpm [.] _is_numeric_string_ex
0.47% [kernel] [k] unroll_tree_refs
0.47% libapr-1.so.0.6.5 [.] apr_file_seek
0.42% [kernel] [k] generic_file_llseek_size
0.41% [kernel] [k] fput
0.40% php-fpm [.] zend_hash_find
0.35% [kernel] [k] __virt_addr_valid
0.30% [kernel] [k] path_put
0.27% libaprutil-1.so.0.6.1 [.] getnext
0.27% libz.so.1.2.7 [.] 0x0000000000002d11
0.27% [kernel] [k] tracesys
0.27% [unknown] [k] 0x00002af9a2716d7b
0.27% [kernel] [k] lookup_fast
0.25% [kernel] [k] mutex_unlock
0.25% [kernel] [k] kfree
0.24% [kernel] [k] current_fs_time
为了进行比较,以下是我们另一台服务器 host2 的结果,该服务器正在处理相当数量的网络流量以及当前我们所有的数据库,并且没有遇到这种高负载问题:
Samples: 1M of event 'cycles:ppp', Event count (approx.): 104427407206424
Overhead Shared Object Symbol
27.34% [kernel] [k] retint_userspace_restore_args
13.57% php-fpm [.] zend_do_inheritance
7.56% [kernel] [k] handle_mm_fault
7.56% httpd [.] 0x000000000004470e
6.87% libpthread-2.17.so [.] pthread_cond_broadcast@@GLIBC_2.3.2
4.43% [kernel] [k] cpuidle_enter_state
3.31% libc-2.17.so [.] __memmove_ssse3_back
3.31% [unknown] [.] 0x00002b8a4d236777
2.68% [kernel] [k] cap_inode_permission
2.09% libperl.so [.] S_refto
2.09% [unknown] [k] 0x00007f4479518900
1.37% [kernel] [k] free_pages_prepare
1.20% [kernel] [k] hrtimer_interrupt
0.90% [kernel] [k] irq_return
0.89% [kernel] [k] change_pte_range
0.76% httpd [.] ap_find_command
0.69% [unknown] [k] 0x00007fe15a923be8
0.68% [kernel] [k] lookup_fast
0.60% libperl.so [.] Perl_runops_standard
0.60% libperl.so [.] Perl_pp_multideref
0.60% [unknown] [.] 0x00007f227838a777
0.55% [kernel] [k] system_call_after_swapgs
0.46% [unknown] [.] 0x00007f18e7736015
0.45% libc-2.17.so [.] __memcpy_ssse3_back
0.40% mysqld [.] 0x0000000000b643c4
0.40% ld-2.17.so [.] _dl_map_object_deps
0.39% [unknown] [.] 0x00007f81151f761c
0.35% [kernel] [k] kmem_cache_alloc
0.35% [kernel] [k] vma_interval_tree_insert
0.30% [kernel] [k] _raw_spin_lock_irqsave
0.30% libc-2.17.so [.] __readdir_r
0.30% [kernel] [k] tick_do_update_jiffies64
0.30% libpng15.so.15.13.0 [.] 0x000000000001ff7f
0.30% [unknown] [.] 0x00007f2a3ffee13c
0.30% libpthread-2.17.so [.] __ctype_init@plt
0.26% libc-2.17.so [.] _int_malloc
0.26% libc-2.17.so [.] malloc
0.26% libc-2.17.so [.] malloc_consolidate
0.26% [kernel] [k] mem_cgroup_charge_common
0.26% libperl.so [.] Perl_hv_common
0.26% [kernel] [k] pid_revalidate
0.26% libperl.so [.] Perl_sv_eq_flags
0.26% libcairo.so.2.11512.0 [.] 0x000000000004bf43
0.26% libperl.so [.] S_dopoptosub_at
0.26% libcairo.so.2.11512.0 [.] 0x00000000000d059a
但是,就顶级功能而言,host2 的变化更大;这只是一个例子。host1(有问题的主机)在列表中具有非常稳定的前几个条目。
编辑 3:将问题追溯到 mod security 后,我发现它似乎与 IP 地址数据库 /tmp/ip.pag 有关,尽管我们已设置修剪超时,但该数据库仍在无限增长。清除此文件可解决高 CPU 使用率问题,而无需完全禁用 mod security。但是,如果我们继续使用基于 IP 的规则,它可能会再次增长,因此我们正在考虑修改规则,或者可能只是设置每日 cron 来清除文件中的任何旧 IP。
答案1
首先进行健全性检查,看看内核是否试图告诉您一些事情。可能是关于存储系统的,因为存储堆栈出现了样本。查看dmesg
syslog 日志文件的输出。
您的问题主机在内核上花费了更多时间。相比之下,php-fpm 和 httpd 位列前 5 名的其他主机则不然。大多数工作负载在用户空间中执行有用的服务,因此较低的内核开销是件好事。
注意在审计接口。我认为审计系统也使用 fsnotify。查看任何审计规则,包括文件系统和系统调用。审计所有读取之类的操作都非常昂贵。请参阅 auditd 包的文档,了解一些场景中的有针对性审计的示例。
如果你进一步分析,就可以了解 Linux 正在做什么的很多细节。使用perf 统计系统调用. 也有可能得到火焰图可视化中的整个调用图。
编辑:如果您有符号,这些火焰图在高 CPU 利用率场景中特别有用。您可以将其与问题报告中的问题堆栈进行比较,并进一步深入研究耗时较长的特定函数。
安装yum-utils
并使用它安装符号:( debuginfo-install --enablerepo=base-debuginfo httpd
这是一个方便的脚本,因此您不必知道 -debuginfo 后缀约定。)
你发现了ModSecurity 问题自发导致 CPU 使用率过高 #890。我实际上还没有在您的火焰图上看到这样的堆栈。但是,如果您安装了调试符号,您可以看到 APR、模块代码和操作系统内核之间的交互,而不仅仅是其中之一。