这里资源泄露主要是指某个对象占用有某些资源,比如连接、内存等,在这个对象被 GC 之前,必须主动执行一个方法,如 close、release 之类的,将其占用的资源释放出来,该对象才能被安全的 GC。否则就会出现资源泄露,比如连接没有关闭,内存没有释放。随着服务的运行,泄露的资源由于无法被释放,整个服务占用的资源就会越来越多,最终让服务无法分配新资源,导致服务异常。
为了介绍线程间传递 ThreadLocal 对象这个事情,请先耐心一些跟我一起来看看我是怎么遇到线程间传递 ThreadLocal 对象这个需求的。
一起看这么个场景,大致上是下面这样,是 clojure 的代码。但是请不要担心,它非常短也非常简单:
|
|
不知道为什么感觉现在比较新的项目好些都用的是 Gradle,而不是 Maven。IDEA 导入 Gradle 项目的时候遇到好几次问题了,在这里记录一下步骤,后面再次遇到要导入工程的时候好回看。
以下使用的是 MacOS,IDEA 版本为:IntelliJ IDEA Community 2016.3.3。
漫漫长路,终于到了我们比较熟悉的 TCP 一层了,但很快就会发现上面这一大堆内容什么 NIC、中断、IP 路由之类的加起来可能都没有 TCP 一层的内容复杂,单是 goto 都比别的地方用的都多。因为 TCP 有状态,不同状态下收不到不同数据会有不同的行为,就导致了这个复杂度。为了不陷入 TCP 各种细节逻辑中,我们还是先只看最简单的连接处在 ESTABLISHED 状态的收消息过程。TCP 数据还分为 Normal 和 Urgent 两种,两种类型数据在处理过程中并不相同,为了简单起见,这里只大致介绍 Normal 的数据接收过程。
前面说到数据是交给 netif_receive_skb
来做进一步的处理,而netif_receive_skb
基本没干什么事情,主要事情都在 netif_receive_skb_internal 中完成。此时数据处理都还在软中断的 Handler 中,top
的 si
能反应出 CPU 在这个阶段花费的时间。
想看能不能完整梳理一下收消息过程。从 NIC 收数据开始,到触发软中断,交付数据包到 IP 层再经由路由机制到 TCP 层,最终交付用户进程。会尽力介绍收消息过程中的各种配置信息,以及各种监控数据。知道了收消息的完整过程,了解了各种配置,明白了各种监控数据后才有可能在今后的工作中做优化配置。
维持大量并发连接是实时通信系统的关键能力之一,而要想测出一台服务器到底能支撑多少连接有时候会比较麻烦,需要涉及到好几个系统参数的调整,在这里希望能将遇到过的各种参数调整记录一下,以备后用。
以下所说连接均指 TCP 连接。
首先需要明确一点是单个压测客户端(单个 IP)能承载的并发连接数是有限制的,这个上限是 65535。也就是说无论压测客户端所在机器性能有多强大,单个 IP 能和服务端建立的并发连接数就只有 65535 个,不可能更多。而从服务端角度来看,服务端能承受的并发连接数又远远不止 65535 个,只要服务器内存足够,CPU 足够强大,单机承载几十上百万的并发连接完全不是问题,所以我们经常能听到评价某些实时通信服务时候说单机能承担百万并发连接等。为什么从客户端和从服务端两个角度会得到不同的限制呢?