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
strict
V2EX  ›  Python

想实现一个点对点的聊天应用服务器,语言暂限为 Python ,大家有什么推荐的框架么? 目前考虑使用 tornado

  •  
  •   strict · 2018-04-13 21:01:40 +08:00 · 5148 次点击
    这是一个创建于 2412 天前的主题,其中的信息可能已经有所发展或是发生改变。
    第 1 条附言  ·  2018-04-13 21:39:56 +08:00
    1 需要已读回执功能
    2.性能能支持 10W 人同时在线
    21 条回复    2018-04-15 12:27:28 +08:00
    strict
        1
    strict  
    OP
       2018-04-13 21:03:15 +08:00
    或者服务端有没有封装程度更高的库推荐?感谢~
    lixm
        2
    lixm  
       2018-04-13 21:12:45 +08:00
    python3 + asyncio 直接用标准库也可以, 用上层封装也 ok https://github.com/timofurrer/awesome-asyncio
    lvsemi1
        3
    lvsemi1  
       2018-04-13 21:33:05 +08:00 via Android
    这要啥框架,直接 websocket
    strict
        4
    strict  
    OP
       2018-04-13 21:38:07 +08:00 via iPhone
    @lvsemi1 忘了说了,要有已读回执功能.
    playniuniu
        5
    playniuniu  
       2018-04-13 23:52:15 +08:00 via iPhone
    flask-socketio ?不知道性能怎么样
    rogwan
        6
    rogwan  
       2018-04-13 23:55:53 +08:00 via Android
    @strict 已读回执只是一种设计方案,和技术实现没有特别的联系。举个例子,用户 A 在当前屏幕看 B 发过来的消息 b1,这个时候 B 又发了一条消息 b2 过来,b2 这条消息算已读?未读?
    wanghaoxi3000
        7
    wanghaoxi3000  
       2018-04-14 01:57:04 +08:00 via Android
    django channels 最近正好在用 非常爽~
    ilylx2008
        8
    ilylx2008  
       2018-04-14 08:02:13 +08:00 via Android
    go websocket, 刚写完
    qile1
        9
    qile1  
       2018-04-14 09:10:21 +08:00 via Android
    前几天看见一个 twes 还是怎么拼写的一个框架,直接有聊天样例,刚刚没有百度到
    CSM
        10
    CSM  
       2018-04-14 09:36:17 +08:00 via Android
    点对点? P2P ?那要啥服务器
    beddo
        11
    beddo  
       2018-04-14 10:43:13 +08:00
    https://cloud.tencent.com/product/im
    日活低于 10w 还免费……自己造轮子不知道怎么死的。
    qile1
        12
    qile1  
       2018-04-14 10:50:08 +08:00
    @qile1 twisted https://twistedmatrix.com/trac/ 听说比较稳定,性能可以,我 python3.7 没有安装好,自己技术不行
    sujin190
        13
    sujin190  
       2018-04-14 11:38:52 +08:00
    tornado 管理 10w 连接问题不大,反正都是由系统 epoll 处理的,重点还是在消息发送数量,发送量很大的话会受限 python 语言的性能可能会跟不上,还有可能还是连接建立时认真的过程吧,如果需要重启的话,单个进程 10w 连接建立可能会比较久

    flask-socketio 这种可能管理 10w 连接都有问题,更别说转发消息了,socketio 玩具吧,真要用估计还是要自己实现服务端的吧

    不过话说 10w 的在线,可能需要多进程多机备份的话,就需要路由功能了吧,只是单进程会不会不稳定

    已读也都是一条消息了,都一样,只是不知道你只是需要把这个状态转发给发送方,还是服务器要持久化存储,那么要注意受限 python 语言性能,单进程访问 mysql mongodb 等数据库 rps 都不是太高,im 持久化会是个很大问题

    话说干嘛不找个云服务,太费劲了吧,还是有业务要处理?
    wwqgtxx
        14
    wwqgtxx  
       2018-04-14 12:34:53 +08:00
    @sujin190 flask-socketio 的后端也是用 gevent,eventlet,aiohttp 的,管理个 10w 连接不还是用 epoll 能有啥问题
    sujin190
        15
    sujin190  
       2018-04-14 13:24:42 +08:00
    @wwqgtxx #14 你说的对,区别就是 gevent eventlet 完全屏蔽了上层对协程连接的调度,在大量连接同时运行的时候会产生大量协程在运行,使得等待运行的协程栈太长,很容易产生雪崩的

    还有 flask-socketio 只能在连接读写有框架做异步,应用层是很难异步的,并发会受限的
    daybyday
        16
    daybyday  
       2018-04-14 20:24:28 +08:00   ❤️ 1
    是在线聊天室还是 IM,需要"已读回执"功能,那估计是 IM 吧
    造个 IM 的轮子没那么简单,存储方案、消息的可靠 /去重 /有序怎么保证,这些有考虑吗
    然后 tornado 官方只有异步 tcp 支持(即 iostream),如果进程里用到同步的 mysql/redis 库这些,单进程 10w 在线是搞不定的,1w 都难
    mengskysama
        17
    mengskysama  
       2018-04-15 01:39:09 +08:00
    做 IM 很有挑战性的事,我认为也是很有意义的一件事,只有对系统架构、网络、系统内核等等都要有一些了解才能做出一个高可用高性能的 IM 系统。

    当时设计参考了 https://github.com/Terry-Mao/goim,简化了 Logic,增加了离线消息持久化,最终性能比毛大佬 bench 差一丢丢,调整内核参数和各级缓存之后,每个用户不到 5K 内存开销,1H1G 的阿里云承载 8 万用户。


    消息网关别用 python (当然你有 6 倍以上的硬件预算的话洒洒水啦。

    tornado 真不太行,高并发干不过 async,做 web 又不像其他线程模型的框架什么东西都能往里放,放到现在来看更像是教科书级的东西。正好去年我也做了一个 im 项目,调研了下 ws 的实现性能差异。总之 IO 密集型的东西最好还是了解下 go 或者 java,c 之流。

    bench i7 2600k 8G @2core
    target i7 2600k 8G @1core
    -s 客户端数量、每秒 echo1 下、测试 30 秒
    同时可以参考下 https://github.com/uNetworking/uWebSockets

    tornado

    bench -a 0.0.0.0:8888 -s 1000 -i 1 -d 30
    Total Sent: 29182 , Total Received: 29182 , Bytes Sent 817096 , Bytes Received: 817096 , Average RTT: 8.147407ms , Connection Error: 0 , Write Error: 0 , Read Error: 0 , Message Mismatch: 0

    bench -a 0.0.0.0:8888 -s 2000 -i 1 -d 30
    Total Sent: 52960 , Total Received: 52960 , Bytes Sent 1482880 , Bytes Received: 1482880 , Average RTT: 77.962957ms , Connection Error: 0 , Write Error: 0 , Read Error: 0 , Message Mismatch: 0

    bench -a 0.0.0.0:8888 -s 4000 -i 1 -d 30
    2018/04/14 22:35:58 Total Sent: 48032 , Total Received: 48032 , Bytes Sent 1344896 , Bytes Received: 1344896 , Average RTT: 1.004519955s , Connection Error: 464 , Write Error: 0 , Read Error: 0 , Message Mismatch: 0

    asynicio

    bench -a 0.0.0.0:8888 -s 2000 -i 1 -d 30
    Total Sent: 57703 , Total Received: 57703 , Bytes Sent 1615684 , Bytes Received: 1615684 , Average RTT: 11.979018ms , Connection Error: 0 , Write Error: 0 , Read Error: 0 , Message Mismatch: 0

    bench -a 0.0.0.0:8888 -s 4000 -i 1 -d 30
    Total Sent: 88348 , Total Received: 88348 , Bytes Sent 2473744 , Bytes Received: 2473744 , Average RTT: 90.734413ms , Connection Error: 492 , Write Error: 0 , Read Error: 0 , Message Mismatch: 0

    gorilla

    bench -a 0.0.0.0:8888 -s 8000 -i 1 -d 30
    Total Sent: 231759 , Total Received: 231759 , Bytes Sent 6489252 , Bytes Received: 6489252 , Average RTT: 17.459239ms , Connection Error: 0 , Write Error: 0 , Read Error: 0 , Message Mismatch: 0

    bench -a 0.0.0.0:8888 -s 16000 -i 1 -d 30
    Total Sent: 420935 , Total Received: 420935 , Bytes Sent 11786180 , Bytes Received: 11786180 , Average RTT: 36.99979ms , Connection Error: 0 , Write Error: 0 , Read Error: 0 , Message Mismatch: 0

    bench -a 0.0.0.0:8888 -s 20000 -i 1 -d 30
    Total Sent: 486466 , Total Received: 486466 , Bytes Sent 13621048 , Bytes Received: 13621048 , Average RTT: 79.126184ms , Connection Error: 1059 , Write Error: 0 , Read Error: 0 , Message Mismatch: 0

    openresty

    bench -a 0.0.0.0:8888 -s 20000 -i 1 -d 30
    Total Sent: 559234 , Total Received: 559234 , Bytes Sent 15658552 , Bytes Received: 15658552 , Average RTT: 20.53849ms , Connection Error: 0 , Write Error: 0 , Read Error: 0 , Message Mismatch: 0

    bench -a 0.0.0.0:8888 -s 30000 -i 1 -d 30
    Total Sent: 485620 , Total Received: 485620 , Bytes Sent 13597360 , Bytes Received: 13597220 , Average RTT: 193.790583ms , Connection Error: 1769 , Write Error: 0 , Read Error: 0 , Message Mismatch: 5

    uWebSockets

    bench -a 0.0.0.0:8888 -s 20000 -i 1 -d 30
    Total Sent: 562872 , Total Received: 562872 , Bytes Sent 15760416 , Bytes Received: 15760416 , Average RTT: 15.233624ms , Connection Error: 0 , Write Error: 0 , Read Error: 0 , Message Mismatch: 0

    bench -a 0.0.0.0:8888 -s 30000 -i 1 -d 30
    Total Sent: 464767 , Total Received: 464767 , Bytes Sent 13013476 , Bytes Received: 13013476 , Average RTT: 12.200729ms , Connection Error: 13107 , Write Error: 0 , Read Error: 0 , Message Mismatch: 0


    python 当然写起来最舒服就是慢! go 则是很好的选择 channel goroutine 语言层面控制力非常给力,openresty 简直让 nginx 为所欲为,lua 写起来也非常非常爽,甚至我还在上面写 api,一旦要做 co 或者 worker 之间 sync、event、lock、share 就有点智障了。。
    julyclyde
        18
    julyclyde  
       2018-04-15 08:41:21 +08:00
    是不是对“点到点”有什么误解?
    你这个叫中心制
    sujin190
        19
    sujin190  
       2018-04-15 11:19:25 +08:00
    @mengskysama #17 tornado 和 asynicio 在高并发下的问题都是同一个,python 语言性能太低,高并发下同时处理大量连接数据会导致协程栈太长,每个 req 处理时间大大增加而导致很多连接会超时,事实上 python 在普通 curd 的 web 场景下大约 64-128 同时处理 req 之间就能保持进程 100%cpu 使用率,既保持每个 req 的低延迟又可以保持每秒吞吐不变,当然是 mysql redis 都用异步的情况下

    asynicio 比 tornado 性能高一点点大概是 tornado iostream 的实现问题了,太繁琐,导致性能比 asynicio 的 protocol 性能低了很多
    sujin190
        20
    sujin190  
       2018-04-15 11:21:43 +08:00
    @daybyday #16 mysql/redis 都有 tornado 的异步版本 driver 啊
    redis 推荐 https://github.com/thefab/tornadis 比 tornado-redis 性能高很多
    mysql 推荐 https://github.com/snower/TorMySQL
    mengskysama
        21
    mengskysama  
       2018-04-15 12:27:28 +08:00 via iPhone
    @daybyday 关键是为什么每个 c 端链接就一定要有一个 redis 或者 mysql 呢?你指的是传统的 web 架构吧?这种 im 后端应该是一个 pipeline 或者是一个 watch 机制的实现。


    @sujin190 同意,所以我在一般 web 场景用一些同步框架,百 qps 这个量级性能会有一点打折扣但不会差很多,至少写起来不这么难受,第三方库可选择性大了很多。我以前觉得 tornado 也还行,直到被 tornado-redis 不可思议的 rtt 和 tornado-mysql 不可思议的 cpu 坑过以后一直有心理阴影。至于单实例千 qps 可能就不考虑 python 了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1760 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 16:43 · PVG 00:43 · LAX 08:43 · JFK 11:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.