单体架构 IM 系统之核心业务功能实现

news2024/11/24 15:39:50

在上一篇技术短文(单体架构的 IM 系统设计)中,我们讨论了在 “用户规模小、开发人员少、开发时间短” 的业务背景下,采取 “怎么简单怎么做,怎么快怎么来” 的研发策略,于是设计了 单体架构的IM系统,并分析了 “通讯协议、编程语言和数据库” 的技术选型。我们快速复习一下单体架构的 IM 系统,见下图。

单体架构 IM 系统的每个组件描述如下:

  1. 客户端是一个业务组件,嵌入在游戏 APP 中运行;

  2. 客户端通过 http 这种非常简单的短连接的协议方式访问后端的 server;

  3. 一个 server 程序实现了后端所有的业务逻辑,不过是多个 server 节点集群化部署的(这就是典型的单体架构);

  4. server 节点直接访问数据库和缓存;在数据库中分别创建消息表、离线消息表、联系人表和用户表,消息表用来存储用户的历史记录消息,离线消息表用来存储用户不在线时收到的消息; 缓存用来记录用户是否在线的状态。

在该单体架构中,前端与后端的通讯协议是 http,也就是说所有的业务流程动作都是由前端触发的,server 端只是被动响应即可;从这一点出发也足以看出,为了降低 server 逻辑的复杂性,选择 http 通讯协议的必要性。基于该架构,我们讨论一下 IM 核心业务逻辑的实现,包括:用户状态维护、点对点消息收发、云消息。

一、 用户状态维护

用户状态是什么状态呢?就是用户的 “在线” 和 “离线” 状态。很多同学可能会有疑惑,不是基于 “长连接协议” 的客户端才会有 “在线” 和 “离线” 这一回事吗? http 是无状态化的短连接,难道也有 “在线” 一说? 是的,客户端在线与否,其实与通讯协议并不是强相关的,协议仅仅是传递数据的方式而已,甚至我们用 http 比用 tcp 更能精准表达出用户的状态。

通过 http 协议表达用户的在线状态,这一块技术实现应该非常成熟了;大家不妨思考一下,当我们登录163邮箱,把浏览器关闭,10分钟后再次访问 163 邮箱,是不需要重新登录的;这就是 http 实现用户在线状态的关键。

单体架构 IM 系统实现用户状态维护的核心逻辑,见下图。

  • 登录
    • 客户端向 server 端发送 http 登录请求;

    • 因为客户端是嵌入在游戏 APP 中运行的,游戏会有登录逻辑,所以 server 只需要调用游戏侧的登录服务进行鉴权校验即可;

    • 登录成功后,server 向 redis 中写入 <uid, {type, cmd, time}> 这样一个 kv 的 session 数据,并设置该 session 的有效期 10秒; type 描述客户端的类型,cmd 描述客户端请求server的接口,time描述写记录的时间。

后续,客户端访问 server 端其他所有接口时,server 读 redis ,如果对应的 session 不存在,说明用户未登录或登录已失效,需要重定向引导客户端重新登录。

  • 心跳
    • 客户端向 server 端周期性(2秒)发送 http 心跳请求;

    • server 延长 redis 中对应 session 的有效期,并修改 session 的 cmd 和 time 属性。

  • 登出
    • 客户端向 server 端发送 http 登出请求;

    • server 直接删除 redis 中对应的 session 数据。

在该单体架构的 IM 系统中,对用户状态的维护,就是对 redis 缓存中 session 数据的维护; 在客户端访问 server 其他接口时,server 也会对 session 的有效期和 cmd、time 属性进行修改。

二、 点对点消息收发

消息收发是 IM 系统最核心的功能;基于 http 协议的单体架构 IM 系统的 “点对点消息收发“ 逻辑见下图。

  • 消息收发
    • client1 向 server 端发送 http 消息请求;

    • server 端向数据库中分别写入 “离线表” 和 “云消息表”;(离线表和云消息表在同一个数据库中,通过数据库保证其事务性)

    • client2 向 server 端周期性(2秒)发送 http 拉取消息请求;(拉取消息复用心跳请求)

    • server 端从数据库 “离线表” 中读取 client2 相关记录后返回;

    • client2 再次发送拉取消息请求时,携带上次已经成功拉取的消息msgid,server 端删除 “离线表” 中相关记录。

整个消息的收发逻辑并不复杂,【发消息】和【收消息】动作完全由客户端触发,server 端被动响应即可;我们把这样的消息收发模型叫做 【信箱模型】。很明显,信箱模型的实现非常简单,缺点是消息的及时性不高,取决于客户端的心跳动作。

在整个消息的收发逻辑中,有两个细节点需要注意:“离线表” 通常在消息接收方离线时存储其消息,而在该实现逻辑中, server 端不管 client2 是否在线都会直接将消息持久化在 “离线表” 中, 这样处理的原因在于防止 clien2 没有及时拉取消息而造成消息丢失,提高了消息的可靠性; 再一个,当 client2 从 “离线表” 中拉取消息时,不能立刻将其删除,必须在下次拉取时进行删除,这也是消息可靠性的体现。

三、 云消息

所谓 “云消息”,指存储在云端的消息,这样的消息可以被反复拉取,用来查看历史记录和实现消息漫游;在上述的消息收发逻辑中,每次客户端发消息时,server 端都会在 “云消息表” 中保存一条记录,所以客户端随时随地都能实现对云消息的读取。见下图。

  • 云消息
    • client 向 server 端发送 http 拉取历史消息请求;

    • server 端从云消息表中读取相关记录返回。

最后,总结文中关键:

1、“信箱模型” 由客户端主动向服务端发送请求,服务端被动响应即可;该模型实现简单,但作为 IM 系统来说,消息的实时性不高;

2、 基于 “信箱模型” 的单体架构 IM 系统,用户的在线状态通过在 redis 中保存有有效期的 session 来实现,并通过客户端的周期心跳实现 session 的持续有效;

3、 基于 “信箱模型” 的单体架构 IM 系统,发消息的逻辑是发送方向 “离线表” 和 “云消息表” 写入消息记录,收消息的逻辑是接收方从 “离线表” 中读取消息记录; 云消息表用来实现消息的历史记录读取和消息漫游。

在该单体架构的 IM 系统中, server 端完全是无状态化的,在 server 节点负载较高时,可以通过增加 server 节点轻松实现集群扩容,应对不断增长的同时在线用户数。

大家思考一下:在该架构中,消息的实时性不高,应该如何优化呢?优化时需要解决什么问题呢?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2238761.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux部署nginx访问文件403

问题描述&#xff1a;在linux服务器上通过nginx部署&#xff0c;访问文件403 新配置了一个用户来部署服务&#xff0c;将部署文件更新到原有目录下&#xff0c;结果nginx访问403 原因&#xff1a;没有配置文件的读写权限&#xff0c;默认不可读写&#xff0c;nginx无法访问到文…

解决 C/C++ 中 “invalid use of incomplete type” 编译错误

解决 C/C++ 中 “invalid use of incomplete type” 编译错误 一、错误原因二、常见场景三、解决方法四、最佳实践五、总结在 C 和 C++ 编程中,invalid use of incomplete type 错误通常发生在尝试使用一个未完全定义的类型时。这个错误表明编译器在当前上下文中没有足够的信息…

使用 Python 实现高效网页爬虫——从获取链接到数据保存

前言 在这个时代,网络爬虫已成为数据分析与信息收集不可或缺的技术之一。本文将通过一个具体的Python项目来介绍如何构建一个简单的网络爬虫,它能够自动抓取指定网站的文章链接、标题、正文内容以及图片链接,并将这些信息保存为CSV文件。 目标网站 一、准备工作 在开始编…

C# 有趣的小程序—桌面精灵详细讲解

C# 桌面精灵详细讲解 最近写了一个简化版桌面精灵&#xff0c;效果如图所示&#xff0c;可以实现切换动画&#xff0c;说话、鼠标拖动&#xff0c;等功能。具体如何做&#xff0c;我发布了一个资源里面包含ppt详解、源代码以及动画素材。放心吧&#xff0c;免费的&#xff0c;…

微软日志丢失事件敲响安全警钟

NEWS | 事件回顾 最近&#xff0c;全球最大的软件公司之一——微软&#xff0c;遭遇了一场罕见的日志丢失危机。据报告&#xff0c;从9月2日至9月19日&#xff0c;持续长达两周的时间里&#xff0c;微软的多项核心云服务&#xff0c;包括身份验证平台Microsoft Entra、安全信息…

Mysql ERROR 1451 (23000) 外键处理异常

通过临时设置外键失效&#xff0c;来规避报错 第一步 # 临时设置外键失效 SET FOREIGN_KEY_CHECKS 0; 第二步&#xff1a;执行更新或者删除操作 第三步&#xff1a; # 操作结束后恢复外键 SET FOREIGN_KEY_CHECKS 1;

智慧社区可视化解决方案:科技引领社区服务与管理新篇章

随着社会的发展&#xff0c;智慧社区作为新型城镇化发展目标和社区服务体系建设的重要举措&#xff0c;正逐步改变着我们的生活方式。智慧社区通过综合运用现代科学技术&#xff0c;整合区域资源&#xff0c;提升社区治理和服务水平&#xff0c;为居民提供更为便捷、高效、安全…

基于redis实现API接口访问次数限制

一&#xff0c;概述 日常开发中会有一个常见的需求&#xff0c;需要限制接口在单位时间内的访问次数&#xff0c;比如说某个免费的接口限制单个IP一分钟内只能访问5次。该怎么实现呢&#xff0c;通常大家都会想到用redis&#xff0c;确实通过redis可以实现这个功能&#xff0c…

【go从零单排】Ticker

&#x1f308;Don’t worry , just coding! 内耗与overthinking只会削弱你的精力&#xff0c;虚度你的光阴&#xff0c;每天迈出一小步&#xff0c;回头时发现已经走了很远。 &#x1f4d7;概念 在 Go 语言中&#xff0c;Ticker 是一个用于定期执行某些操作的工具。它属于 tim…

C++《stack与queue》

在之前的章节我们学习了C当中string、vector和list三种容器并且试着模拟实现这三种容器&#xff0c;那么接下来在本篇当中我们将STL当中的stack和queue&#xff0c;并且在学习stack和queue的使用之后和之前一样还会试着模拟实现stck和queue。由于stck和queue的模拟实现较为简单…

网页web无插件播放器EasyPlayer.js点播播放器遇到视频地址播放不了的现象及措施

在数字媒体时代&#xff0c;视频点播已成为用户获取信息和娱乐的重要方式。EasyPlayer.js作为一款流行的点播播放器&#xff0c;以其强大的功能和易用性受到广泛欢迎。然而&#xff0c;在使用过程中&#xff0c;用户可能会遇到视频地址无法播放的问题&#xff0c;这不仅影响用户…

【前端】HTML标签汇总

目录 展示用户信息的标签 1.文本标签 span 2.标题标签 h1~h6 3.竖着布局的标签 div 4.段落标签 p 5.超链接标签 a 5.1跳转至网上的资源 5.2锚点 6.列表标签 6.1有序列表 ol 6.2无序列表 ul 7.图片标签 img 7.1相对路径 7.1.1兄弟关系 7.1.2叔侄关系 7.1.3表兄弟…

xtu oj 加一

样例输入# 2 4 1 2 3 4 4 3 2 4 1样例输出# 3 5 解题思路&#xff1a;最小操作次数一定是把所有数变成数组中最大值max。 1、找最大值&#xff0c;一开始我把max初始值设为0&#xff0c;如果a[i]>max,maxa[i],WA了。又看了一遍题目&#xff0c;发现所有整数的绝对值小于…

Windows10/11开启卓越性能模式 windows开启卓越性能电源模式 工作电脑开启卓越性能模式 电脑开启性能模式

Windows10/11开启卓越性能模式 windows开启卓越性能电源模式 工作电脑开启卓越性能模式 电脑开启性能模式 1、所要用到的激活工具2、开启电脑卓越性能模式Windows11Windows10在电源模式中选择卓越性能模式 3、将系统版本切换为 工作站版本 1、所要用到的激活工具 KMS激活工具(…

人工智能、机器学习与深度学习:层层递进的技术解读

引言 在当今科技快速发展的时代&#xff0c;人工智能&#xff08;AI&#xff09;已经成为一个热门话题&#xff0c;几乎渗透到了我们生活的方方面面。从智能手机的语音助手&#xff0c;到自动驾驶汽车&#xff0c;再到医疗诊断中的图像识别&#xff0c;人工智能的应用正在改变我…

光流法(Optical Flow)

一、简介 光流法&#xff08;Optical Flow&#xff09;是一种用于检测图像序列中像素运动的计算机视觉技术。其基于以下假设&#xff1a; 1.亮度恒定性假设&#xff1a;物体在运动过程中&#xff0c;其像素值在不同帧中保持不变。 2.空间和时间上的连续性&#xff1a;相邻像素之…

OkHttp网络请求框架

添加依赖 在 build.gradle 文件中添加 OkHttp 依赖&#xff1a; dependencies {implementation("com.squareup.okhttp3:okhttp:4.10.0") }使用OkHttp发起GET请求 同步请求 public class MainActivity extends AppCompatActivity {// Used to load the okhttptes…

《XGBoost算法的原理推导》12-14决策树复杂度的正则化项 公式解析

本文是将文章《XGBoost算法的原理推导》中的公式单独拿出来做一个详细的解析&#xff0c;便于初学者更好的理解。 我们定义一颗树的复杂度 Ω Ω Ω&#xff0c;它由两部分组成&#xff1a; 叶子结点的数量&#xff1b;叶子结点权重向量的 L 2 L2 L2范数&#xff1b; 公式(…

使用postmain 测试下载文件接口

文章目录 前言使用postmain 测试下载文件接口 前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&#xff0c;收藏一键三连啊&#xff0c;写作不易啊^ _ ^。   而且听说点赞的人每天的运气都不会太差&#xff0c;实在白嫖的话&#xff0c;那欢迎常来啊!!…

Python函数详解

目录 一、函数的定义 二、函数的特性 三、函数参数 四、返回值 五、文档字符串 六、高级函数 七、偏函数 八、装饰器 总结 在Python编程中&#xff0c;函数是构建程序的基本模块&#xff0c;它提供了一种封装特定任务的方式&#xff0c;使得代码更加模块化、可重用和易…