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

XDM,要优化一套站内信,请问有什么可执行落地的方案。

  •  
  •   xiayushengfan · 2021-11-20 09:17:38 +08:00 · 2816 次点击
    这是一个创建于 860 天前的主题,其中的信息可能已经有所发展或是发生改变。
    我初步的实现用 MYSQL ,一张站内信模板表,一张用户表,一张模板用户关系表。
    但是现在用户表的数据量有点大,大概在百万条。
    如果给多次所有的用户发站内信,关系表很容易数据量破亿。
    请问有什么其他方法能解决这个问题。
    有两个需求:
    1.最好不要用 MYSQL 的分库分表,想用新技术代替
    2.百万用户的日常活跃也就几千,可能阅读人数就几百这样子。
    3.关系表中,有对应的用户是否阅读。
    13 条回复    2021-11-22 09:32:12 +08:00
    oott123
        1
    oott123  
       2021-11-20 10:11:46 +08:00 via Android
    还这样,但是只存已读用户,没已读的就当未读
    zpf124
        2
    zpf124  
       2021-11-20 10:17:41 +08:00
    我先说个我之前设计的实现,不一定好,而且当时我们的在线用户量级很小都不担心这个问题。

    一张用户表,一张站内信表,一张站内信已读表。

    站内信表中有 sendUserId 字段 魔法值 0 代表发送给所有人,其他值代表只发给某人。
    因为我们数据量不大,所以消息是直接 join 查的,order 排序未读的展示在前。
    zpf124
        3
    zpf124  
       2021-11-20 10:23:29 +08:00
    本来当时打算有个消息发送组的概念,消息分为发给个人还是发给某个组, 然后组里面有个魔法值是群发。
    结果这个功能对于我们本事不是很重要,而且人手要优先干其他的,所以这里就简化了,有给某个组群发的需求,就 foreach ,创建多条信息发送给指定的人。
    zpf124
        4
    zpf124  
       2021-11-20 10:33:56 +08:00
    最后说说你的需求
    1 、数据肯定要落库的,虽然这个数据重要性不高丢了就丢了,但发消息偶尔会出现收不到肯定最起码业务领导会不爽。
    所以如果想要性能那就用搜索引擎 es 或者其他非关系数据库如 mongoDB ,数据读取层面还可以加 redis 。

    2 ,3 、阅读很少那就把阅读单独建表, 就像我们那种, 阅读表包含消息 id 、用户 id 、是否已读、已读时间、创建时间啥的。
    kaiki
        5
    kaiki  
       2021-11-20 10:41:12 +08:00
    @zpf124
    群发这块是不是直接发送一个空邮件或只有标题的邮件,邮件数据链接到一个群发表中取邮件内容效率会高点?
    感觉发邮件和发文章也没什么太大的区别,就是用户能不能查看而已,既然是给所有人的,当文章来发会不会好一点。
    xiayushengfan
        6
    xiayushengfan  
    OP
       2021-11-20 11:17:14 +08:00
    @zpf124 我是打算是 mongoDB 去重新做这一块。主要 mongoDB 不怎么熟悉。
    xiayushengfan
        7
    xiayushengfan  
    OP
       2021-11-20 11:20:05 +08:00
    @kaiki
    是偶尔群发,偶尔按照组别发送,但是这个组别又有很多。
    一个用户可能有十几种属性或者是标签,然后标签组合,这样子类别就很多了。
    所以不太想用 3 楼说的发送组的概念
    zpf124
        8
    zpf124  
       2021-11-20 11:38:03 +08:00
    @kaiki 最后我们是发多条了,没有组的概念,这种情况下按照你说的方式确实能优化一些存储。

    针对后面的问题,我们的文章表有 n 多字段,对于消息来说都是完全没用的,而且文章没有记录多少人已读的。
    最后我们的站内信不是用户给用户发送的,基本都是系统通知,"你订阅的 某个资源更新了,url " 类似这种,所以我们和楼主的也不完全相似,因为我们的消息大多数是分组的,个别是全站群发,没有用户间私信。
    zpf124
        9
    zpf124  
       2021-11-20 11:42:36 +08:00
    @xiayushengfan mongodb ,我们用的也不是很有心得,我们还是按照关系型数据库的用法或者 k-v 缓存的用法在用。

    比如我们如果用 mongodb 存站内信的话,就是一个集合是所有消息,或者一个集合是一个月的消息之类的维度,每个文档包含文档的全部内容包括所有的接受用户 id ,以及已读状态, 查询的时候 直接查当前用户 id 的文档数据。
    CrazyMonkeyV
        10
    CrazyMonkeyV  
       2021-11-20 15:25:35 +08:00
    这个我以前设计过,我们的情况类似,邮件会分类:
    1 、全部用户邮件 先生成一条数据,然后再用户登录的时候,给他发一个邮件。
    2 、特定类型用户邮件 先生成一条数据,然后再用户登录的时候,检测是否满足条件,满足给他发一个邮件。
    上面这 2 类邮件,还有开始和结束时间(也就是有效期),有效期外登录则不发了
    3 、指定用户右键 直接发
    这样的话,日活不多的系统,邮件不会太多,mysql 基本没问题
    CrazyMonkeyV
        11
    CrazyMonkeyV  
       2021-11-20 15:28:17 +08:00
    其实主要的概念就是把群发改为了给活跃用户发,减少数据量。
    lesismal
        12
    lesismal  
       2021-11-20 16:21:35 +08:00   ❤️ 1
    ### 选型
    因为楼主希望不要用 mysql ,所以选择 mongodb ,能支持的数据量足够大,并且 nosql 方便扩展

    ### 信件存储方案(按类型分别处理,广播类信件去重)
    1. 系统发给用户,多个用户收到的是相同内容:只插入一条到 letter 集合中
    2. 系统发给用户,多个用户收到的是不同内容:一个用户一条插入到 letter 集合中,类似用户发给用户
    3. 用户发给用户:每个一条插入到 letter 集合中

    ### mongodb 集合( collection )和 文档( document )设计
    mongodb 的 collection 相当于 mysql 的 table
    collection 里的 document 相当于 table 的一条数据 collection 设计:
    1. collection name: letter
    document struct:
    {
    "_id": xxx, //mongodb 自带的就行
    typ: system/p2p/...,
    time: xxx,
    from: userid:name, //用户之间的会有这个字段,系统发的看功能设计是否需要
    content: xxx,
    ...
    }

    2. collection name: letter_list
    document struct:
    {
    userid: xxx,
    letters: [
    {
    id: letter_id_xxx, // 根据信件 id 去 letter 里查
    time: xxx,
    readed: 0,
    },
    ......
    ],
    }

    优化:上面的 1 、2 中的 document 是为了方便展示,直接是用展开的结构字段,实际使用中,应该把各个字段合并编码、减少字段数量、从而减少相应的计算消耗和存储空间占用等成本,比如冒号分隔符分割多个字段,取出后 splitN 得到各个字段内容
    letter 可以优化成:
    {
    "_id": xxx, //mongodb 自带的就行
    info: "type:time:from:content", // 例如: "0:1637396101::您的超级 VIP 已经开通!", "1:1637396101:用户 B:您的回复太棒了,非常感谢!"
    // content 应该放在最后,以面 content 中有冒号时放在中间 splitN 无法正常解析
    }

    letter_list 可以优化成:
    {
    "_id": xxx, //mongodb 自带的就行
    info: "id:time:readed", // 如:"aaaa:1637396101:0"
    }

    ### 其他
    具体细节以及 mongo 的一些优化,请根据自己实际情况进行
    xiayushengfan
        13
    xiayushengfan  
    OP
       2021-11-22 09:32:12 +08:00
    @lesismal 谢谢老哥,给的全面了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5938 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 02:06 · PVG 10:06 · LAX 19:06 · JFK 22:06
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.