我们使用的Squid服务器之前跑得好好的,突然有一天出现了严重的问题:磁盘空间满了,上去一查,发现在/app/squid/var/logs这个目录里面全是core.12345这样的dump文件,而且几乎是每秒钟都要产生这样的dump。通过gdb打开之后发现,几乎每一个dump都出现了类似如下的情况:
Program terminated with signal 6, Aborted.
#0 0x000000373aa30265 in raise () from /lib64/libc.so.6
(gdb) where
#0 0x000000373aa30265 in raise () from /lib64/libc.so.6
#1 0x000000373aa31d10 in abort () from /lib64/libc.so.6
#2 0x00000000004812d1 in fatal_dump ()
#3 0x000000000049c7f9 in xcalloc ()
#4 0x000000000047cc8b in storeKeyDup ()
#5 0x0000000000475b4a in storeHashInsert ()
#6 0x000000000048f280 in storeAufsDirAddDiskRestore ()
#7 0x000000000049092e in storeAufsDirRebuildFromSwapLog ()
#8 0x00000000004375d4 in eventRun ()
#9 0x000000000045da06 in main ()
上面标黄的#3这一行就是问题所在,在其下面的堆栈情况则并不一定。如果你直接搜索xcalloc和squid,几乎是找不到任何线索的。当然,你仔细看网上那些英文帖子的话呢,也会看到有人提示你使用free看看内存是否充足,使用df看看磁盘是否满了。可是你一看,就会发现其实很正常。在Google上搜索这两个关键词,几乎都会指向这样一个Bug,这里面的堆栈和我遇到的问题极度相似。可问题是,人家使用的是3.1系列,而我使用的是2.7系列。而这个BUG的讨论中有人说了,3.1有问题但2.7没有。而且该Bug的描述说的是,如果有人POST了一个很大的文件,超出了内存容量,则可能会出现此错误。但显然,因为这种问题导致频繁当机的可能性太低了,不应该是这个原因。到了这里,似乎又没有任何头绪了。
实际上,如果仔细看第一个帖子,里面还有人贴出了大量的信息,什么Dependencies.txt、Disassembly.txt啊等等。关键的地方其实都不在这些链接里面,而是5楼的回复:
I'm seeing this too; I'm attaching the /var/log/squid-deb- proxy/cache. log, which seems to indicate that squid is attempting to allocate approximately 10PB of memory for swap. This, obviously, fails; hence the abort.
也就是说,在这个cache.log里面会有线索。Linux先进的地方就在于日志真的很多,dump也很多。但问题也很多,尤其是莫名其妙的问题。那么在这个日志文件里面又说了什么呢?在我这里,这个日志大致如下:
FATAL: xcalloc: Unable to allocate 1 blocks of 4112 bytes!
Squid Cache (Version 2.7.STABLE9): Terminated abnormally.
CPU Usage: 23.655 seconds = 11.627 user + 12.028 sys
Maximum Resident Size: 4665232 KB
Page faults with physical i/o: 0
Memory usage for squid via mallinfo():
total space in arena: 1020340 KB
Ordinary blocks: 1020328 KB 38 blks
Small blocks: 0 KB 0 blks
Holding blocks: 166348 KB 8 blks
Free Small blocks: 0 KB
Free Ordinary blocks: 11 KB
Total in use: 1186676 KB 100%
显然,我这里的情况和BUG所导致的症状很不一样。前者每次都是分配一个很小的内存——最低只有24字节,最大也不过几KB;而后者则是分配4035364077 blocks of 1 bytes。这就进一步增加了此问题非彼问题的几率了,可还是不知道问题在哪对不?好在这次又有了另一个新的关键词:FATAL: xcalloc: Unable to allocate 1 blocks of bytes
这个问题一搜索,就发现有不少人报告这个问题,除了上面提到的BUG之外,也有像我这种分配一点点内存即报错的(B贴)。当然,也有中文贴,只不过中文贴貌似真没几个人进来讨论,就更不要抱给点营养的希望了。
除了报Bug之外,还有一些文档说这个问题“通常”跟以下两个问题有关:
- 这个机器的磁盘交换空间用完了;或者
- 这个进程的数据段大小已经达到最大限制了。
对于这两个问题,第一个应该用ps -m或者cat /proc/mem查看。(如果你想知道具体交换文件在哪里,可以用cat /proc/swaps或者swapon -s来查看,坑太多了,这里插播一下。)第二个问题可以通过ulimit -a和ulimit -aH来查看,其中第一个似乎是查看目前的配置,第二个似乎是硬件本身以及kernel编译时的限制。
我执行第一个命令之后,发现空余的交换空间足以将整个进程都交换进去,而正在使用的交换空间则小得可怜(也就100兆),于是第一个问题可以排除。而第二个命令则发现data seg size均设置为unlimited,这个问题也可以排除了。于是这个文档又没有解决问题。
(插播一下,你需要通过运行uname -a来看看你的系统是否64位。如果是32位的系统,也可能会有2G左右的内存大小的限制。)
最后,还是B贴的最后一个说法给出了本问题的终极答案:编译时去掉dlmalloc参数就能解决问题了。而且在这里,你还得到了另一个“有用的”忠告:不要使用你不知道你是否需要的配置参数。这真是一个有用的忠告啊!后面再说这个问题。
真TMD神奇了,这可是从repo下载下来的源代码的默认编译参数啊!那么dlmalloc又是一个什么玩意儿呢?上面那个讨论中说道:
这个参数是为了让那些malloc内存分配函数实现得很糟糕的操作系统所准备的。要知道你是否正好走了这种狗屎运,(在关掉这个参数的情况下,编者注)你会看到Squid不停的增长,但已分配的内存没有变化,而空余内存则一直在增长。
我估计说的是内存地址空间增加,但实际分配的数量很少。相应的,因为内存地址增加导致总虚拟内存增加,而空余内存则因为总虚拟内存-实际分配内存的计算,导致空余内存不停增加的假象。
如果你想知道具体什么是dlmalloc,这篇文章会告诉你这是一个叫做Doug Lea的同志,在1987开始写的内存分配函数。由于该邮件是1996年从德语翻译过来的,所以估计在那时候已经基本稳定了。换句话说,这是一个古董。而这个古董级的文件可能根本就无法分配超过2G的内存,甚至在前面那个B贴中说无法超过1G,而我的实际情况也是似乎无法超过1.2G。可是这个问题在很多地方都没有提及,尤其是中文的编译参数详解说明。
看到了吧,Linux里面可以动的东西很多,坑也就很多。大家一定要注意了,LINUX下面的默认编译安装方式,有可能会要了你的亲命。为了避免出现像我这里描述的问题,去掉默认参数也许都不是稳妥的。因为有可能某些参数一去掉,这种隐藏的Bug是没有了,但性能就急剧下降,甚至你无法证明你的系统必须要有某些参数才能够工作。于是,保险的办法应该是了解都有哪些编译参数,每一个参数是干什么的,你的系统有什么限制,你需要什么样的优化。这才是刚才那句忠告的终极含义!
换句话说,你需要搞清楚什么事内存分配,malloc和dlmalloc的关系,还要英语过硬知道怎么搜索。这,就是一个linux系统应用维护人员所需要具备的基本素质,可不是Windows人员拷贝安装就可以搞定的。这还不包含安装完毕之后的各种配置呢!
没有评论:
发表评论