当服务器的并发TCP连接数以十万计时,我们就会对一个TCP连接在操作系统内核上消耗的内存多少感兴趣。socket编程方法提供了SO_SNDBUF、SO_RCVBUF这样的接口来设置连接的读写缓存,linux上还提供了以下系统级的配置来整体设置服务器上的TCP内存使用,但这些配置看名字却有些互相冲突、概念模糊的感觉,如下(sysctl -a命令可以查看这些配置):
net.ipv4.tcp_rmem = 8192 87380 16777216 net.ipv4.tcp_wmem = 8192 65536 16777216 net.ipv4.tcp_mem = 8388608 12582912 16777216 net.core.rmem_default = 262144 net.core.wmem_default = 262144 net.core.rmem_max = 16777216 net.core.wmem_max = 16777216
还有一些较少被提及的、也跟TCP内存相关的配置:
net.ipv4.tcp_moderate_rcvbuf = 1net.ipv4.tcp_adv_win_scale = 2
(注:为方便下文讲述,介绍以上系统配置时前缀省略掉,配置值以空格分隔的多个数字以数组来称呼,例如tcp_rmem[2]表示上面第一行最后一列16777216。)
网上可以找到很多这些系统配置项的说明,然而往往还是让人费解,例如,tcp_rmem[2]和rmem_max似乎都跟接收缓存最大值有关,但它们却可以不一致,究竟有什么区别?或者tcp_wmem[1]和wmem_default似乎都表示发送缓存的默认值,冲突了怎么办?在用抓包软件抓到的syn握手包里,为什么TCP接收窗口大小似乎与这些配置完全没关系?
TCP连接在进程中使用的内存大小千变万化,通常程序较复杂时可能不是直接基于socket编程,这时平台级的组件可能就封装了TCP连接使用到的用户态内存。不同的平台、组件、中间件、网络库都大不相同。而内核态为TCP连接分配内存的算法则是基本不变的,这篇文章将试图说明TCP连接在内核态中会使用多少内存,操作系统使用怎样的策略来平衡宏观的吞吐量与微观的某个连接传输速度。这篇文章也将一如既往的面向应用程序开发者,而不是系统级的