zoukankan      html  css  js  c++  java
  • 04Windows频繁打开和关闭端口可能引发的问题 | 07.杂项

    04-Windows频繁打开和关闭端口可能引发的问题

    郑昀 20100810 隶属于《07.杂项》小节

    老赵写了一篇《关于Windows频繁打开关闭端口时出现的问题》,论述了他从 Windows Web Server 2008 R2 通过 TCP 连接对 Cent OS 下的 MongoDB 数据库服务做压力测试,遇到了 Socket 连接资源耗尽,导致程序报告“由于系统缓冲区空间不足或队列已满,不能执行套接字上的操作。”错误的情况。

    Socket 连接资源耗尽,在 Windows Server 下很常见,如果使用者程序写得没问题的话,一般都是微软(或其他软件厂商)设置的一些默认参数不合时宜导致的。

    我以前写过一篇《02-Twisted 构建 Web Server 的 Socket 长链接问题 | 07.杂项 | Python》,记述了另外一种 Windows Server 常见问题:在 Python 开发语言下,用 twisted 框架编写一个 Web Server ,接收 Google PubSubHubbub 的 Hub Server 推送过来的 Google Reader 文章共享信息时,遇到了文件描述符到达上限的现象。这个模式的特点是,用 twisted.web.server 对接 PubSubHubbub Hub Server ,双方都支持重用连接,照理说,既然保持长连接并且重用 socket 连接,不应该出现这种“too many file descriptors in select”错误。这里的知识点是 Windows 下 select module 文件描述符(file descriptor)最多是512个,而在 Linux 下这个限制为 32767 ,如果超过这个限制值,就会出现类似上面的异常。

    老赵的文章指出了一个有意思的知识点:临时端口号可分配范围, 

    临时端口号范围定义

    当一个客户端程序(比如说一个浏览器)初始化一个 connection 连接远端服务(比如一个网站)时,客户端会打开一个“ephemeral(临时)”端口,端口号一般是随机分配的。你可以用微软工具 TCPView 来查看。

    那么这个进程为出站连接(outbound connection)分配端口号时,端口号的可分配范围与操作系统有关。其中一个主要影响因素是 MaxUserPort ,位于注册表的 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters 下。

    下面这张表列出了不同 Windows 操作系统所能分配的端口范围:

    操作系统

    MaxUserPort
    数值的
    含义

    端口范围,如果MaxUserPort
    没有定义

    端口范围,如果MaxUserPort
    已定义

    最小值

    最大值

    Windows NT/2000/XP/2003

    Ending Port

    1025 to 5000

    1025 to [MaxUserPort]

    5000

    65535

    Windows 2000/XP/2003 with KB951748/KB951746

    Ending Port

    49152 to 65535

    1025 to [MaxUserPort]

    5000

    65535

    Windows Vista/2008

    Number of Ports

    49152 to 65535

    49152 to [49152 + MaxUserPort − 1]

    255

    16384

    表1 端口范围

    当然,你如果在服务器上安装了微软的一些服务,还是会自动修改这个 MaxUserPort 参数的,比如Small Business Server 2000/2003 会修改为 60000, ISA Server 会修改为 65535, Exchange Server 2003 会改为 60000 。

    看了这张表后,你会知道:

    1、不要使用小于1025的端口号;

    2、尽量使用系统临时端口范围(ephemeral port range)之外的端口,比如你定义自己应用程序要打开的端口号为8000,而不是5000。

    3、重用连接。

    查看了我的笔记本电脑(Win XP)和服务器(Windows 2003),注册表里都没有设置过这个MaxUserPort参数,所以端口范围就是默认的,在服务器上,可分配的临时端口是从1025到5000。

    回到我的文件描述符打开过多的问题上,

    重用端口失败+保持长连接生效

    如果监听的 Google Reader User 足够多,这些用户又在一个时段集中分享文章,那么 Google PubSubHubub Hub Server 就会以极快的速度把数据推送过来,此时如果重用 socket 端口失败,而保持长连接策略又起作用,于是很快在 twisted web server 监听的端口上打开的文件描述符又爆了。

    处理办法:

    1、参考《02-Twisted 构建 Web Server 的 Socket 长链接问题 | 07.杂项 | Python》,

    twisted.web.server.Site 类的初始化函数有一个可选参数 timeout ,它的默认值是 60*60*12 ,也就是12小时,它的目的是闲置端口超时自动关闭。在我们的情景下,超时时间太长,所以才会有许多处于 ESTABLISHED 状态的 Socket Connections 积累。

    所以我们缩短为 15 分钟(也可以更短),让没有得到重用的 Connections 尽快自动关闭。只需要在开始执行:
    reactor.listenTCP(8080, Site(MyWebResource.setup(),timeout=60*15))
    即可。

    2、参考《03-PubSubHubbub 和 twisted 的 Persistent connections 能力 | 07.杂项 | Python》,接收到对方 Server 推送过来的数据后,异步扔给另一个方法解析和处理,render_POST 方法立刻 return NOT_DONE_YET 标志, 等异步处理数据成功了,回调里再 finish 掉当前的 request 。

    参考资源:

    1、关于Windows频繁打开关闭端口时出现的问题

    2、Choosing a TCP Port for a Network Service

    3、02-Twisted 构建 Web Server 的 Socket 长链接问题 | 07.杂项 | Python

    4、03-PubSubHubbub 和 twisted 的 Persistent connections 能力 | 07.杂项 | Python

    5、TCP - WAIT状态及其对繁忙的服务器的影响

  • 相关阅读:
    JSON 使用
    JSON 语法
    JSON 简介
    什么是 JSON ?
    PHP 数组排序
    PHP 数组
    swan.after
    Page.after
    App.after
    AOP说明
  • 原文地址:https://www.cnblogs.com/zhengyun_ustc/p/socket.html
Copyright © 2011-2022 走看看