V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
cz5424
V2EX  ›  Python

如何维护 socket 链接池

  •  1
     
  •   cz5424 · 2019-08-07 15:09:50 +08:00 · 3948 次点击
    这是一个创建于 1938 天前的主题,其中的信息可能已经有所发展或是发生改变。

    背景

    每个任务需要建立一个 tcp 链接, 发送数据到 iot 设备, 在并发量高的情况下,tcp 链接不能有效的复用, 每次链接花费的代价太高

    疑问

    想要请教一下有没有维护一个 socket 链接池的方法或者例子?

    使链接发起之后在一定时间内保持 tcp 链接不中断, 如 rabbitmq 的 60 秒不活跃就关闭链接

    第 1 条附言  ·  2019-08-07 17:11:23 +08:00
    可能用任务的方式描述会清晰一些

    目前设计:

    开始任务-> 建立链接-> 发送数据- >关闭链接->任务结束

    理想中的设计

    开始任务-> 查找有没有已经建立的链接(没有则建立)-> 发送数据->任务结束
    29 条回复    2019-08-12 08:54:46 +08:00
    BBCCBB
        1
    BBCCBB  
       2019-08-07 15:22:24 +08:00
    如果你熟悉 java 可以看看 Netty 的 ChannelPool 的实现. 写的非常好.
    ShangAliyun
        2
    ShangAliyun  
       2019-08-07 15:36:22 +08:00
    python 语言不清楚,C#下是设置 keepalive 时间自动释放掉不活跃的链接
    并发量高需要提高后端负载服务器数量
    sujin190
        3
    sujin190  
       2019-08-07 15:46:59 +08:00
    你这是要多路复用吧,如果应用层协议不支持,基本不可行
    如果连接重用的话,有状态不行,无状态倒是可以

    要么你自己再封装,那就是 vpn 差不多了
    cz5424
        4
    cz5424  
    OP
       2019-08-07 17:02:59 +08:00
    @sujin190 服务端决定了链接不同设备就必须发起一个 socket 链接, 我这个客户端可能会收到几千个任务,假设其中 50 个是链接到相同设备的,目前用 celery 的设计, 会造成这个设备的链接一直链接断开链接断开. 目的是想让这个 socket 保持住
    janxin
        5
    janxin  
       2019-08-07 17:05:26 +08:00
    本来以为能看懂的,但是后面似乎看不懂了,为什么一个设备要几十个连接...
    cz5424
        6
    cz5424  
    OP
       2019-08-07 17:08:29 +08:00
    @janxin 因为任务周期决定了....没有 socket 池,就是收到任务建立链接,任务完成释放链接
    Player1973
        7
    Player1973  
       2019-08-07 17:12:33 +08:00
    有多少个设备
    Player1973
        8
    Player1973  
       2019-08-07 17:15:33 +08:00
    我这边至多会有 5K 多个设备点位、采取的措施是长连接,维持一个设备一个连接不断开
    cz5424
        9
    cz5424  
    OP
       2019-08-07 17:15:52 +08:00
    @Player1973 目前是 1w+吧, 服务设计预计支持 10w
    cz5424
        10
    cz5424  
    OP
       2019-08-07 17:17:22 +08:00
    @Player1973 想要的就是维持长链接的方法..比如全局变量..之类的...
    Player1973
        11
    Player1973  
       2019-08-07 17:19:03 +08:00
    @cz5424
    哦哦、你可以看下我的方案 https://gitee.com/hlmycode/HL_agent.git
    DeepRedApple
        12
    DeepRedApple  
       2019-08-07 17:21:22 +08:00
    直接使用 Netty 不就好了 多好的技术
    sujin190
        13
    sujin190  
       2019-08-07 17:36:17 +08:00
    @cz5424 #4 你这是通过长连接往 rabbitmq 推消息,然后 celery 处理?没懂你同一设备为啥需要多个连接啊
    不同消息完全可以放在一个连接里发送,为啥需要多个连接。。
    janxin
        14
    janxin  
       2019-08-07 17:50:31 +08:00
    @cz5424 看描述你是向设备推送数据才建立连接?这样子只要做个超时时间标记和 fd 表就可以了,断开采用统一的维护机制。对于已经建立连接的设备就使用已有 fd,如果没有则创建;独立检查轮巡是不是已到超时时间,到了就关闭
    misaka19000
        15
    misaka19000  
       2019-08-07 17:54:11 +08:00
    如果你不主动 close,操作系统是不会主动断开 TCP 连接的,所以你不需要做任何事情,连接就会被维持
    misaka19000
        16
    misaka19000  
       2019-08-07 17:56:15 +08:00   ❤️ 1
    哦,你是要连接复用是吧,这个更简单了,做一个 ip:port -> connection(本质上是 fd) 的映射关系,需要使用连接的时候先检索一下存在就直接使用,不存在再创建
    xnode
        17
    xnode  
       2019-08-07 17:58:01 +08:00
    单独开一个进程 做一个定时器,timer 循环检查 长时间的垃圾连接
    lolizeppelin
        18
    lolizeppelin  
       2019-08-07 18:23:53 +08:00
    简单可以看看 python redis 的实现

    rabbitmq 心跳抄 openstack 的 oslo_messaging,的做法自己处理下就行了

    基本上就是
    写个优先级锁(避免心跳抢占具体执行),每个 connection 都记录上次使用时间和心跳包时间,用于判断是否发心跳 /是否长期不用

    一个线程 /协程专门用于心跳发送,顺便回收长时间不使用的 connection
    lolizeppelin
        19
    lolizeppelin  
       2019-08-07 18:27:08 +08:00
    顺便,tcp 层维持链接不一定靠谱,最好在应用层心跳,基本上常用的服务器都有用于心跳检测的 PING 协议包
    oahebky
        20
    oahebky  
       2019-08-07 18:57:06 +08:00 via Android
    说白了就是要定时发心跳包到链接的另一端,为了不让对端因为链接长时间没有活动而主动断开连接。
    所以你应该确定(找到 /定义)一个空包类型,这个空包类型需要是最终接受数据设备能够“知道”的--无意义的包。
    然后在代码中开一个线程类,线程类中维护一个链接“池”,将想要保持的暂存链接交给这个运行中的线程类。
    至于这个线程类,它的工作就是不停地定时取出链接池内的链接发空包,再返回池。
    lloovve
        21
    lloovve  
       2019-08-07 19:40:25 +08:00 via iPhone
    断开除非你客户端定时自动链接服务器
    lazyfighter
        22
    lazyfighter  
       2019-08-07 19:55:42 +08:00
    netty 不是现成的吗
    iamsk
        23
    iamsk  
       2019-08-07 20:30:00 +08:00
    可以基于 socketpool 实现一个,其中 max_lifetime 设置生命周期
    https://github.com/benoitc/socketpool
    基于这个比较简单,也可以参考 redis 的 python 库实现,见 connection.py
    MMMMMMMMMMMMMMMM
        24
    MMMMMMMMMMMMMMMM  
       2019-08-07 20:59:22 +08:00
    跟网游一样,发心跳包

    别无他法
    realpg
        25
    realpg  
       2019-08-07 21:12:25 +08:00
    这种场景…… UDP 大法好……
    cabing
        26
    cabing  
       2019-08-07 21:18:06 +08:00
    你自己也可以做个吧。

    把连接放到容器里面,加上定时器,定时心跳。
    cz5424
        27
    cz5424  
    OP
       2019-08-07 21:39:49 +08:00 via iPhone
    谢谢各位大佬,下班了没看信息,等我慢慢消化一波
    cz5424
        28
    cz5424  
    OP
       2019-08-08 17:26:53 +08:00
    @lazyfighter
    @BBCCBB
    @DeepRedApple

    不是 java, 在 python 环境下, 我会去参考它的实现
    Tracy1997
        29
    Tracy1997  
       2019-08-12 08:54:46 +08:00
    楼主有方案了吗,能不能贴下代码。最近也要写一个 TCP 服务器,接受几千个长连接一直发数据过来然后保存到数据库,还没想好怎么弄。多路复用可以吗?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4945 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 01:10 · PVG 09:10 · LAX 17:10 · JFK 20:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.