如何维护 socket 链接池 - V2EX
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 4457 次点击
    这是一个创建于 2340 天前的主题,其中的信息可能已经有所发展或是发生改变。

    背景

    每个任务需要建立一个 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  
    PRO
       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     Solana     836 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 23:01 PVG 07:01 LAX 15:01 JFK 18:01
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86