热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

服务器接收消息写日志,IM服务器设计消息存储

这部分专门讲述IM消息存储的设计。消息存储的难度在于,要考虑以下的场景:离线消息存储。即发送消息时对方不在线该怎么处理。单聊、群聊消息。随着用户量越来越

这部分专门讲述IM消息存储的设计。消息存储的难度在于,要考虑以下的场景:

离线消息存储。即发送消息时对方不在线该怎么处理。

单聊、群聊消息。

随着用户量越来越大,应该以后如何扩展。

读扩散 VS 写扩散

消息同步模型中,有写扩散和读扩散这两种模型。在开始讨论之前需要先了解两个相关的概念:

收件箱(inbox):该用户收到的消息。

发件箱(outbox):该用户发出的消息。

写扩散(push)

写扩散就是经常说的push模式,即每个消息都直接发送到该用户的收件箱中。其优缺点如下:

优点:读优化,用户每次只需要去读取自己收件箱中的消息即可。

缺点:写很重,如果这个消息是一条群消息,那么一个群成员发送出去的消息将拷贝到所有其余群成员的收件箱中。

095647450c2c78f60e9b22546b1d19fd.png

读扩散(pull)

读扩散就是pull模式,用户每次到消息发送者的发件箱去拉取消息,优缺点如下:

优点:写优化,每次发送的消息只需要写到一个地方,由收件者自己去拉取消息即可。

缺点:读操作很重,假设一个用户有一千个好友,重新登录时需要拉取这些好友所有的离线消息。

cd296e7b5ded68e6117fc3035e7de52f.png

最终选择的是以pull模式为主的模式,理由在于:

IM业务属于『写多读少』类型的业务,如果使用push模式,将造成消息的大量冗余。

pull模式读操作较重的缺陷可以通过其他方式来优化解决。

下面来看具体的设计。

表设计

在数据库设计中,仅使用一个发送消息表来存储消息的具体内容,而另外有一个消息接收表用来存储消息的ID信息而不是具体内容,这样用户查询消息时,大体流程如下:

首先拉取接收消息表中的信息。

根据接收消息表中的ID以及发送者ID信息到发送信息表来具体查询消息。

0e887b1a6cd96861b1dde8be4c81cf44.png

用户发送消息表

无论是单聊还是群聊消息,都使用这个表来存储发送出去的消息。

im_message_send(msg_id,msg_from,msg_to,msg_seq,msg_content,send_time,msg_type)

其中:

msg_id:消息ID。

msg_from:消息发送者UID。

msg_to:消息接收者。如果是单聊消息那么就是用户UID,如果是群聊消息就是群ID。

msg_seq:客户端发送消息时带上的序列号,主要用于消息排重以及通知客户端消息发送成功之用。

msg_content:消息内容。

send_time:消息发送时间。

msg_type:消息类型,如单聊、群聊消息等。

用户接收消息表

im_message_recieve(id,msg_from,msg_to,msg_id,flag)

其中:

id:这个表的ID,自增。

msg_from:消息发送者ID。

msg_to:消息接收者ID。

msg_id:消息ID,对应发送消息表中的ID。

flag:标志位,表示该消息是否已读。

接收消息表的信息并没有很多,因为主体部分如消息内容、发送消息时间等都在发送消息表中。

cf48cc213432aa079e391c269bd94ace.png

分库分表及访问策略

发送消息表,根据msg_from字段做为分库分表的依据,而接收消息表则使用msg_to字段做为分库分表的依据。

另外,还需要添加缓存将群聊消息进行缓存,缓存的key为msg_to和msg_id的组合,这样查询具体群聊消息的时候就可以根据组ID来查询一条具体的消息了。

以上需要对存储之上的业务层完全透明,因此加上一个db proxy来处理消息的读写,除了应付这套流程以外,proxy的引入还有这些好处:

无状态,可以横向扩展。

下面的存储服务扩缩容的时候,proxy可以感知到变化,而这些对上面的应用层而言都是透明的。

有了这一层proxy之后,消息的读写流程如下。

写消息

收到用户发送过来的消息,db proxy做如下处理:

根据msg_from查询到哪个存储服务存储该发送消息,写入消息,同时得到写入成功之后的消息ID。

如果这条消息是一个群聊消息,此时根据群ID以及第一步返回的消息ID,写一条键为群ID以及消息ID组合,而值为消息内容的缓存数据到缓存中。

根据msg_to查询是哪个存储服务存储该接收消息,写入这部分信息。

7b460466c64ef9d0b290853cc21a97ea.png

读消息

读消息的过程反之:

根据msg_to查询是哪个存储服务存储该接收消息,查询到该消息之后就知道对应的msg_id。

根据第一步查询到msg_from以及msg_id来去发送消息表中查询消息,如果是群聊消息的话,可以首先组合这两个字段到缓存中查询,查询不到再查询数据库。

如果上面第二步中的群聊消息,在缓存中没有查询到,需要一个策略来向缓存中写入一份该群聊消息。

如果接收到用户已读该消息的应答,那么还需要再次根据msg_to查询该消息将flag字段变成用户已读状态。

登录之后拉取离线消息的优化

在第一篇基础篇中已经给出了拉取离线消息的基本流程,在这里还需要进行一些优化。

在实际的应用中,离线的群聊消息并不是需要每次登录都完整拉取下来的,因此这里可以做一个优化:登录时针对群聊消息仅拉取每个群的未读消息数量,用于客户端的展示,而实际消息内容的加载,可以等到用户真的点到这个群查看消息或者可以后台加载,总之不影响登录主流程即可。

细化了消息存储部分之后的整体架构如下图所示:

e8311bddf307aca67a621f36e32c6d3c.png

总结

采用pull模式为主的消息发送存储方式。

为了解决pull模式的读消息较重的问题,引入了以下组件:

db proxy来解决整个读写逻辑,这部分对业务层完全透明,同时proxy可以感知下面存储服务的扩缩容变更等。

群聊消息根据消息ID以及群ID写入缓存一份,不必每次都到存储服务器上面拉取消息。

使用另一个消息计数表来存储未读消息数量,登录之后群聊消息仅展示未读消息数量,这部分群聊消息可以延迟拉取或者后台拉取不影响客户端登录主流程。



推荐阅读
  • 基于PgpoolII的PostgreSQL集群安装与配置教程
    本文介绍了基于PgpoolII的PostgreSQL集群的安装与配置教程。Pgpool-II是一个位于PostgreSQL服务器和PostgreSQL数据库客户端之间的中间件,提供了连接池、复制、负载均衡、缓存、看门狗、限制链接等功能,可以用于搭建高可用的PostgreSQL集群。文章详细介绍了通过yum安装Pgpool-II的步骤,并提供了相关的官方参考地址。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • Linux如何安装Mongodb的详细步骤和注意事项
    本文介绍了Linux如何安装Mongodb的详细步骤和注意事项,同时介绍了Mongodb的特点和优势。Mongodb是一个开源的数据库,适用于各种规模的企业和各类应用程序。它具有灵活的数据模式和高性能的数据读写操作,能够提高企业的敏捷性和可扩展性。文章还提供了Mongodb的下载安装包地址。 ... [详细]
  • Oracle优化新常态的五大禁止及其性能隐患
    本文介绍了Oracle优化新常态中的五大禁止措施,包括禁止外键、禁止视图、禁止触发器、禁止存储过程和禁止JOB,并分析了这些禁止措施可能带来的性能隐患。文章还讨论了这些禁止措施在C/S架构和B/S架构中的不同应用情况,并提出了解决方案。 ... [详细]
  • vue使用
    关键词: ... [详细]
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • Tomcat/Jetty为何选择扩展线程池而不是使用JDK原生线程池?
    本文探讨了Tomcat和Jetty选择扩展线程池而不是使用JDK原生线程池的原因。通过比较IO密集型任务和CPU密集型任务的特点,解释了为何Tomcat和Jetty需要扩展线程池来提高并发度和任务处理速度。同时,介绍了JDK原生线程池的工作流程。 ... [详细]
  • flowable工作流 流程变量_信也科技工作流平台的技术实践
    1背景随着公司业务发展及内部业务流程诉求的增长,目前信息化系统不能够很好满足期望,主要体现如下:目前OA流程引擎无法满足企业特定业务流程需求,且移动端体 ... [详细]
  • 企业数据应用挑战及元数据管理的重要性
    本文主要介绍了企业在日常经营管理过程中面临的数据应用挑战,包括数据找不到、数据读不懂、数据不可信等问题。针对这些挑战,通过元数据管理可以实现数据的可见、可懂、可用,帮助业务快速获取所需数据。文章提出了“灵魂”三问——元数据是什么、有什么用、又该怎么管,强调了元数据管理在企业数据治理中的基础和前提作用。 ... [详细]
  • 深度学习中的Vision Transformer (ViT)详解
    本文详细介绍了深度学习中的Vision Transformer (ViT)方法。首先介绍了相关工作和ViT的基本原理,包括图像块嵌入、可学习的嵌入、位置嵌入和Transformer编码器等。接着讨论了ViT的张量维度变化、归纳偏置与混合架构、微调及更高分辨率等方面。最后给出了实验结果和相关代码的链接。本文的研究表明,对于CV任务,直接应用纯Transformer架构于图像块序列是可行的,无需依赖于卷积网络。 ... [详细]
author-avatar
手机用户2602918637
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有