V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
awanganddong
V2EX  ›  程序员

请教大家关于 im 的一个问题。

  •  
  •   awanganddong · 2022-03-06 17:33:19 +08:00 · 1697 次点击
    这是一个创建于 984 天前的主题,其中的信息可能已经有所发展或是发生改变。

    原帖子是这样的 http://www.52im.net/thread-1230-1-1.html

    问题是这个

    主要的问题是用户在线情况下,收到一条消息(此时还有些离线消息没有同步), 那客户端消息数据的最新 seq 就是这条在线消息。这可能导致有些离线消息不能同步到客户端

    想请问下针对这个问题,怎么解决

    12 条回复    2022-03-07 08:31:41 +08:00
    imn1
        1
    imn1  
       2022-03-06 17:43:30 +08:00
    没做过,但以前看过前端同事做过类似的
    异步或不同线程接收,然后前端排序刷新,注意刷新频率

    “不能同步”这个应该是单线程的原因?
    awanganddong
        2
    awanganddong  
    OP
       2022-03-06 17:49:32 +08:00
    可以理解为单单通过 seq 可以获取最新的消息标识,但是无法区分离线消息是否已经被拉取完毕。
    Building
        3
    Building  
       2022-03-06 17:54:39 +08:00 via iPhone
    先放在客户端 Dispatch 队列里啊,等离线消息都拉完同步了再 Dispatch 。
    awanganddong
        4
    awanganddong  
    OP
       2022-03-06 17:57:12 +08:00
    这个文章是如何优雅的实现大量离线消息的可靠投递 和楼上的想呼应的。但是还是没解决我的问题。https://segmentfault.com/a/1190000023318638
    Building
        5
    Building  
       2022-03-06 18:08:00 +08:00 via iPhone
    @awanganddong 大量离线消息为什么要同步到本地?一般只需要在注册推送前同步最后的几条消息和未读角标就行了,上拉的时候再去拿未读的消息。
    documentzhangx66
        6
    documentzhangx66  
       2022-03-06 18:23:11 +08:00
    1.客户端消息数据的最新 seq 可能导致有些离线消息不能同步到客户端,解决方案:
    服务端,把每一条客户端需要接收的消息,加 4 个字段:
    消息接收时间(此条数据的产生时间)、消息同步到客户端的时间、客户端确认已收到该消息的时间、客户端已阅读该消息的时间。

    2.可靠投递的实现方式,是客户端以分布式事务的方式,从服务端获取消息。事务执行成功,则更新上述 4 个字段中的某个字段。你可以直接找个分布式事务的组件来用就行。

    3.大量消息的优化投递方式:批量投递 + 分批投递 + 每批压缩。

    4.你要做企业级 IM ,请拒绝 UDP ,因为很多企业级防火墙与网管,把 UDP 传输无脑当攻击。
    awanganddong
        7
    awanganddong  
    OP
       2022-03-06 18:27:17 +08:00
    @Building 对,但是这里边有个点我没太明白,比如上线后,在线消息,直接推送本地,保存 sqlite 。同时起个线程,根据 seq 倒序拉数据到 sqlite 。然后主线程从 sqlite 取上翻数据是这样的吗?
    awanganddong
        8
    awanganddong  
    OP
       2022-03-06 18:42:11 +08:00
    @documentzhangx66 设置这四个字段的深意我现在还不太理解。
    des
        9
    des  
       2022-03-06 19:15:20 +08:00 via iPhone
    你的意思是“最新 seq ”覆盖了?
    这种一般会在 app 启动的时候就去启动同步的进程
    documentzhangx66
        10
    documentzhangx66  
       2022-03-06 19:16:55 +08:00
    @awanganddong

    这 4 个字段,是解决你说的同步问题的的消息同步逻辑。

    比如,客户端会先加载服务端数据库的 [消息同步到客户端的时间] 为 NULL 的数据,这个字段为 NULL ,意思是客户端还没把这些消息进行拉取。当客户端完成拉取这些消息后,这个字段会设置为客户端完成拉取的时间。

    接着,此时客户端有可能会崩溃,因此 [客户端确认已收到该消息的时间] 这个字段的意思是,当客户端,把这些消息,完成落盘,并稳定地显示了一段时间后,该字段才会被设置为客户端的当前时间。否则,该字段为 NULL ,意思是,客户单已经拉取了消息,但在展示前,可能出现问题,需要客户端重新拉取这些消息。

    其他字段也是差不多的意思,当整个流程要设计的完备,就需要这 4 个字段,也就能避免你说的 [有些离线消息不能同步到客户端] 的问题。
    Building
        11
    Building  
       2022-03-06 19:19:29 +08:00 via iPhone
    @awanganddong 啊,主线程是不能参与数据处理工作的,主线程只能处理 UI 交互,所有的消息都由 Dispatch 经手,Dispatch 分发出来的消息顺序肯定是正确的,Dispatch 把消息分发给储存器,储存器储存后再分发给会话,会话加入消息列表,渲染 UI ,或者先分发给会话,会话再分发给储存器,或者同时分发,都可以,不是重点。如何保证 Dispatch 的顺序性,已经说过了,注册推送前已经拿过一次未读消息了,否则注册不了推送,推送开启后可以下一条消息带着上一条消息的 hash 来保证消息的连续性。至于刷历史消息,不是 Dispatch 的活,另外实现。
    awanganddong
        12
    awanganddong  
    OP
       2022-03-07 08:31:41 +08:00
    @documentzhangx66 你讲的我明白了,你这个是实现 ack 机制

    @Building 你这样讲我大概清楚了,至于更细节的操作,我和前端同学沟通下

    谢谢各位了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2609 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 16:00 · PVG 00:00 · LAX 08:00 · JFK 11:00
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.