最近我遇到了 snmpd 服务的问题。我有一个运行 CentOS 6.9 的 Linux 机器,当我在 localhost 上发出 snmpwalk 时,通常我得到的只是超时,然后我尝试添加 10 秒的超时值,结果更好,但仍然慢得令人痛苦。我决定使用 strace 深入研究内核,发现 snmpd 服务在响应 snmp 请求之前会尝试多次调用 gettimeofday。与运行 Debian 8 和 Centos 6.3 的其他 Linux 机器相比,它们的 snmpd 服务根本不调用 gettimeofday。这是我得到的结果:
rpm --query centos-release
centos-release-6-9.el6.12.3.x86_64
service snmpd status
snmpd (pid 28244) is running...
strace -r -e trace=gettimeofday -p 28244
Process 28244 attached
0.000000 gettimeofday({1516589055, 372419}, NULL) = 0
0.000048 gettimeofday({1516589055, 372448}, NULL) = 0
0.000015 gettimeofday({1516589055, 372463}, NULL) = 0
0.000015 gettimeofday({1516589055, 372477}, NULL) = 0
0.003271 gettimeofday({1516589055, 375751}, NULL) = 0
0.000013 munmap(0x7f1950abf000, 4096) = 0
0.000086 open("/proc/sys/net/ipv6/conf/eth3/forwarding", O_RDONLY) = 11
0.000028 fstat(11, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
0.000015 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1950abf000
0.000015 read(11, "0\n", 1024) = 2
0.000017 close(11) = 0
0.000012 munmap(0x7f1950abf000, 4096) = 0
0.000017 open("/proc/sys/net/ipv6/neigh/eth3/base_reachable_time_ms", O_RDONLY) = 11
0.000017 fstat(11, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
0.000013 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1950abf000
0.000014 read(11, "30000\n", 1024) = 6
0.000016 close(11) = 0
0.000012 munmap(0x7f1950abf000, 4096) = 0
0.000015 read(9, "", 1024) = 0
0.000026 close(9) = 0
0.000015 munmap(0x7f1950ac0000, 4096) = 0
0.000014 close(10) = 0
0.000028 gettimeofday({1516099695, 497691}, NULL) = 0
0.000015 gettimeofday({1516099695, 497705}, NULL) = 0
0.000012 gettimeofday({1516099695, 497718}, NULL) = 0
0.000016 gettimeofday({1516099695, 497734}, NULL) = 0
0.000012 gettimeofday({1516099695, 497746}, NULL) = 0
0.000013 gettimeofday({1516099695, 497758}, NULL) = 0
与另一个运行 CentOS 6.3 的 Linux 机器上 snmpd 服务的 strace 结果进行比较:
rpm --query centos-release
centos-release-6-3.el6.centos.9.x86_64
Process 4566 attached - interrupt to quit
0.000000 select(10, [4 6 7 9], [], [], {1, 160003}) = 0 (Timeout)
1.161298 open("/proc/diskstats", O_RDONLY) = 10
0.000109 fstat(10, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
0.000245 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f6e1d035000
0.000047 read(10, " 1 0 ram0 0 0 0 0 0 0 0 "..., 1024) = 1024
0.000109 read(10, "0 sda 240731 163874 8048386 2853"..., 1024) = 611
0.000061 read(10, "", 1024) = 0
0.000023 close(10) = 0
0.000064 munmap(0x7f6e1d035000, 4096) = 0
0.000036 open("/proc/stat", O_RDONLY) = 10
0.000034 read(10, "cpu 3775592 27347 3516548 70619"..., 4095) = 866
0.000056 close(10) = 0
0.000028 open("/proc/vmstat", O_RDONLY) = 10
0.000031 read(10, "nr_free_pages 75722\nnr_inactive_"..., 4095) = 1964
0.000042 close(10) = 0
0.000037 select(10, [4 6 7 9], [], [], {4, 999068}) = 0 (Timeout)
5.003442 open("/proc/diskstats", O_RDONLY) = 10
0.000082 fstat(10, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
0.000034 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f6e1d035000
0.000029 read(10, " 1 0 ram0 0 0 0 0 0 0 0 "..., 1024) = 1024
0.000126 read(10, "0 sda 240731 163874 8048386 2853"..., 1024) = 611
0.000045 read(10, "", 1024) = 0
0.000023 close(10) = 0
0.000076 munmap(0x7f6e1d035000, 4096) = 0
0.000036 open("/proc/stat", O_RDONLY) = 10
0.000037 read(10, "cpu 3775592 27347 3516551 70619"..., 4095) = 866
0.000084 close(10) = 0
0.000045 open("/proc/vmstat", O_RDONLY) = 10
0.000035 read(10, "nr_free_pages 75722\nnr_inactive_"..., 4095) = 1964
0.000100 close(10) = 0
0.000055 select(10, [4 6 7 9], [], [], {2, 88417}
是否有任何我可能不知道的特定配置,使 snmpd 服务在响应请求之前多次调用 gettimeofday?
提前致谢。
答案1
显然存在一些问题,设置 TZ 变量可以拯救你数千由于时间库的编码方式而导致的系统调用。
它们实际上与您的问题有关,因此我需要反馈。
为了避免在您不会更新时区(或者可以在更新时区时重新启动进程)的服务器进程上进行额外的系统调用,只需将 TZ 环境变量设置为 :/etc/localtime (或您选择的其他时区文件)即可过程。这将导致 glibc 避免进行额外的(和不必要的)系统调用。
原来glibc中的localtime函数会检查TZ环境变量是否设置。如果没有设置(我测试过的两个Ubuntu都没有设置),那么glibc每次调用localtime时都会使用stat系统调用。
换句话说:你的系统支持通过Linux内核的vDSO调用时间系统调用,以避免切换到内核的成本。但是,一旦您的程序调用 time,它就会立即调用 localtime,这无论如何都会调用系统调用。因此,您已经使用 vDSO 消除了一个系统调用,而是用另一个系统调用替换了它。
请注意,文件访问通常也使用与时间相关的系统调用。尝试在 SNMP 的配置文件中使用数字 MIBS 而不是其名称。 (它可能只在开始时产生影响snmpd
,之后不会产生太大影响)。
由于新文件访问利用与时间相关的系统调用,因此在启动时您会看到其中一些是正常的snmpd
- 您可能会将未安装 MIB 的系统与另一个安装了 MIB 的系统进行比较。