作者:任坤 现居珠海,先后担任专职Oracle和MySQLDBA,现在主要负责MySQL、mongoDB和Redis维护工作。 本文来源:原创投稿 爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。1、背景 上班时间收到一条磁盘空间报警 登录该机器查看,根分区只有不到16G,此刻已经使用超过了80。 查看根分区下最大的10个文件并按照size降序排列duSmexcludedatasortk1nrhead10 这条命令在其他环境执行几秒钟就返回了,在这个机器上执行了将近1分钟,最后定位到是几个日志文件,直接删除即可。 刚准备退出登录,又收到一条内存报警,还是这台机器。 2、诊断 查看内存使用情况,确实已经被耗尽 top查看最耗内存的几个进程 消耗内存每多的mysqld只占用了43G,就算加上截图中的其他几个进程,顶多占用44G。为避免漏算,统计一下所有进程占用的物理内存总和:〔rootcentos6564220〕moreRSS。shbinbashforPROCinlsprocgrep〔09〕doif〔fprocPROCstatm〕;thenTEPcatprocPROCstatmawk{print(2)}RSSexprRSSTEPfidoneRSSexprRSS410241024echoRSSGB〔rootcentos6564220〕shRSS。sh44GB 注:该脚本来自于褚霸多年前的一篇文章http:blog。yufeng。infoarchives2456 问题来了,剩余的10多G内存被谁占用了?top和ps都给不出答案,只能查看procmeminfo文件 注意红框中的信息,slab消耗了太多的缓存,且都是可回收的,看大小正好有16G左右。 联想到刚刚执行的巨慢的duSm命令,答案似乎很明显了。 执行slabtop dentry和inode占用了很多内存,但是输出结果不够直观。 查看超过100M的slab缓存组件〔rootcentos6564220〕catprocslabinfoawk{if(3410241024100){print1,3410241024MB}}xfsinode113。586MBprocinodecache11989。1MBdentry3526。19MB inode占用了将近12G,dentry占用了3。5G,一切都对上了。 既然是slab缓存导致的内存不足,可以直接用echo2procsysvmdropcaches命令回收。 至此,内存不足的问题已解决。3、寻源 新的疑问产生,到底是哪个目录消耗了海量的inodedentry? 执行如下命令,统计根目录下每个目录拥有的文件和子目录总数。foriinls;docountlslRiwclechoihascountfilesanddirsdone。。。prochas32940780filesanddirsroothas462filesanddirssbinhas287filesanddirstmphas2filesanddirs。。。。 proc是元凶,继续探查proc下的子目录,这次统计细化分为文件和子目录foriinlsproc;dofileslslRprocigrepwcldirslslRprocigrepdwclechoihasfilesfilesanddirsdirstmpcounttmpsdone715049进程占用了1600w个文件〔rootcentos6564220tmp〕morecounttmpssortk3nrhead515049has16381888filesand964dirs17211has7653filesand349dirs6053has7511filesand384dirs18720has2289filesand269dirssyshas1166filesand119dirs〔rootcentos6564220tmp〕psefgrep15049mysql150491383941Jan07?8509:04:44usrsbinmysqldbasedirusrdatadirdatavarplugindirusrlib64mysqlpluginusermysqllogerrordatavarerr。logpidfiledatavarmysql。pidsocketdatavarmysql。sockport3306root2491225232001:10pts300:00:00grep15049 多尴尬,查半天居然还是mysql的问题。 统计proc15049下的子目录信息destproc15049foriinlsdest;dofileslslRdestigrepwcldirslslRdestigrepdwclechoihasfilesfilesanddirsdirstmp15049done〔rootcentos6564220task〕cattmp15049sortk3nrhead5taskhas20428788filesand955dirsfdinfohas106921filesand0dirsnethas60filesand3dirsattrhas6filesand0dirsautogrouphas1filesand0dirs proc15432task目录,记录的是mysqld衍生的每个子线程的信息。 查看mysqld当前的子线程数量〔rootcentos6564220task〕catproc15049statusgrepithreadsThreads:191 继续查看每个子线程具体信息destproc15049taskforiinlsdest;dofileslslRdestigrepwcldirslslRdestigrepdwclechoihasfilesfilesanddirsdirstmp15049taskdone〔rootcentos6564220tmp〕more15049tasksortk3nrhead515049has106957filesand4dirs15058has106957filesand4dirs15117has106957filesand4dirs15118has106957filesand4dirs15119has106957filesand4dirs 每个子线程打开的文件数量是一样的,进入任意1个子线程的fd目录,〔rootcentos6564220fd〕pwdproc15432task15120fd〔rootcentos6564220fd〕lswcl85286每一个fd都是1个mysql文件,看命名格式是分区表〔rootcentos6564220fd〕ll39326lrwx1rootroot64Jul3101:3439326datatokudbsql204d542Pp20161105188status3f14ef59811d。tokudb4、结论 登录数据库查看informationschema。partitions,发现了100多个分区表,每个表1000个分区起步。 这套实例是其他部门半路转交给我们的,该组同学使用mysql最大的特点就是喜欢创建分区表。 另外,诊断全程freeg显示空闲物理内存为0,但是mysqld并没有因此OOM,这是因为被额外消耗的那16G内存全属于可回收类型,可以被其他内存请求复用