15

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

 1 year ago
source link: https://www.v2ex.com/t/883731
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

V2EX  ›  数据库

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

  monkeydream · 9 小时 34 分钟前 · 5474 次点击

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

72 条回复    2022-09-29 19:24:32 +08:00
liuhan907

liuhan907      9 小时 31 分钟前 via Android

要查询聊天这种东西,第一反应应该是 es 吧。
Smilencer

Smilencer      9 小时 28 分钟前

学微信,聊天记录全部 sqllite 存在客户端本地,查询全部在本地
superbai

superbai      9 小时 28 分钟前

有没有考虑过直接用云服务厂商提供的 IM 功能
NGUP915

NGUP915      9 小时 26 分钟前

@Smilencer wx 这么🐶???
c332030

c332030      9 小时 23 分钟前

@Smilencer #2 微信动不动找不到文件、图片,但是空间又没减少
coderxy

coderxy      9 小时 18 分钟前

2 亿条不算多,mongodb 的分片集群可以搞定。 如果量再大,可以考虑 hbase 这一类的分布式数据库,我们用 hbase 存的,一天都不止 1 亿条,稳得很。
tramm

tramm      9 小时 15 分钟前

查询的话都是查本地的吧.
monkeydream

monkeydream      9 小时 9 分钟前

@Smilencer 主要是要考虑消息同步,不同终端之间要保证消息一致性,还有离线消息存储,所以消息必须存在服务器。本地查询会存在 Sqlite 中。
julyclyde

julyclyde      9 小时 9 分钟前

首先 10w 用户就不可能,想多了
monkeydream

monkeydream      9 小时 8 分钟前

@coderxy 因为需要走消息同步,获取用户最近消息这个操作也很频繁;不知道 Mongodb 和 Hbase 针对这种并发查询的性能咋样?
awanganddong

awanganddong      9 小时 6 分钟前

热数据放 redis, 冷数据存 mysql ,定时归档。一般查询的话,都是查本地,如果想实现云端检索类似功能,直接异步走一份到 es 。

推荐个网站

http://www.52im.net/

即时通讯网

im 这块是天坑。单纯存储的不复杂。
tairan2006

tairan2006      9 小时 4 分钟前

你要做线上查询的话,肯定推荐 es 吧。

不然的话推荐用时序数据库,或者 hbase 这些方案也能用。
coderxy

coderxy      9 小时 3 分钟前

@monkeydream 我们是仿照钉钉走的拉模式,全部都是走数据库,反正 hbase 稳得很(请求量大了或者数据量大了都会自动分片)。mongodb 的话,如果你用分片集群,提前做好压测,应该也没啥问题。
masterclock

masterclock      8 小时 59 分钟前

公司有 10 万人?买一套不好吗?为啥要浪费时间开发?
monkeydream

monkeydream      8 小时 59 分钟前

@coderxy 多谢;那我们估计优先考虑 mongodb ,因为目前项目中已经有些应用在尝试使用 mongodb 数据库。
monkeydream

monkeydream      8 小时 56 分钟前

@masterclock IM 聊天是我们 SAAS 产品的一部分;不只是我们公司自己用。
coderxy

coderxy      8 小时 55 分钟前

@monkeydream 可以的,符合自己需求的才是最好的。 毕竟 hbase 这一类数据库用的人少,维护起来也比较麻烦。IM 领域真正麻烦的是超大群,其它都还好。
coderxy

coderxy      8 小时 55 分钟前

@masterclock 第三方的各种限制,而且也不便宜。 有能力的话自研一下其实成本不高的。
monkeydream

monkeydream      8 小时 53 分钟前

@tairan2006 ES 可以考虑下;时序数据库没接触过,不太敢用。
di1012

di1012      8 小时 52 分钟前

要不试试时序数据库?
onlyhuiyi

onlyhuiyi      8 小时 52 分钟前

为什么要用 mongo 呢,我们公司 mongo 都不再支持新的接入了
monkeydream

monkeydream      8 小时 49 分钟前

@di1012 你们实际项目生产上有使用过吗?我们没接触过这块,怕坑太多。
monkeydream

monkeydream      8 小时 47 分钟前

@onlyhuiyi 为啥不接入了? mongo 写入查询效率还可以吧?这么多年了也比较成熟,也可以进行分片存储大数据。比存 mysql 肯定要强不少吧。
wxf666

wxf666      8 小时 38 分钟前

@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

liuhan907      8 小时 28 分钟前

@monkeydream 聊天数据,你要搜索要全文搜索,除了 ES 你还想自己实现倒排索引?
monkeydream

monkeydream      8 小时 27 分钟前

@wxf666 主要考虑不仅仅是数据量存的问题,还有并发读。最终还是要做个压测对比下。
b123405060

b123405060      8 小时 27 分钟前

@wxf666 mysql 单表一般不超过 500w, 单表上亿的数据? mysql 这么强大吗
monkeydream

monkeydream      8 小时 26 分钟前

@liuhan907 不是全文检索,是多端数据同步,要实现消息拉取。
joesonw

joesonw      8 小时 25 分钟前 via iPhone   ❤️ 1

时序是存数字的,每条记录存的是差值来优化空间和统计。聊天记录这种文本的完全和时序没半毛钱关系。一般查询是本地的,服务器只是留档不检索的话,按时间存对象存储就好了。用户同步到本地 sqlite 再查询。
yangzhuowork

yangzhuowork      8 小时 23 分钟前

某办公 IM 大厂早期用的是 mysql 写扩散。 后面量大了。就扛不住了。 架构升级成 类 Hbase 的 OTS ( tableStore ) IM 业务核心特性之一是,基本上很少修改数据(撤回,删除等)。另外要核心关注一下 读写扩散模型的问题。 大群治理。 现代的 IM 都不是单纯的读扩散或者写扩散了。

MongoDB 不太建议。MongoDB 最贴合的应该是数据 schema 多变的这种业务类型 。IM 业务的表基本不会有啥变化。不适合。clickHouse 不了解。
pengtdyd

pengtdyd      8 小时 18 分钟前

就没人推荐 postgresql 吗?
首先是场景:聊天记录需要频繁查询吗?拿微信来说,本地先有一份,同时同步多端消息,但是需要发送查询到服务器本身并不是一个高频的场景,聊天应用本地需要一个数据库,查询不到本地或者轮询同步的时候才需要和服务器进行交互。
lmshl

lmshl      8 小时 17 分钟前

聊天场景的话,主要是写多读少,几乎不修改,而且顺序性明显
那我推荐 Cassandra ,以 Channel/Group 为 partition key ,timeuuid 为 clustering key ,写入每 key 几万且支持水平线性扩展,以 partition key 读取也是顺序读,速度不需要担心。
wxf666

wxf666      8 小时 15 分钟前

@b123405060 超过 500w 会怎样? B+ 树从 3 层 变为 4 层?

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

还是怎么个逻辑?

数据库新人,求指教
lmshl

lmshl      8 小时 12 分钟前

接 #35 Cassandra 还支持过期时间 (TTL).
你想存储几个月就存储几个月,过期后不需要手动清理
wxf666

wxf666      8 小时 10 分钟前

@monkeydream 你要并发读多少啊?

那个帖子里反馈,MySQL 单表这么多亿,单次查询也能 10- ms 啊(噢,26 楼写错了)
demon1991yl

demon1991yl      8 小时 9 分钟前

mongodb 吧,我们的私信、im 消息目前都是存在 monodb 里面的,规模都是上百亿条,而且根据楼主的描述,数据量 2 亿不算多,存 mongo 的话,也方便后续扩展,,而且基本也是一些在线索引查询。ES 、CK 等对于 TP 类业务实时性不一定能保证
demon1991yl

demon1991yl      8 小时 8 分钟前

@onlyhuiyi 为啥不接 mongodb 了呢,我们挺多业务再用,还有很多 mysql 转过来的呢
fengjianxinghun

fengjianxinghun      8 小时 3 分钟前

实时查询用 ES ?都是 ppt 架构师?
hahasong

hahasong      7 小时 57 分钟前

肯定用 hbase 我之前就做过这个。消息都是时序写入,hbase 轻松无压力。只有硬盘到位,永久存都行
microxiaoxiao

microxiaoxiao      7 小时 53 分钟前 via Android

2 亿条消息也不大吧,直接存内存相关的数据库吧。持久化随便选一个。200000000*1k/1024/1024/1024=190GB 。图片,视频另外存
tt67wq

tt67wq      7 小时 49 分钟前

热 tidb + 冷 hbase
helloxiaofan

helloxiaofan      7 小时 39 分钟前 via iPhone

MySQL 不行吗,我们之前每天 400w 左右,可以分库分表
shot

shot      7 小时 15 分钟前   ❤️ 4

建议参考头部玩家的技术选型,比如 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

cp19890714      7 小时 2 分钟前

首先排除 clickhouse 。clickhouse 主要用于 OLAP ,不适合 OLTP 。并发能力很弱,不适合你的场景。
mongodb 分片、写入并发、数据压缩、数据过期自动清理 都挺适合你的场景。数据量 2 亿真不多。
ES 我只是简单使用过,没有太多了解。不过,实时查询好像不是太快,而且服务器成本比 mongodb 高。
cp19890714

cp19890714      7 小时 1 分钟前

@cp19890714
不过,如果要做聊天记录查询,那么全文索引又必然是用 ES 了
defage

defage      6 小时 39 分钟前

clickhouse 肯定是不合适的,这种端上的场景不是 clickhouse 的场景。
数据量级一大,要考虑综合做法,不一定是单个存储。 比如 db 分表+hbase 存详情,用户维度的列表从 db 查,详情回表用 hbase 构建出来。
liuhan907

liuhan907      6 小时 28 分钟前

@monkeydream 所以你是要做 IM 消息存储和消息本身的检索?那这个 2E 的量基本随便了吧,拿个 pgsql 硬件规格拉高一些单机大概都够。不放心就找一个分布式数据库一把梭。
guanhui07

guanhui07      6 小时 2 分钟前 via iPhone

tidb
polardb
NoString

NoString      6 小时 0 分钟前

hbase

上 clickhouse 不可能的,你可以试试 ck 对并发支持。聊天记录你查详情又不聚合去重计算,选他干啥
lmmlwen

lmmlwen      5 小时 50 分钟前

hbase 这些没现成的就没必要,毕竟你一天也就 100w ,只存 6 个月
wellsc

wellsc      5 小时 41 分钟前

映射存就行了,kv 存消息尸体和 id ,量不大
dog82

dog82      5 小时 41 分钟前

IM 要做好非常难,存储只是难点之一

有条件的就买吧,腾讯云、网易云都有 IM 产品
yty2012g

yty2012g      5 小时 35 分钟前

CK 不太 ok ,ck 是 OLAP 引擎,QPS 不能太高,而且关联性能不太行。
第一想法是 ES
WebKit

WebKit      5 小时 17 分钟前 via Android

@superbai 云服务厂商的消息不给保存的。保存费用更高。而且定制化太差了
wxf666

wxf666      4 小时 24 分钟前

@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

la2la      4 小时 11 分钟前

不考虑时序数据库么,本地缓存加线上时序数据库持久化。理论上线上存储的消息应该是加密的的吧?
paouke

paouke      4 小时 6 分钟前

公司有搭好的 hbase 就用 hbase ,没有用 mysql ,mongo 也能撑得住,ck 肯定是不太行,ES 用来全文索引还行,主存储不太行吧
aitaii

aitaii      3 小时 19 分钟前

clickhouse 1000 个并发撑死了
ThinkCat

ThinkCat      2 小时 38 分钟前

前公司用的是 mysql ,后面数据量实在过大,用了阿里的 OTS ,但是这个东西太贵了。IM 的热数据不多的话,可以用 mysql ,做好分表和冷热隔离。其实最好的,是楼上讲的时序数据库,较适合 IM 特性,不过这个没用过。
binge921

binge921      2 小时 19 分钟前

查询肯定 es 存储肯定 hbase
flycloud

flycloud      2 小时 9 分钟前

说用 ES 的真是人才,还全文索引。。。

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

再设置一个字段自动过期删除。
Huelse

Huelse      2 小时 1 分钟前

@flycloud #65 搜索聊天记录中的关键词是有这种需求的
flycloud

flycloud      2 小时 1 分钟前

“频繁的查询聊天数据”

其实很多是无效请求,根本没有新增消息,可以在 redis 中设置标记,真正有新消息时才去读取 DB ,可以很大成都降低 DB 压力。
podel

podel      1 小时 54 分钟前

不如所有的消息都是日志 /FILE 。以时间递增序列进行保存。
服务器只存储。
所有消息查询功能都要根据时间戳,从服务器下载下来 SYNC 后。在本地进行计算。比如说搜索之类的。
(服务器只承担存储功能,不承担任何查询功能)
flycloud

flycloud      1 小时 53 分钟前

@Huelse 是有这种需求,但是注意审题啊,是客户端查询。
第一种:本地有存储消息,直接客户端本地搜索啊。
第二种:客户端本地不存储消息,应该是没有什么 IM 应用会在所有会话中查询某个关键字吧,而是在某个会话里查询,直接拉取某个会话的历史消息来搜索,不就可以了?

当然也会有在后台查询关键字的情况,多半也是会指定某两个用户之间消息查询。
实在想不出来在所有用户的所有会话里查询关键字这种需求的意义,所以觉得 ES 没有适用场景。
jitongxi

jitongxi      38 分钟前

说 es 的确实扯淡的,es 的缓存对于非公用的内容查询, 缓存空间估计就炸裂了。
查询确实只是给客户端做的事,服务端只负责存储。
sunmacarenas

sunmacarenas      16 分钟前 via Android

公司有钱就上 SAP HANA

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK