11 | 期中实战:动手写一个简易版的IM系统
11 | 期中实战:动手写一个简易版的IM系统
讲述:袁武林
时长10:04大小9.20M
需求梳理
需求分析
其他实现上的注意点
代码分层
依赖资源
小结
赞 4
提建议
精选留言(20)
- 王蒙2019-10-17Embedding方式是什么意思
作者回复: 就是嵌入到jvm里的一些中间件和db,web容器这些,随着jvm启动也能跟着一起run起来,用起来比较方便。
6 - Ricky Fung2019-10-24建议 期中 和 期末考试作业 代码可以分两个分支,这样大家看起来更直观。5
- 燃着的半支烟2019-09-20只是基于redis吗?没用到netty吗?
作者回复: 期中实战只是个简易版demo哈,期末的实战会基于目前轮询的方式进行长连接改造,再加上ack和心跳等功能,这样也让大家能对“消息推送实时性”的实现方案有一个比对。 另外,实战的目的是让大家自己尝试结合课程前面的内容来练手加深对知识的理解,所以提供的demo并不具备线上可用性,只是一个简单的参考。
3 - kamida2020-03-12老师 我想问一下 分库分表的问题 如果MSG_CONTENT的partition是mid 而MSG_RELATION的partition key 是onwer id 那么如果我们要查询两个用户之间所有的msg及其内容的话 我们需要去每一个DB shard去查找msg_content table 这样会不会很慢 或者这个查询需求是不必要的?
作者回复: 这个查询需求是存在的,但由于一般我们都是分页查询,所以针对某一页的消息内容进行multi get的并发查询实际上性能上也是可以接受的。
1 - 飞翔2019-09-22CREATE 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 ?,?
1 - 飞翔2019-09-22消息内容表: 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, 这两个字段是不是有些多余?展开
作者回复: 嗯,是冗余了一下,主要是方便离线统计和后台使用,业务上可以不需要。
1 - 山头2019-09-21消息索引表: 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里面有讲过的哦
1 - 林晓威2023-01-16 来自广东老师觉得聊天数据库用mongodb会不会更合适?
- ahack2021-10-16新手,redis这个表看不懂要怎么建,有没有大佬jies一下呢
- DeenJun2020-11-08请教个问题:之前讲的IM服务划分为业务逻辑和连接层两部分,连接层负责维护连接和编解码消息。并且看之前课程讲,一般各厂都设计了一套私有协议而没有用MQTT,但是这部分讲得比较略。我的问题是,长连接的两端发送请求都是oneway的吗?有req-resp模型吗?比如说客户端通过长连接发送了一个请求A,这时候服务端又推送了一条消息,然后再发送请求A对应的response。客户端就必须要能够区分哪个包是对应哪个请求的resp还是仅仅是服务端主动推送的。服务端也同理。一般是怎么做呢?长连接的协议需要设计成 oneway + req-resp都支持这种模式,还是说就仅仅是oneway这种模式,推了就完事儿,需要resp的请求走另外的服务不走长连接?如果在协议中支持,有推荐的开源协议吗?一般长连接的私有协议需要考虑连接的多路复用吗?问题有点多,期待老师的回答…展开共 1 条评论
- Geek_908e992019-11-14老师我看更新未读数的逻辑并没有用到redis事务,我看到的就是下面两行,这个实现不能保证原子性吧: /**更未读更新 */ redisTemplate.opsForValue().increment(recipientUid + "_T", 1); //加总未读 redisTemplate.opsForHash().increment(recipientUid + "_C", senderUid, 1); //加会话未读展开
作者回复: 嗯,这个demo没有用lua来保障原子性,所以是会存在并发更新的一致性问题,有兴趣的话可以尝试来优化改造试试哈,核心lua代码在文章中有。
- 五点半先生2019-10-20搬运,https://github.com/coldwalker/Sample
- Geek_defa2f2019-10-18能不能期中期末实战的代码分开部署在github上,现在才学到,发现期中的代码被期末的代码覆盖了。。。
作者回复: 期末的代码基本没有覆盖期中的哈,都是独立的功能和实现,页面也都是独立的。
- yic2019-10-05消息索引表: 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数据库来存储索引。
共 2 条评论 - 王棕生2019-09-25感谢老师的总结和源码分享!
作者回复: 😺 谢谢
- YidWang2019-09-24消息 没有重复 设计
- Geek_发现2019-09-24老师你好,我启动项目报错org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'embededRedis': Invocation of init method failed; nested exception is java.lang.RuntimeException: Can't start redis server. Check logs for details. 我redis是启动了的,端口号也是6379,怎么回事呢?
作者回复: 还有其他报错吗?比如“This redis server instance is already running...”或者“Failed to start Redis instance”。可以断点跟进到start方法里去看看。
共 6 条评论 - 给我点阳光就灿烂2019-09-23即使通讯的消息可不可以不存在数据库中而已消息队列的形式代替呢
作者回复: 存消息队列的问题在于你需不需要按会话维度啥的来进行查询,分页等等。如果不需要,可以只根据uid维度来暂存消息和信令。
- leslie2019-09-23期中考试 、、、还是等期末考试的时候一起做吧,看的懂写不来,出去的都是伪代码:忙起来就发现写这个东西自己的Coding太差了,被Coding能力拖后腿了:谁让这是DBA和OPS的通病呢、、、
作者回复: 建议还是动手写一写,一码胜千言~
- 飞翔2019-09-23老师 有一个问题 对于redis 事务 redisTemplate.multi(); redisTemplate.opsForValue().increment(recipientUid + "_T", 1); //加总未读 redisTemplate.opsForHash().increment(recipientUid + "_C", senderUid, 1); //加会话未读 redisTemplate.exec(); 假设第一个加总未读失败, 事务并不会停止,而是继续进行,第二个加会话未读, 这样不也是数据就不一致了嘛, redis 事务完全和没有一样呀?展开
作者回复: 是的,redis的事务只保证这些命令原子执行,执行过程中就算有命令失败,队列中的其他命令也会被执行,所以调用方需要根据返回结果来进行二次处理。