V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
monkeydream
V2EX  ›  数据库

请教一下聊天消息应该用什么数据库存储?

  •  1
     
  •   monkeydream · 179 天前 · 9346 次点击
    这是一个创建于 179 天前的主题,其中的信息可能已经有所发展或是发生改变。

    公司要开发运营聊天功能,估计用户 10w 左右,在线 1w 人,消息每天 100w 以上,需要存储 6 个月左右的消息,差不多 2 亿条,而且考虑到不同终端之间的消息同步,客户端需要频繁的查询聊天数据。 请问针对这样的场景应该选择哪种数据库? 目前考虑 Mongodb 或 Clickhouse ;考虑 mongodb 主要是 mongodb 的分片模式适合存储大量数据、查询也比较快,考虑 clickhouse 主要是其能存储大数据并且查询性能也比较好(但是听说并发不太好,不知道是否适合并发查询要求)。

    88 条回复    2022-10-01 19:05:35 +08:00
    liuhan907
        1
    liuhan907  
       179 天前 via Android
    要查询聊天这种东西,第一反应应该是 es 吧。
    Smilencer
        2
    Smilencer  
       179 天前
    学微信,聊天记录全部 sqllite 存在客户端本地,查询全部在本地
    superbai
        3
    superbai  
       179 天前
    有没有考虑过直接用云服务厂商提供的 IM 功能
    NGUP915
        4
    NGUP915  
       179 天前
    @Smilencer wx 这么🐶???
    c332030
        5
    c332030  
       179 天前
    @Smilencer #2 微信动不动找不到文件、图片,但是空间又没减少
    coderxy
        6
    coderxy  
       179 天前
    2 亿条不算多,mongodb 的分片集群可以搞定。 如果量再大,可以考虑 hbase 这一类的分布式数据库,我们用 hbase 存的,一天都不止 1 亿条,稳得很。
    tramm
        7
    tramm  
       179 天前
    查询的话都是查本地的吧.
    monkeydream
        8
    monkeydream  
    OP
       179 天前
    @Smilencer 主要是要考虑消息同步,不同终端之间要保证消息一致性,还有离线消息存储,所以消息必须存在服务器。本地查询会存在 Sqlite 中。
    julyclyde
        9
    julyclyde  
       179 天前
    首先 10w 用户就不可能,想多了
    monkeydream
        10
    monkeydream  
    OP
       179 天前
    @coderxy 因为需要走消息同步,获取用户最近消息这个操作也很频繁;不知道 Mongodb 和 Hbase 针对这种并发查询的性能咋样?
    awanganddong
        11
    awanganddong  
       179 天前
    热数据放 redis, 冷数据存 mysql ,定时归档。一般查询的话,都是查本地,如果想实现云端检索类似功能,直接异步走一份到 es 。

    推荐个网站

    http://www.52im.net/

    即时通讯网

    im 这块是天坑。单纯存储的不复杂。
    monkeydream
        12
    monkeydream  
    OP
       179 天前
    @awanganddong 多谢。
    tairan2006
        13
    tairan2006  
       179 天前
    你要做线上查询的话,肯定推荐 es 吧。

    不然的话推荐用时序数据库,或者 hbase 这些方案也能用。
    coderxy
        14
    coderxy  
       179 天前
    @monkeydream 我们是仿照钉钉走的拉模式,全部都是走数据库,反正 hbase 稳得很(请求量大了或者数据量大了都会自动分片)。mongodb 的话,如果你用分片集群,提前做好压测,应该也没啥问题。
    masterclock
        15
    masterclock  
       179 天前
    公司有 10 万人?买一套不好吗?为啥要浪费时间开发?
    monkeydream
        16
    monkeydream  
    OP
       179 天前
    @coderxy 多谢;那我们估计优先考虑 mongodb ,因为目前项目中已经有些应用在尝试使用 mongodb 数据库。
    monkeydream
        17
    monkeydream  
    OP
       179 天前
    @masterclock IM 聊天是我们 SAAS 产品的一部分;不只是我们公司自己用。
    coderxy
        18
    coderxy  
       179 天前
    @monkeydream 可以的,符合自己需求的才是最好的。 毕竟 hbase 这一类数据库用的人少,维护起来也比较麻烦。IM 领域真正麻烦的是超大群,其它都还好。
    coderxy
        19
    coderxy  
       179 天前
    @masterclock 第三方的各种限制,而且也不便宜。 有能力的话自研一下其实成本不高的。
    monkeydream
        20
    monkeydream  
    OP
       179 天前
    @tairan2006 ES 可以考虑下;时序数据库没接触过,不太敢用。
    di1012
        21
    di1012  
       179 天前
    要不试试时序数据库?
    onlyhuiyi
        22
    onlyhuiyi  
       179 天前
    为什么要用 mongo 呢,我们公司 mongo 都不再支持新的接入了
    monkeydream
        23
    monkeydream  
    OP
       179 天前
    @di1012 你们实际项目生产上有使用过吗?我们没接触过这块,怕坑太多。
    monkeydream
        24
    monkeydream  
    OP
       179 天前
    @onlyhuiyi 为啥不接入了? mongo 写入查询效率还可以吧?这么多年了也比较成熟,也可以进行分片存储大数据。比存 mysql 肯定要强不少吧。
    Singular
        25
    Singular  
       179 天前
    System Design 的书介绍设计 Facebook Messenger 用的是 Hbase 这类宽表存储 DB

    F.Y.I.: https://akshay-iyangar.github.io/system-design/grokking-system-design/system-design-problems/facebook-messenger.html
    wxf666
        26
    wxf666  
       179 天前
    @monkeydream 3 天前的 [这个帖子]( https://www.v2ex.com/t/882773 ) 里,有很多人反映,MySQL 单表存 1~2 亿(#11 楼 #16 #18 #19 #21 #35 )、4 亿(#27 )、10 亿(#35 )、20 亿(#28 )都没问题诶,查询也很快(几十 ms ,#27 #28 )

    MySQL 真的不行吗?
    liuhan907
        27
    liuhan907  
       179 天前
    @monkeydream 聊天数据,你要搜索要全文搜索,除了 ES 你还想自己实现倒排索引?
    monkeydream
        28
    monkeydream  
    OP
       179 天前
    @wxf666 主要考虑不仅仅是数据量存的问题,还有并发读。最终还是要做个压测对比下。
    b123405060
        29
    b123405060  
       179 天前
    @wxf666 mysql 单表一般不超过 500w, 单表上亿的数据? mysql 这么强大吗
    monkeydream
        30
    monkeydream  
    OP
       179 天前
    @liuhan907 不是全文检索,是多端数据同步,要实现消息拉取。
    joesonw
        31
    joesonw  
       179 天前 via iPhone   ❤️ 1
    时序是存数字的,每条记录存的是差值来优化空间和统计。聊天记录这种文本的完全和时序没半毛钱关系。一般查询是本地的,服务器只是留档不检索的话,按时间存对象存储就好了。用户同步到本地 sqlite 再查询。
    yangzhuowork
        32
    yangzhuowork  
       179 天前   ❤️ 1
    某办公 IM 大厂早期用的是 mysql 写扩散。 后面量大了。就扛不住了。 架构升级成 类 Hbase 的 OTS ( tableStore ) IM 业务核心特性之一是,基本上很少修改数据(撤回,删除等)。另外要核心关注一下 读写扩散模型的问题。 大群治理。 现代的 IM 都不是单纯的读扩散或者写扩散了。

    MongoDB 不太建议。MongoDB 最贴合的应该是数据 schema 多变的这种业务类型 。IM 业务的表基本不会有啥变化。不适合。clickHouse 不了解。
    realrojeralone
        33
    realrojeralone  
       179 天前
    pengtdyd
        34
    pengtdyd  
       179 天前
    就没人推荐 postgresql 吗?
    首先是场景:聊天记录需要频繁查询吗?拿微信来说,本地先有一份,同时同步多端消息,但是需要发送查询到服务器本身并不是一个高频的场景,聊天应用本地需要一个数据库,查询不到本地或者轮询同步的时候才需要和服务器进行交互。
    lmshl
        35
    lmshl  
       179 天前   ❤️ 1
    聊天场景的话,主要是写多读少,几乎不修改,而且顺序性明显
    那我推荐 Cassandra ,以 Channel/Group 为 partition key ,timeuuid 为 clustering key ,写入每 key 几万且支持水平线性扩展,以 partition key 读取也是顺序读,速度不需要担心。
    wxf666
        36
    wxf666  
       179 天前
    @b123405060 超过 500w 会怎样? B+ 树从 3 层 变为 4 层?

    然后由于内存只能完整缓存前两层(前两层代价是 20~30 MB 内存,前三层代价是 20~30 GB ),所以 3 层变为 4 层,会导致实际 IO 由 1 次 变为 2 次,即速度下降 50%?

    还是怎么个逻辑?

    数据库新人,求指教
    lmshl
        37
    lmshl  
       179 天前
    接 #35 Cassandra 还支持过期时间 (TTL).
    你想存储几个月就存储几个月,过期后不需要手动清理
    wxf666
        38
    wxf666  
       179 天前
    @monkeydream 你要并发读多少啊?

    那个帖子里反馈,MySQL 单表这么多亿,单次查询也能 10- ms 啊(噢,26 楼写错了)
    demon1991yl
        39
    demon1991yl  
       179 天前
    mongodb 吧,我们的私信、im 消息目前都是存在 monodb 里面的,规模都是上百亿条,而且根据楼主的描述,数据量 2 亿不算多,存 mongo 的话,也方便后续扩展,,而且基本也是一些在线索引查询。ES 、CK 等对于 TP 类业务实时性不一定能保证
    demon1991yl
        40
    demon1991yl  
       179 天前
    @onlyhuiyi 为啥不接 mongodb 了呢,我们挺多业务再用,还有很多 mysql 转过来的呢
    fengjianxinghun
        41
    fengjianxinghun  
       179 天前
    实时查询用 ES ?都是 ppt 架构师?
    fengjianxinghun
        42
    fengjianxinghun  
       179 天前
    @fengjianxinghun 还是都是个位数并发?
    hahasong
        43
    hahasong  
       179 天前
    肯定用 hbase 我之前就做过这个。消息都是时序写入,hbase 轻松无压力。只有硬盘到位,永久存都行
    microxiaoxiao
        44
    microxiaoxiao  
       179 天前 via Android
    2 亿条消息也不大吧,直接存内存相关的数据库吧。持久化随便选一个。200000000*1k/1024/1024/1024=190GB 。图片,视频另外存
    tt67wq
        45
    tt67wq  
       179 天前
    热 tidb + 冷 hbase
    helloxiaofan
        46
    helloxiaofan  
       179 天前 via iPhone
    MySQL 不行吗,我们之前每天 400w 左右,可以分库分表
    shot
        47
    shot  
       179 天前   ❤️ 6
    建议参考头部玩家的技术选型,比如 Discord 的数据库迁移历程:MongoDB → Cassandra → ScyllaDB

    《 How Discord Stores Billions of Messages 》
    > In July, we announced 40 million messages a day, in December we announced 100 million, and as of this blog post we are well past 120 million.
    > The messages were stored in a MongoDB ……, we reached 100 million stored messages and…… see the expected issues appearing: the data and the index could no longer fit in RAM and latencies started to become unpredictable.
    https://discord.com/blog/how-discord-stores-billions-of-messages

    《 Discord Chooses ScyllaDB as Its Core Storage Layer 》
    https://www.scylladb.com/press-release/discord-chooses-scylla-core-storage-layer/
    cp19890714
        48
    cp19890714  
       179 天前   ❤️ 1
    首先排除 clickhouse 。clickhouse 主要用于 OLAP ,不适合 OLTP 。并发能力很弱,不适合你的场景。
    mongodb 分片、写入并发、数据压缩、数据过期自动清理 都挺适合你的场景。数据量 2 亿真不多。
    ES 我只是简单使用过,没有太多了解。不过,实时查询好像不是太快,而且服务器成本比 mongodb 高。
    cp19890714
        49
    cp19890714  
       179 天前
    @cp19890714
    不过,如果要做聊天记录查询,那么全文索引又必然是用 ES 了
    defage
        50
    defage  
       179 天前
    clickhouse 肯定是不合适的,这种端上的场景不是 clickhouse 的场景。
    数据量级一大,要考虑综合做法,不一定是单个存储。 比如 db 分表+hbase 存详情,用户维度的列表从 db 查,详情回表用 hbase 构建出来。
    liuhan907
        51
    liuhan907  
       179 天前
    @monkeydream 所以你是要做 IM 消息存储和消息本身的检索?那这个 2E 的量基本随便了吧,拿个 pgsql 硬件规格拉高一些单机大概都够。不放心就找一个分布式数据库一把梭。
    guanhui07
        52
    guanhui07  
       179 天前 via iPhone
    tidb
    polardb
    NoString
        53
    NoString  
       179 天前
    hbase

    上 clickhouse 不可能的,你可以试试 ck 对并发支持。聊天记录你查详情又不聚合去重计算,选他干啥
    lmmlwen
        54
    lmmlwen  
       179 天前
    hbase 这些没现成的就没必要,毕竟你一天也就 100w ,只存 6 个月
    wellsc
        55
    wellsc  
       179 天前
    映射存就行了,kv 存消息尸体和 id ,量不大
    dog82
        56
    dog82  
       179 天前
    IM 要做好非常难,存储只是难点之一

    有条件的就买吧,腾讯云、网易云都有 IM 产品
    yty2012g
        57
    yty2012g  
       179 天前
    CK 不太 ok ,ck 是 OLAP 引擎,QPS 不能太高,而且关联性能不太行。
    第一想法是 ES
    WebKit
        58
    WebKit  
       179 天前 via Android
    @superbai 云服务厂商的消息不给保存的。保存费用更高。而且定制化太差了
    wxf666
        59
    wxf666  
       179 天前
    @monkeydream 我大概算算 MySQL 单表,受限于 IO 的读并发吧:

    假设:
    - B+ 树 4 层 *(若 InnoDB 、Dynamic 、16 KB 每页、8 字节主键、1 KB 一条消息,可容纳 110 亿)*
    - 缓存前两层 *( 14 MB 内存代价)*
    - 有 `(uid 4 字节, time 5 字节)` 索引
    - 每个用户每次获取不超过 700 条消息 *(此时索引只需读一个叶节点)*
    - **不缓存实际消息** *(就当所有用户都在获取历史消息吧。因为每个叶节点可能存着 15 个不同用户的消息,太散了,不会算『每次一个用户获取一堆消息时,能利用上多少缓存』,直接按最差情况算)*


    设每秒有 x 人请求,平均每人有 y 条消息要获取,硬盘有 z 个 16 KB 的 IOPS ,那么:

    2x (每人消耗 2 次 IO 去索引读取自某个时间以来的消息 ID 列表) + 2xy (每条消息都要 2 次 IO 去消息表读取) <= z


    如,我的垃圾固态,16 KB 有 25000 IOPS (也就 400 多 MB/s )。那么:

    每秒 100 人要获取消息时,平均每人能得到(不在缓存中的) 124 条历史消息?


    (数据库新手,算的不对,恳请指出)
    la2la
        60
    la2la  
       179 天前
    不考虑时序数据库么,本地缓存加线上时序数据库持久化。理论上线上存储的消息应该是加密的的吧?
    paouke
        61
    paouke  
       179 天前
    公司有搭好的 hbase 就用 hbase ,没有用 mysql ,mongo 也能撑得住,ck 肯定是不太行,ES 用来全文索引还行,主存储不太行吧
    aitaii
        62
    aitaii  
       179 天前
    clickhouse 1000 个并发撑死了
    ThinkCat
        63
    ThinkCat  
       179 天前
    前公司用的是 mysql ,后面数据量实在过大,用了阿里的 OTS ,但是这个东西太贵了。IM 的热数据不多的话,可以用 mysql ,做好分表和冷热隔离。其实最好的,是楼上讲的时序数据库,较适合 IM 特性,不过这个没用过。
    binge921
        64
    binge921  
       179 天前
    查询肯定 es 存储肯定 hbase
    flycloud
        65
    flycloud  
       179 天前
    说用 ES 的真是人才,还全文索引。。。

    “客户端需要频繁的查询聊天数据” 意思是用户需要拉取和其他用户会话的聊天消息,而不是去全文索引查询某个关键字。
    mongodb shard 再适合不过了,设计好 shard key ,保证两个用户之间的会话消息落入某一个分片中,不同的会话消息均匀分布到各个分片。比如 {sessionId: "hashed", msgId: 1},如果有群聊天也是一样的,分配一个 sessionId ,msgId 递增,以支持按会话批量按序拉取消息。

    再设置一个字段自动过期删除。
    Huelse
        66
    Huelse  
       179 天前
    @flycloud #65 搜索聊天记录中的关键词是有这种需求的
    flycloud
        67
    flycloud  
       179 天前
    “频繁的查询聊天数据”

    其实很多是无效请求,根本没有新增消息,可以在 redis 中设置标记,真正有新消息时才去读取 DB ,可以很大成都降低 DB 压力。
    podel
        68
    podel  
       179 天前
    不如所有的消息都是日志 /FILE 。以时间递增序列进行保存。
    服务器只存储。
    所有消息查询功能都要根据时间戳,从服务器下载下来 SYNC 后。在本地进行计算。比如说搜索之类的。
    (服务器只承担存储功能,不承担任何查询功能)
    flycloud
        69
    flycloud  
       179 天前
    @Huelse 是有这种需求,但是注意审题啊,是客户端查询。
    第一种:本地有存储消息,直接客户端本地搜索啊。
    第二种:客户端本地不存储消息,应该是没有什么 IM 应用会在所有会话中查询某个关键字吧,而是在某个会话里查询,直接拉取某个会话的历史消息来搜索,不就可以了?

    当然也会有在后台查询关键字的情况,多半也是会指定某两个用户之间消息查询。
    实在想不出来在所有用户的所有会话里查询关键字这种需求的意义,所以觉得 ES 没有适用场景。
    playtomandjerry
        70
    playtomandjerry  
       179 天前
    @Smilencer 也信
    jitongxi
        71
    jitongxi  
       179 天前
    说 es 的确实扯淡的,es 的缓存对于非公用的内容查询, 缓存空间估计就炸裂了。
    查询确实只是给客户端做的事,服务端只负责存储。
    sunmacarenas
        72
    sunmacarenas  
       179 天前 via Android
    公司有钱就上 SAP HANA
    hopingtop
        73
    hopingtop  
       179 天前
    1.如果在都能满足功能的情况下,一定要选择团队熟悉的!!!
    2.这里 2 亿数据确实不多,而且也不用依赖 mongodb 本身的分片,可依据时间自行管理分片,这样在扩容很有优势
    3.mongodb 在查询方面性能还是很不错的,你的查询场景一般还带有时间限制。
    4.楼上也说了参考 头部 ,Discord 当初在 2015 年就选择了 mongodb ,(2022 年的 mongodb 更强大了) 为什么不选择其他?当你数据量真的到达扛不住的量级了,我想肯定是很赚钱的了,这个时候人手和资源又不一样了!很多事情本就不可一步到位。
    5.需要频繁查询聊天数据,这个需求一般只是 存在运营这个角色, 如果真到 DB 性能不够,那么你完全可以经过角色同步数据的概念到本地进行查询,然后,如果有必要再去服务器去获取上下文。
    WOLFRAZOR
        74
    WOLFRAZOR  
       179 天前
    @c332030 这是没做优化的问题吧。优化之后不可能这样的。
    zmzeng12
        75
    zmzeng12  
       179 天前
    写多读少,又不涉及修改消息。
    数量不大用 SQLite ,数量大用 RocksDB 。
    RocksDB 的话,服务器存全量 sstable 作为 single of truth ,客户端按需拉取查询时间范围内的 sstable 文件,Client 本地完成查询。
    remember5
        76
    remember5  
       179 天前
    个人猜测,本地查询 sqllite + 后台 hbase
    changdy
        77
    changdy  
       179 天前
    clickhouse 去掉 .不是干这个的
    其次 时序数据库 了解的不多 .但是 也比较赞同 @joesonw 的说法

    es 我觉得有几个问题吧.基于分词,无法保证查询结果 数据难分表. 不分表冷热数据混在一起也有点小问题.


    感觉 im 这个场景还是挺大的 ,最好还是和产品一起商量下如何优化 使用体验.
    documentzhangx66
        78
    documentzhangx66  
       179 天前   ❤️ 1
    淘宝这么多年现成的方案,都不用?

    直接按用户进行分库。

    首先按用户热度,分为冷热用户集群。

    热集群高配置,大内存,SSD 。冷集群低配置,小内存,HDD 。

    每个集群由一大堆 Mysql 节点组成,每个 Mysql 节点负责一部分用户。节点散列策略按用户 IO 数量来进行负载均衡。

    这样实现了几个好处:

    1.对于一个用户,所有数据集中在一台 Mysql 里。

    2.实现了基于性价比的冷热数据分离。

    3.如果一些 Mysql 节点坏了,只会影响一小部分用户,不会影响整体业务。

    4.如果一些用户的冷热度发生变化,方便做自动迁移。

    5.每个 Mysql 节点的数据量小,能够支持 LIKE 进行高精度搜索。
    djoiwhud
        79
    djoiwhud  
       179 天前 via Android
    @monkeydream #30 。你的需求选 mysql 或者 pg 就可以了。

    热数据放 redis 里面。

    实在想折腾新方案,想永久保存聊天记录,考虑 hbase 或者 hive 。本人做过 IM 类的需求产品,我负责的说,这个需求用 es 是个错误。
    akira
        80
    akira  
       179 天前
    凡是发帖问方案的 ,一律推荐 用 三方的,例如腾讯的聊天服务 .

    光是在线 1w 人这个事情 估计你们就已经要头大了。。
    QlanQ
        81
    QlanQ  
       178 天前
    为啥还有推荐 es 的,这个量级用 es 做储存,会是什么价位的?
    这个场景写入也很多,es 不合适吧
    Asimov01
        82
    Asimov01  
       178 天前
    其他我不知道,这种需求别用 Clickhouse ,Clickhouse 设计目标就是做小规模并发,超大数据量且没有固定查询模式的快速即席分析,不适合做这种业务。
    wqhui
        83
    wqhui  
       178 天前
    mongo 挺合适做聊天数据存储的,全文查询什么的确实比不上 es ,但感觉 2 亿数据问题也不大,还可以建个时间索引自动把旧数据删掉,es 很少见到用来保存源数据的,一般都是从数据库存储然后同步到 es 。clickhouse 设计目标是拿来做数据分析不合适
    onlyhuiyi
        84
    onlyhuiyi  
       178 天前
    @monkeydream 我也不知道为啥,提申请页面都写着不再接新的实例了。应该是内部用的少吧,不想浪费人力去维护这部分了,主要还是用 mysql ,ES ,redis 等,最近越来越多用 clickhouse 。接触的系统很少用 mongo 。
    onlyhuiyi
        85
    onlyhuiyi  
       178 天前
    @demon1991yl 我也不知道为啥,用的人少,不值得安排人来维护吧。
    c332030
        86
    c332030  
       177 天前
    @WOLFRAZOR #74 微信都迭代这么多个版本了
    AnLuoRidge
        87
    AnLuoRidge  
       177 天前
    @Singular 这个附的链接 404 了
    AnLuoRidge
        88
    AnLuoRidge  
       177 天前
    关于   ·   帮助文档   ·   博客   ·   nftychat   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   实用小工具   ·   1345 人在线   最高记录 5556   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 50ms · UTC 23:35 · PVG 07:35 · LAX 16:35 · JFK 19:35
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.