想自己做个推送服务,有些疑惑 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
edk24
V2EX    问与答

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

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

    搜索了一些资料, 感觉应该可以做。 推送服务用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     Solana     821 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 21:29 PVG 05:29 LAX 14:29 JFK 17:29
    Do have faith in what you're doing.
    ubao 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