美文网首页
一次未使用单例模式导致的Too many open files

一次未使用单例模式导致的Too many open files

作者: 我的女友叫胜楠 | 来源:发表于2020-08-16 11:16 被阅读0次

一. 前言

(1)事件的描述:在新项目上线后,部分基础数据需要两个系统进行同步。这些基础数据涉及大量的历史数据,需要从新上线的项目中,同步到其他有关联的系统中。同步的是方式采用RocketMq进行消息推送和消费。

(2)事故的反思:为避免今后在犯同样的错误,反思bug为何未在测试环节中被暴露出来,最主要的原因还是并未进行充分的测试,测试的场景并不能覆盖生产中所能涉及到的所有场景,导致事故的发生。

二. 事故回顾排查经过

(1)在基础数据同步过程中,一共有四部分基础数据需要同步。按照数据依赖关系,有先后顺序的进行同步,当在第四部分数据也是数据量最大的一部分数据同步时,bug被暴露出来。数据量大概是13000多条,同步的方式是批量同步,由于双方系统中都有限制,所以批量同步时,每条报文中的数据量是30条。计算下来也就是需要推送434次,才可以将人员信息 全部推送完成。

至此就是本次事故的起始情况,下面来看一下异常信息。

(2)too many open files 异常

图片

分析:从异常的直观含以上来看是开起了太多的文件数据量,导致 consumer 再创建socket链接时失败。通过百度查阅后学习到,在linux系统一切都是文件,socket也是以文件的形式存在,那么由此就可以将异常链接起来了,每创建一个socket链接或每开启一个线程或者进程,都是在创建并开启一个文件,这个文件在linux系统中的学名叫做“文件句柄”。

并且每台Linux系统中都有默认的 “文件句柄”数量的限制,默认是1024个(通过 ulimit -a 可以查看)通常只有在高并发的场景下会出现该情况,但以当前的配置来看,足以支撑现有的并发数。

图片

(3)继续往下看, 正常情况下,socket使用后close掉是会被正常关闭回收掉的,且在新上线的系统并不会有什么并发量,所以socket持续存在是并不正常的,通过 ps -ef | grep TIME_WAIT 可以查看到,项目所在的服务器中有大量的 socket 处在等待状态,这也就是为生socket 不能在被实例化和 too many open files 的原因。只要批量个几次,一定会超过1024这个open file的数量。

接下来,查看 err log 中异常抛出的具体类 ,从代码中找到了这样一段代码

图片

这段代码的功能是用来创建 MQ 中 Producer 与 Broker(这里的broker是阿里的ONS)的链接方法,会实例化一个Producer出来供后续方法调用,实例化的本质也就是创建一个和Broker 的RPC链接,至此too many open files 的原因就基本说的通了。

(4)再来看另外一段代码

图片

创建完链接后,紧接这就是方法调用,将数据推送出去。但是在推送后并未将资源关闭,这也就是为什么有那么多处在 TIME_WAIT 状态下的 socket 的连接。

至此整个事故的回顾到此就告一段落了。

三. 方法的改进

针对本次事故产生问题的位置,有两种解决办法。

(1)方法一:将创建 Product 实例化的方法改为单例模式。

图片

此处我们使用 (Double-Check)模式优化该方法中的单例模式以提高效率。

(2)方法二:资源调用完后,关闭释放掉资源。

图片

以上两种方法任选其一即可。但是对于不同的使用场景,两种改进方法各有优势,具体情况还需具体分析。

四. 总结

在项目开发完成后,开发应先将开发好的功能,尽可能的充分测试,以暴露可能存在的bug。因为有些bug并不是简单的黑盒测试可以暴露出来的。代码书写要严谨,如果时间允许,每一个环节其实都值得认真反复的推敲。

@Author : zhankai

相关文章

网友评论

      本文标题:一次未使用单例模式导致的Too many open files

      本文链接:https://www.haomeiwen.com/subject/ykjtjktx.html