钉钉消息已读、未读咋实现的嘞?(转)

博客围绕APP消息页面已读、未读功能的实现展开。提出设计“对话模型”,将各类通知当作“虚拟人”处理,判断小红点及数量即获取与虚拟人对话的未读消息数。还探讨了前端展示、消息存储,以及应对长尾问题的策略和热门内容数据处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

一款app,消息页面有:钱包通知、最近访客等各种通知类别,每个类别可能有新的通知消息,实现已读、未读功能,包括多少个未读,这个是怎么实现的呢?比如用户A访问了用户B的主页,难道用rabitmq给B发通知消息吗?量大了成本受得了吗?有没有成本低的方案呢

小谈

挺好的一个问题,可惜其他的回答要么是大而化之想当然,要么是顾左而言他,没有一个正经的回答。

这个是很常见的需求,在做这类需求的时候,首先要做的是,设计一个合适的业务模型,那么这个模型就是“对话模型”,

将问题中的"设置",“赚钱积分”,"最近听众","好友跟新","最近来访"当做一个“虚拟人”来处理,你跟"虚拟人"组成了一个"对话列表(msg_group)"

虚拟人”与正常人的区别就是,虚拟人与你的对话是单向的,只能他向你发消息,你无法回复。

所有,判断有没有小红点,或者小红点的数字是多少,就是简单的获取你与虚拟人的对话的未读的消息的数量。

“最近来访”标签

当有人访问你主页的时候,后端会以这个“最近来访”虚拟人的身份给你发一条消息,不过消息里还有一个特殊标记,标明了来源。我们除了要拉取总量,还有不同来源消息的数量。当然,一个动作不一定只发一条消息,比如,图中下方有个金刚键"消息",它是所有消息的总和,所以,投递其他消息的时候,也要给它投递一次,不过它只展示一个未读数字,所以这个消息只需要一个msg_id即可,不需要消息payload。

前端怎么展示

看具体产品需求。

每个对话可以看作一个msg_group,它是一个消息的队列(注意,不是我们常说的消息队列),每条msg的msg_id都是有序递增的,至于msg_id只是队列内有序还是全局有序,就看你选择了,一般数据10亿以内没必要优化,发号器全局有序即可。这个队列有基本的信息:参与人(图中的例子只有2个,你和“虚拟人”),maximal_msg_id。

你只需要保存一个last_pull_msg_id或last_read_msg_id即可,在拉取信息的时候,带上这个last_msg_id即可。

当然,消息列表的存储,读取,就比较多样了。可以是MySQL,nosql,hbase,redis。一般我们是混合存储,特别老的存hbase,比较老的存mysq或nosql,新数据存redis。云厂商也有专门针对这类场景的存储产品。大多数情况,我们只需要一个数量,固定从maximal_id往前取,如果取到100条还没完,直接返回99+完事了。

实际上,图中的需求,比如“设置”,"隐私设置",是整个产品全局的,所以可以弄个简单的"广播消息模式",广播模式就是维持一个单向的消息的队列,所有的人都可以拉取这个队列的消息,只需要他们各位维护自己的last_id即可。

"已读和未读"。它包含两层意思,一个判否,即内容你是否读过,二是计数,即这个内容有多少人读过。

长尾原因

如果你用Redis存储,成本非常高,浪费非常严重。如果不用redis,一旦刷到历史数据,会非常非常慢。在这里bitmap肯定是搞不定的,因为bitmao需要加载全部数据,显然不可行。

这个时候,通常的策略是"[log record]"和"comb", 我们每产生一个动作,比如读,赞,收藏,就会产生一个log record( 取关,取消赞...也是一条独立的log record),我们由专门的大数据系统统一收集这些record,然后对多个维度的数据统计,将统计结果存起来,前端获取数据的时候,先从缓存取,取不到再到comb取。comb的数据规模是远远小于log record的,查询速度非常快。

log record因为不涉及查询,所以没必要用数据库,一般直接存hbase或cassandra这类廉价存储介质。

热门内容

用户互动非常活跃,所以在写入log record的时候,会直接同步更新缓存,但是缓存的数据并不保证十分准确,它只是迷惑用户的,准确的数据是以log record为准的,你在wb经常可以看热门内容的点赞数跟实际的数量不符。因为wb的缓存,独立的counter,实际的数据不同步。

### 实现钉钉群聊消息状态功能 #### 存储策略 针对群聊中的每条消息仅保存单一副本,而非为每位成员单独存储。此方法有效减少了数据冗余并优化了存储效率[^3]。 #### 成员阅跟踪 通过维护每个用户的`last_ack_msgid`(最后确认的消息ID)来追踪个人的阅进度。一旦某位参与者确认接收了一定编号的信息,则表明在此之前的所有信息已被此人阅览;反之,后续尚未触及的内容则处于未阅状态。这种机制确保了系统能精准掌握各成员的具体查看情况而无需额外占用过多资源。 #### 数据结构设计 构建专门的数据表格用于记录群组内部交流详情以及各个参与者的最新取位置(`last_ack_msgid`)。这使得查询特定个体是否查阅过某些通知变得简单快捷,并支持快速统计整体阅状况,如计算当前有多少名成员还未浏览最新的公告等。 ```sql CREATE TABLE group_messages ( msg_id INT PRIMARY KEY AUTO_INCREMENT, content TEXT NOT NULL, sender VARCHAR(50), send_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE user_read_status ( user_id INT, group_id INT, last_ack_msgid INT, -- 记录用户在这个群里最后一个确认接收到的消息ID FOREIGN KEY (group_id) REFERENCES groups(group_id), FOREIGN KEY (msg_id) REFERENCES group_messages(msg_id) ); ``` #### 已回执展示 对于群内任意一则信息而言,只要存在至少一位成员未曾访问它,那么就认为整条信息仍处于部分未被所有人审阅的状态。此时可以在界面上适当提示“N人未读”,其中N代表具体数量;相反地,当所有人都完成了对该项内容的检视后,则更新显示为完全已形式[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值