即时消息技术剖析与实战
袁武林
微博研发中心技术专家
24187 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 25 讲
即时消息技术剖析与实战
15
15
1.0x
00:00/00:00
登录|注册

11 | 期中实战:动手写一个简易版的IM系统

代码示例
实时性的三种常见方式
总未读和会话未读的存储格式
联系人列表设计
消息索引表设计
消息内容表设计
用户表设计
加上ACK机制、应用层心跳等特性
调整为WebSocket长连接的方式
实现消息的实时触达
未读数的设计
消息的存储
提供的Demo作为参考
以自己动手实现为主
通过Embedding方式提升代码对IDE的友好性及代码的可迁移性
合理的代码分层规划
理论与实践相结合的动手实战
依赖资源
代码分层
消息和未读自动更新
消息未读数支持
文本聊天消息存储
用户登录
支持聊天页有新消息时自动更新
支持联系人页和未读数有新消息的自动更新
支持消息未读数
双方支持简单的文本聊天
支持用户登录
期末实战
期中实战Demo关注点
期中和期末实战
小结
其他实现上的注意点
需求分析
需求梳理
课程计划和设计思路
期中实战:动手写一个简易版的IM系统
参考文章

该思维导图由 AI 生成,仅供参考

你好,我是袁武林。
到上一讲为止,IM 的相关课程已经进行过半,在前面的课程中,我们讨论的大部分内容都比较偏理论,你理解起来可能会比较抽象。为了让你对前面讲到的知识有更深入的理解,今天我们就来回顾、梳理近期学习的内容,一起尝试搭建一个简单的 IM 聊天系统。
在开始之前呢,我先来说明一下 IM 课程的期中、期末实战的课程计划和设计思路。
期中和期末实战是希望你以自己动手实现为主,提供的 Demo 主要作为参考,在设计层面上,并不能让你直接用于线上使用。
本次期中实战 Demo 的主要关注点是:消息的存储、未读数的设计,并以“短轮询”的方式来实现消息的实时触达。希望你能从用户的使用场景出发,来理解消息存储设计的思路,以及未读数独立两套存储的必要性。
另外,在期末实战中,我会从“短轮询”方式调整为 WebSocket 长连接的方式,并且加上 ACK 机制、应用层心跳等特性。希望你能在两次实战中,通过对比,真正理解长连接方式相比“短轮询”方式的优势,并且通过 ACK 机制和应用层心跳,真正理解为什么它们能够解决“数据丢失”和“连接可靠性”的问题。
OK,下面我们说回本次实战。
这个聊天系统要求并不复杂,只需要构建简单的 Web 界面(没有界面通过命令行能实现也行)。我在这里写了一个简易版的 Demo,供你参考。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入介绍了如何动手写一个简易版的IM系统,通过期中、期末实战的课程计划和设计思路,强调了实战Demo的关注点和调整。详细讲解了需求梳理和需求分析,包括用户登录、文本聊天、消息存储、未读数设计以及消息和未读自动更新的实现方式。强调了代码分层的重要性,以及表现层、业务层和持久化层的分离和职责明确。全文以实战的方式帮助读者理解IM系统的设计和实现,涵盖了技术细节和实际应用,对于想要深入了解IM系统开发的读者具有一定的参考价值。期中实战的演示代码并没有完全覆盖之前课程讲到的内容,鼓励读者在代码实现时加入更多的特性,如长连接、心跳、ACK机制、未读原子化变更等。通过脚踏实地的代码实现,将理论知识变成真正可用的系统,能够帮助读者进一步加深对IM系统核心技术的理解。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《即时消息技术剖析与实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(20)

  • 最新
  • 精选
  • 王蒙
    Embedding方式是什么意思

    作者回复: 就是嵌入到jvm里的一些中间件和db,web容器这些,随着jvm启动也能跟着一起run起来,用起来比较方便。

    2019-10-17
    7
  • 不焦躁的程序员
    只是基于redis吗?没用到netty吗?

    作者回复: 期中实战只是个简易版demo哈,期末的实战会基于目前轮询的方式进行长连接改造,再加上ack和心跳等功能,这样也让大家能对“消息推送实时性”的实现方案有一个比对。 另外,实战的目的是让大家自己尝试结合课程前面的内容来练手加深对知识的理解,所以提供的demo并不具备线上可用性,只是一个简单的参考。

    2019-09-20
    3
  • kamida
    老师 我想问一下 分库分表的问题 如果MSG_CONTENT的partition是mid 而MSG_RELATION的partition key 是onwer id 那么如果我们要查询两个用户之间所有的msg及其内容的话 我们需要去每一个DB shard去查找msg_content table 这样会不会很慢 或者这个查询需求是不必要的?

    作者回复: 这个查询需求是存在的,但由于一般我们都是分页查询,所以针对某一页的消息内容进行multi get的并发查询实际上性能上也是可以接受的。

    2020-03-12
    1
  • 飞翔
    CREATE INDEX `idx_owneruid_otheruid_msgid` ON IM_MSG_RELATION(`owner_uid`,`other_uid`,`mid`); 老师 消息索引表中 为什么要创作(`owner_uid`,`other_uid`,`mid`); 这三个的联合索引 呀

    作者回复: 分页的时候会用到。比如: select msgid from IM_MSG_RELATION where owner_uid=? and other_uid=? and mid <= ? order by mid desc limit ?,?

    2019-09-22
    1
  • 飞翔
    消息内容表: CREATE TABLE IM_MSG_CONTENT ( mid INT AUTO_INCREMENT PRIMARY KEY, content VARCHAR(1000) NOT NULL, sender_id INT NOT NULL, recipient_id INT NOT NULL, msg_type INT NOT NULL, create_time TIMESTAMP NOT NUll ); 老师 消息内容表中的sender_id INT NOT NULL, recipient_id INT NOT NULL, 这两个字段是不是有些多余?

    作者回复: 嗯,是冗余了一下,主要是方便离线统计和后台使用,业务上可以不需要。

    2019-09-22
    1
  • 山头
    消息索引表: CREATE TABLE IM_MSG_RELATION ( owner_uid INT NOT NULL, other_uid INT NOT NULL, mid INT NOT NULL, type INT NOT NULL, create_time TIMESTAMP NOT NULL, PRIMARY KEY (`owner_uid`,`mid`) ); CREATE INDEX `idx_owneruid_otheruid_msgid` ON IM_MSG_RELATION(`owner_uid`,`other_uid`,`mid`); ownerid otherid是什么意思?张三给李四发一条消息,在这个表里存几条数据呢

    作者回复: 会存两条,咱们课程2里面有讲过的哦

    2019-09-21
    1
  • Geek_908e99
    老师我看更新未读数的逻辑并没有用到redis事务,我看到的就是下面两行,这个实现不能保证原子性吧: /**更未读更新 */ redisTemplate.opsForValue().increment(recipientUid + "_T", 1); //加总未读 redisTemplate.opsForHash().increment(recipientUid + "_C", senderUid, 1); //加会话未读

    作者回复: 嗯,这个demo没有用lua来保障原子性,所以是会存在并发更新的一致性问题,有兴趣的话可以尝试来优化改造试试哈,核心lua代码在文章中有。

    2019-11-14
  • Geek_defa2f
    能不能期中期末实战的代码分开部署在github上,现在才学到,发现期中的代码被期末的代码覆盖了。。。

    作者回复: 期末的代码基本没有覆盖期中的哈,都是独立的功能和实现,页面也都是独立的。

    2019-10-18
  • yic
    消息索引表: CREATE TABLE IM_MSG_RELATION ( owner_uid INT NOT NULL, other_uid INT NOT NULL, mid INT NOT NULL, type INT NOT NULL, create_time TIMESTAMP NOT NULL, PRIMARY KEY (`owner_uid`,`mid`) ); CREATE INDEX `idx_owneruid_otheruid_msgid` ON IM_MSG_RELATION(`owner_uid`,`other_uid`,`mid`); 老师,消息索引表这么创建,请教一下群发(500人群)消息,是不是要插入500条记录? 如果是插库的话,性能能保证吗?

    作者回复: 群发消息qps很高的话就不要用mysql这种关系型数据库啦,另外也不需要发件人维度的消息存储,可以考虑采用hbase这类nosql数据库来存储索引。

    2019-10-05
    2
  • 王棕生
    感谢老师的总结和源码分享!

    作者回复: 😺 谢谢

    2019-09-25
收起评论
显示
设置
留言
20
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部