V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
edk24
V2EX  ›  问与答

想自己做个推送服务,有些疑惑

  •  
  •   edk24 · 2019-07-15 01:08:34 +08:00 · 2419 次点击
    这是一个创建于 1940 天前的主题,其中的信息可能已经有所发展或是发生改变。

    搜索了一些资料, 感觉应该可以做。 推送服务用nodejs+socket.io做, 记录在线用户和离线消息交给redis

    一对一, 客户 A客户 B推消息。 客户 B不在线。 记录到redis中。 并且做持久化防止丢失。

    但是一对多, 有点懵。 客户 A给广播给所有人。 在线的兄弟直接转发,

    不在线的兄弟们, 我怎么知道有那些。 并且给他们记录离线消息呢?

    必须完整的把当前所有用户的 uid 查出来, 预存到redis。 在线用户发了出栈。 剩余全部存离线消息?

    或者一开始查询出所有用户 uid, 存起来, 在线的用户修改状态, 非在线的存离线消息。 如何做到和数据库里的成员表同步呢? 毕竟每分钟都可能发生注册。

    这两天对这类东西很感兴趣, 想试着做一个。 想不通, 请各位大佬解答。

    9 条回复    2019-07-15 10:27:34 +08:00
    edk24
        1
    edk24  
    OP
       2019-07-15 01:09:55 +08:00
    辛辛苦苦的 md 标注, 没了! 变得更难阅读了。。。
    edk24
        2
    edk24  
    OP
       2019-07-15 01:15:34 +08:00
    我这个需求可能不太像 push server, 倒是像个聊天。 哈哈 概念还没搞清楚呢
    baojiweicn2
        3
    baojiweicn2  
       2019-07-15 01:30:55 +08:00 via Android
    mqtt。qos 2
    wd
        4
    wd  
       2019-07-15 05:57:59 +08:00 via iPhone
    push 和 聊天本来就有点共通。你这个需求是离线消息的处理逻辑,一个群发消息是需要给所有要收消息的人都记录一份的,然后一般是用户下次链接的时候发给用户。
    gzlock
        5
    gzlock  
       2019-07-15 06:39:26 +08:00 via Android
    用时间流的概念就可以解决了吧
    一个聊天群组一个 ID,所有聊天内容都有时间信息,都存到数据库,a 在 22 点下线,记录下线时间,按 a 的下线时间查询数据库就能获取到哪些内容需要推送给 a
    Yourshell
        6
    Yourshell  
       2019-07-15 07:52:31 +08:00
    重点是客户端的实现吧
    phpdever
        7
    phpdever  
       2019-07-15 08:53:16 +08:00
    利用长连接状态即可。

    记录用户的 uid 及长连接 id,在建立长连接,断开长连接时进行持久化存储,再进行信息消息推送。

    但需要考虑极端情况下的断线重连等问题。

    用户在线不在线其实并不需要关心,推送消息时,如果在线,只要通知客户端进行拉取最新的消息即可,如果不在线,上线之后主动拉取。

    如果是是一对一进行推送,需要同时推给自己和对方,如果是一对多,则推送给所有群组成员。

    难点其实在于客户端处理,你可能还需要用到消息队列,如:rabbitmq。
    opengps
        8
    opengps  
       2019-07-15 09:00:39 +08:00
    轮训不可取,长连接需要踩够坑才可行
    Universe
        9
    Universe  
       2019-07-15 10:27:34 +08:00
    这样说不大看得出架构,就假设是服务端和客户端,服务端负责控制消息分发,客户端向服务端发出生产和消费请求。

    那么有一个区别,服务端在分发消息的时候是主动还是被动,像 flume 就是设置 sink 主动推送,而 kafka 服务端就是被动被客户端请求消费推送。

    像 kafka 这类被动推送就比较好处理,kafka 的做法是记录不同消费者的偏移量,消费者每消费一条数据就把偏移量向后推一条,这样就不需要关心消费者是否在线。

    像 flume 这类其实对于内部 channel 到 sink 也是被动推送,而 sink 是主动消费 channel 并主动推送出去,所以在外部看起来是个主动推送。

    那么在这里就能看出来,其实主动还是被动并不是关键,记录不同客户的偏移量才是关键,如果你希望被动推送,那就让客户端请求推送,如果你希望主动推送,那就在客户端链接上的时候从服务端请求推送。

    现在看你的 3 个问题:
    1. 使用 offset 记录推送进度,离线用户的 offset 不会变化,不需要另外记录离线消息。
    2. 这个推送方式是主动推送,只推送在链接的用户并调整偏移量。
    3. 新用户直接给最后的 offset,是否在线就是是否有链接。

    使用 offset 就还有问题需要考虑:
    1. 每条消息需要一个唯一 id 来作为偏移量,这个唯一 id 怎么取
    2. 如果离线用户长期不消费离线数据造成离线数据堆积,这部分数据是进行持久化还是删掉
    3. 一致性是否需要保证,重复推送是否需要避免
    4. 根据上一个问题的结果来决定推送数据粒度是批量还是单条
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3183 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 43ms · UTC 12:37 · PVG 20:37 · LAX 04:37 · JFK 07:37
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.