我的想法是这样的:
如果有给这个用户的新消息,先把具体内容存到数据库,然后把有新消息的通知进入 rabbitmq 队列
如果此时用户在线,直接发送到前端(只是通知前端消息数目+1 ,不发送具体消息内容)
如果用户不在线,就先放在队列里面。用户前端上线后,和后端建立 websocket 连接,然后后端就把队列里面积累的东西发过去
用户点击消息提示之后,再从后端查询数据库,得到所有的新消息的具体内容
这样做有什么问题吗?业界通常的做法是什么?
1
Chad0000 2022-02-03 18:47:49 +08:00 1
如果让我做,那么:
新消息来后直接入 RabbitMQ ,防止消息太多数据库压力大。Consumer 负责将数据入库,同时判断用户是否在线,在线就发给用户,不在线就标记最新版本号。 用户上线后先通过 API 获取最新版本号,如果有未读消息则同时获取消息内容。之后再建立连接开始接收新消息。 |
2
Chad0000 2022-02-03 18:59:39 +08:00 3
但如果是给后台用,而且用户量不大,能接受若干秒延迟,则可以直接使用 HTTP 而不是 Websocket ,每隔一段时间比如 30 秒请求一次即可。是否有最新消息这个标记保存在 Redis 中。
我的后台应用就是这么弄的,配合 Long Polling 实在秒提醒。 |
3
liuzhedash 2022-02-03 21:03:52 +08:00
早年论坛实现都是轮询,数据库压力没有那么夸张。
当然,这个只适合站内信的场景,不适合高频率的 IM 对话那种。 |
4
LeeReamond 2022-02-03 21:23:08 +08:00 via Android
@Chad0000 轮训和 ws 的开销怎么说,30s 轮训一次开销比 ws 高多少?
|
5
chendy 2022-02-03 22:24:53 +08:00
隔壁 sf 的这个帖子是楼主发的么 https://segmentfault.com/q/1010000041363597
这问题不知道具体业务场景不好说啊 |
6
seki 2022-02-03 23:43:09 +08:00
|
7
kaneg 2022-02-04 00:08:15 +08:00
如果有用户一直不上线,消息就一直存在 mq 里?如果有大量类似场景,mq 就会由大量消息堆积而挂掉
|
8
jinliming2 2022-02-04 00:44:50 +08:00 1
你的消息队列里存的是消息通知,而不是消息内容??
用到消息队列,应该是缓解数据库那边的压力吧?如果你的消息可以直接入数据库,那应该没必要用消息队列了?新消息来了先写数据库,然后判断用户是否在线,在线的话就推一条新消息通知,用户阅读的时候再查数据库获取数据。 如果消息量比较大的话,就先把消息放到消息队列,消息入队的时候不通知用户,队列直接输出对接到数据库入库。写完数据库再判断用户是否在线,在线推送。 至于轮询和 websocket 的选择,看具体的业务实时性:1 、实时性要求非常低,那么完全可以不推送,用户刷新的时候获取新消息( V2EX 貌似就是这个模式),2 、web app ,用户很少会刷新页面,而实时性要求不高的话,用轮询 30 秒、1 分钟,3 、要求实时性高的场景,则使用 websocket ,几乎是实时的。 轮询需要接口能够承受住刷新请求,websocket 需要服务端能够持有足够多的 socket 连接。 至于 #6 的 push 消息,使用场景不太一样,主要用于用户没有访问你的网站时也可以收到通知推送(类似于手机 APP 的后台被杀掉,也还是可以通过 FCM/APNs 收到实时推送消息)。你需要注册一个 service worker ,然后用户不需要打开你的网站也可以收到消息推送(只要浏览器在运行,sw 就能在后台接收消息推送),消息推送的形式是通过浏览器的 notification 弹窗(用户必须先授权弹窗)。 |
9
Chad0000 2022-02-04 01:58:45 +08:00 via iPhone
@LeeReamond #4 ws 主要是开发变得复杂以及服务器能承载的 ws 数量有限(只看过相关文章没有测试过)
|
10
3dwelcome 2022-02-04 04:52:48 +08:00
websocket 在安卓上有很大的坑,因为设计上是多线程的。有时候 webview 生命周期结束了,websocket 还挂在后台。
如果仅仅是 PC 上应用,个人感觉轮询和 websocket 都差不多,两者没啥太大区别。 |
11
zqx 2022-02-04 11:15:26 +08:00 via Android
业界常见做法就是前端轮询,后端直接从 mysql 分页查,没有消息队列,也不需要推送。
|