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

[ 咨询 ] 好友聊天功能如何实现

  •  
  •   NeverBelieveMe · 2023-07-13 10:52:50 +08:00 · 3821 次点击
    这是一个创建于 498 天前的主题,其中的信息可能已经有所发展或是发生改变。

    公司项目需要增加这么一个社交的功能,网上搜了一下,基本都是 socket 的方式去实现。这种方案也比较好理解,tcp 长链之后进行消息收发。自己简单写了一下多种事件的处理,可以运行。

    这里有几个问题

    1. 我是在全局变量里面保存了每一个 client ,根据 IP 来取,然后进行消息发送。用户量不大,应该不会出现数据量过大的内存问题。不过还是想问一下,有没有什么好的方案。
    2. 以前写过一个类似的东西,是 socket 用多线程做事件并发处理的,现在改用 python 的 streams ,直接使用协程方法了,想问一下,这一块还需要搞协程池或者设置协程数量吗?我看文档上没写这个。
    3. socket 是单线程,可支持的并发量能有多大?虽然用不到高并发高可用,但是想了解一下,如果说用户量很大的情况下,单台服务器无法支撑的情况下,如何升级架构?
    42 条回复    2023-07-14 16:03:10 +08:00
    brader
        1
    brader  
       2023-07-13 10:55:55 +08:00
    其实聊天挺复杂的,越做越深入,遇到问题会越多,想省事还是直接用第三方的。如果你说体量小,想用自己的也好,你要开发出一个基本功能完善的 IM ,我预估 2 个月工期是少不了的,后续还要持续维护
    opengps
        2
    opengps  
       2023-07-13 10:57:52 +08:00   ❤️ 1
    1 ,看你 socket 的收和发缓冲区设置的是不是过大,这个地方直接决定了内存占用量
    2 ,单台服务器,有些模型单机可以做到服务端承载几十万连接,实际你按照几万理解行了,因为太多连接会让故障重建的时间拉得很长,密集建立期间 cpu 也是爆满的
    3 ,单台无法支撑了,那就需要合理的架构集群设计了,这不是一句话说的明白的,但其实也没那么难
    me1onsoda
        3
    me1onsoda  
       2023-07-13 10:58:02 +08:00
    什么单不单线程,你是想说阻塞非阻塞吧?
    brader
        4
    brader  
       2023-07-13 11:01:01 +08:00   ❤️ 4
    你说的思路差不多是对的,但你只说到了众多实现的其中一点,远远不够完善,一个 IM ,大致你要实现:绑定了所有客户端 ID 的句柄、客户端 ID 与 UID 的绑定关系、UID 与组的绑定关系、心跳检测、私聊、群聊、拉取离线消息、离线消息推送、离线消息恢复、支持多种消息类型、分布式同步信息,这只是其中一部分,还有很多其他功能要实现,我就不列举了。有个开源的 PHP 项目,实现了我说的一些基础功能,你可以借鉴他的思想,看看别人是如何设计及维护客户端列表、UID 绑定、GROUP 绑定、心跳检测等等这些东西的
    https://www.workerman.net/doc/gateway-worker/
    unii23i
        5
    unii23i  
       2023-07-13 11:07:29 +08:00
    我们开发说做好一个基础版至少六个月,于是我们用了第三方的,用的是腾讯 im ,感觉不是很好,收发消息有时候会错位,也不适合迭代其他功能
    NeverBelieveMe
        6
    NeverBelieveMe  
    OP
       2023-07-13 11:07:37 +08:00
    @brader #4 感谢提供思路
    unii23i
        7
    unii23i  
       2023-07-13 11:09:26 +08:00
    我觉得完全可以用类及时通讯,隔个一分钟再发给对方什么的,也没啥影响
    vaaagle
        8
    vaaagle  
       2023-07-13 11:09:41 +08:00
    理论上,如果你想要建立一个聊天室,需要考虑到以下几个方面的内容:

    选择协议:根据你的需求和目标,选择适合的协议。对于实现双向通信的聊天室,Socket 是一个不错的选择。通过 Socket 可以实现在客户端和服务器之间进行收发消息的功能。

    中间件支撑:在协议的基础上,为了应对复杂的业务需求,你可能需要引入一些中间件来支持。这些中间件可以包括各种缓存、队列等。缓存可以用于提高系统的读取性能,队列可以用于处理消息的异步发送和接收。

    开源 IM 工具:如果时间和理解有限,可以考虑使用开源的即时通讯( IM )工具来实现聊天室。这些工具已经经过了实践和稳定性验证,可以帮助你快速搭建一个简单的聊天室。你可以选择符合你需求的开源 IM 工具,并按照其文档进行配置和使用。

    自己编写:如果你希望通过自己编写来磨练技术,也可以多阅读相关的技术博客,综合各方面的知识,逐步实现一个聊天室。你可以参考一些开源项目或者教程,了解聊天室的基本原理和实现方式。

    需要注意的是,以上只是一些一般性的建议,具体的润色还要结合具体情况进行分析和优化。
    NeverBelieveMe
        9
    NeverBelieveMe  
    OP
       2023-07-13 11:17:28 +08:00
    @unii23i #7 我只需要做个功能就行,没多少用户。
    NeverBelieveMe
        10
    NeverBelieveMe  
    OP
       2023-07-13 11:17:57 +08:00
    @vaaagle #8 这是 GPT 的回答吗
    robot1
        11
    robot1  
       2023-07-13 13:57:36 +08:00
    这个问题逻辑性很差,而且我觉得你搞不了这个事,为什么这么说?
    根本就没从业务出发去考虑技术选型,上来就是零散的技术名词,性能问题,这些都是次要的,你要先考虑业务,业务是什么?
    什么场景,有没有群,消息要不要必达,要不要及时性,能不能丢,消息频率,用户数预估
    wbconnie
        12
    wbconnie  
       2023-07-13 14:04:26 +08:00   ❤️ 1
    对于实现社交功能的方案,使用 socket 是常见且合理的选择。不过,如果你希望尝试其他方案,可以考虑使用现有的开源社交网络框架,如 Django 社交网络插件或 Open Source Social Network (OSSN)等。

    关于保存每个客户端的全局变量,根据 IP 来取,这种方式对于用户量不大的情况而言是可行的。如果确保数据量不会过大,且内存占用量在可接受范围内,那么这个方案是没有问题的。但请确保在并发访问时进行线程/协程安全的访问,以避免数据竞争的问题。

    关于协程的处理,如果你使用的是 Python 的异步流( streams )框架(如 asyncio ),它会自动管理协程池和协程数量。你无需手动创建协程池或设置协程数量,框架会根据系统资源和并发情况自动进行调整。

    关于 Socket 的并发处理能力,实际上取决于服务器的性能,特别是 CPU 和内存的能力。对于普通的聊天应用来说,Socket 的并发处理能力很高,可以同时处理数百到数千个连接。但当用户量大到单台服务器无法支撑时,可以考虑以下升级架构的方案:

    1. 横向扩展:通过增加更多的服务器实例并将负载均衡器放置在服务器前面,将流量均匀地分发到多个服务器上,以提高整个系统的并发处理能力。

    2. 分布式架构:将系统拆分成多个逻辑模块,每个模块分别部署在不同的服务器上,通过消息队列或分布式数据库进行通信和数据同步。这样可以将负载分散到多个服务器上,提高整个系统的可伸缩性和性能。

    综上所述,根据你的需求和用户量的大小,选择合适的方案并进行相应的架构升级是很重要的。
    Baloneo
        13
    Baloneo  
       2023-07-13 14:12:12 +08:00
    emqx mqtt?
    godleon
        14
    godleon  
       2023-07-13 14:24:11 +08:00
    如果只文字聊天,自己服务端跟客户端建 socket 就可以满足了, 如果要求发语音消息跟图片 视频聊天 语音聊天,建议还是上第三方,因为自己实现需要流服务器,相对比较麻烦些,如果是 go 当我没说 [手动狗头!]
    vaaagle
        15
    vaaagle  
       2023-07-13 14:26:58 +08:00
    这是我的回答,gpt 润色了一下 ahhhh~
    NeverBelieveMe
        16
    NeverBelieveMe  
    OP
       2023-07-13 14:30:45 +08:00
    @Baloneo #13 之前就是在用 mqtt 搞聊天,不过现在想换条路子走走看
    coderxy
        17
    coderxy  
       2023-07-13 14:32:58 +08:00
    我们写的第一个 im ,用了将近 2-3 个月才线上稳定,确实有很多坑,如果原来没接触过,建议先买第三方。
    NeverBelieveMe
        18
    NeverBelieveMe  
    OP
       2023-07-13 14:33:29 +08:00
    @godleon #14 只是简单文字聊天
    coderxy
        19
    coderxy  
       2023-07-13 14:38:14 +08:00
    @godleon 发语音跟图片都是上传到 oss ,然后发送对应类型的 im 消息。 语音、视频那是 RTC 的范畴了,跟 IM 不是一个东西
    wonderblank
        20
    wonderblank  
       2023-07-13 14:50:51 +08:00
    mqtt 应该就行了
    npe
        21
    npe  
       2023-07-13 14:53:51 +08:00
    Websocket / MQTT
    assiadamo
        22
    assiadamo  
       2023-07-13 15:05:47 +08:00
    社交做下去就要各种审核屏蔽字,准备好了吗
    darkengine
        23
    darkengine  
       2023-07-13 15:06:54 +08:00
    集成个第三方吧,这玩意儿是个无底洞
    jiaoery
        24
    jiaoery  
       2023-07-13 15:27:42 +08:00   ❤️ 2
    能用第三方尽量用第三方,分之前公司就搞过自己的聊天系统,分享一下自己的踩坑之旅(各位大佬不喜勿喷)后端用的方案是 socket 做及时推送,http 做同步的方式;一开始只有简单的 1v1 的服务,当时就搞了个 id 对 id 的方式来搞;后面又搞群聊,如果群里只有两个人,容易误发到之前 id 对 id 的情况下,而且只要有新用户加入群聊,又要迁移数据,就搞了一个
    so1n
        25
    so1n  
       2023-07-13 15:32:00 +08:00
    有对接前端的话,可以考虑用下 socketio ,不然就 websocket
    jiaoery
        26
    jiaoery  
       2023-07-13 15:34:28 +08:00
    @jiaoery conversationId ,然而还有个麻烦,就是如果群聊所有人都退出,需要回收资源;这就必须搞一个定时任务来检查所有的 conversation ;这个解决了;后面业务从国外转入国内,又出现国内某些厂商杀后台的情况,本身及时推送就是在一个 service 里,然后各种保活的方案,适配国内的各个 OEM 又是一地鸡毛,当时团队里搞这个就压了一半的人,痛苦不行;而且上面的问题还是我遇到过的,没遇到的估计更多;要问为什么自己搞,也是当时用第三方的,如个推,信鸽,友盟等上 Google Play 由于内部带广告 API 给扫出来,直接给下架了;甚至当时还给个推写过投诉邮件
    lx271896700
        27
    lx271896700  
       2023-07-13 16:03:17 +08:00
    能用第三方,就用第三方。我曾在两个公司负责 im 项目,开发周期都在 1 年左右,两家公司都是辛辛苦苦开发了一年,最后兜兜转转,都回到了第三方。第三方应该也有按量计费的,你可以找找看。
    coderxy
        28
    coderxy  
       2023-07-13 16:24:53 +08:00
    @lx271896700 兄弟,不至于吧? 开发了一年最后还转回第三方了? 你们最后是啥问题解决不了? 说出来让大家涨涨见识。
    NeverBelieveMe
        29
    NeverBelieveMe  
    OP
       2023-07-13 16:30:06 +08:00
    @assiadamo #22 接入阿里云的审核的。
    NeverBelieveMe
        30
    NeverBelieveMe  
    OP
       2023-07-13 16:31:38 +08:00
    @jiaoery #24 感谢分享经验
    LindsayZhou
        31
    LindsayZhou  
       2023-07-13 16:50:23 +08:00
    我觉得你们在讨论怎么重新造 irc (小声)

    只是不能发图片语音,irc 服务端应该有不少开源实现的,找个来改改?
    irc 也能分布式横向扩展 ( rfc2813 ),不过许多服务端并没有实现。
    lx271896700
        32
    lx271896700  
       2023-07-13 17:04:19 +08:00
    @coderxy #28 第一家公司是比较奇葩,公司只有四五个人,一个 iOS+一个安卓+一个后台,用 websocket 搞了一年,app 没什么用户,ios 和安卓都跑了,app 没有人维护,就换了第三方的 im 。第二家公司,也用 websocket 搞了几个月,后来换了小米的 MIMC ,因为 MIMC 免费,初用没发现什么问题,但后来我们使用量大了之后,qps 受限,消息积压严重,只好又换成腾讯 IM(旗舰版),好在之前写的 UI 界面可以继续使用,所以改动不算太大。
    coderxy
        33
    coderxy  
       2023-07-13 17:10:52 +08:00
    @lx271896700 原来如此, 第三方 im 在 app 早期的时候肯定是够用的,量大了费用就上来了,这个阶段再自研也不迟。
    NeverBelieveMe
        34
    NeverBelieveMe  
    OP
       2023-07-13 17:32:23 +08:00
    @lx271896700 #27 我也想用第三方,不过客户不愿意掏钱
    chong3397
        35
    chong3397  
       2023-07-13 18:55:43 +08:00
    linnana
        36
    linnana  
       2023-07-13 19:16:39 +08:00
    1.用 ip 存映射关系可能不是一个好的选择?可以考虑用户的 uid 存映射关系,比如以 uid 映射 connected-client , 也方便后继要做多设备同步等等。

    2.网络和 IO 等层面的东西用网络编程库和框架来替代就可以了,比如我们用的 Netty ,Python 不太熟但应该也有类似的东西。

    3.单台服务器无法支撑的情况下,可以前置一个 im-route 模块用某种规则路由(往往取决于业务需要)到不同的 im-server 上,同时所有当消息需要做跨 im-server 路由时,需要全局的在线记录表来找到一个用户在哪个 im-server 实例上。这时候需要一个全局在线记录映射等等。扩展可能还会有 login/broker/store/sensitive-censor 等子模块拆分。
    tyzandhr
        37
    tyzandhr  
       2023-07-13 21:27:52 +08:00
    我很好奇,为什么发在 python 标签
    fluyy
        38
    fluyy  
       2023-07-13 21:50:51 +08:00 via iPhone
    我觉得直接用第三方的比较好。单纯的看你这个问题,第一个问题最好最好以用户 id 来存 client ,
    fluyy
        39
    fluyy  
       2023-07-13 21:53:22 +08:00 via iPhone
    第二个问题不太清楚了。第三个规模扩大了,那就要有多台机器。简单的可以再搭一个接入层,然后根据 userid hash 到后端业务机器。
    kuituosi
        40
    kuituosi  
       2023-07-14 09:47:40 +08:00 via Android
    im 主要分两种类型,是否支持离线消息。支持离线消息复杂很多,其中又分服务器是否集群,毕竟单点故障会影响用户体验。如果只支持在线消息这个很简单。如果不支持集群的离线消息,难度也不大。如果支持离线消息并且服务器集群,那难度相当大。至于 python 单机支持的连接数其实问题不太大,比较聊天很多时候处理逻辑不复杂,大不了多进程就能解决
    xiaoshan5733
        41
    xiaoshan5733  
       2023-07-14 15:59:32 +08:00
    感觉悟空 IM ( https://githubim.com/) 挺适合 OP 的,一键部署,业务分离,可以试试
    qbmiller
        42
    qbmiller  
       2023-07-14 16:03:10 +08:00
    花钱买服务,接入云信。 越做越复杂,
    我们 5w dau 每月几万块钱,但自己做,后端+客户端+推送+服务器.... 那一摊子,每月 2 个人成本打不住....
    没多少人的外包项目,可以用 openim 算是全套的了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2942 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 11:10 · PVG 19:10 · LAX 03:10 · JFK 06:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.