美文网首页
设计聊天系统

设计聊天系统

作者: 尚无花名 | 来源:发表于2019-03-19 08:19 被阅读0次

https://www.slideshare.net/brizzzdotcom/facebook-messages-hbase

设计what's app, facebook messenger, wechat
要求支持群聊


4.7. 2019的第二版

Clarify

Scenario

Api

sendMessage(userId, content, timestamp, thread)
GetRecentMessage(userId)

Services

Chat Service
User Service

image.png

Storage

Relations:

User Table

user id, name, password (md5), last login

Thread Table

ThreadId, userId threadName, participant ids, createdAt, lastUpdatedAt,

Message Table

ThreadId, MessageId, content (Message Id包含timestamp和senderId)

Message User Table

MessageId, UserId, ReadOrNot
其实这个table有点大, 可以不做,用user的last pulled time来做就好。 这个要跟面试官讨论。
具体某个消息我pull下来但是没有读过,可以由本地的客户端来处理。

加速查询/Index

use case是要时间倒序显示thread
对一个thread要按显示最近的message
对一个用户要看他在哪个thread里面。
对同一组人,看它之前有没有开过一个会话。

所以对thread table要按userId + last updatedAt 建index(就是这个index要经常更新),
对message table, 要按threadId + messageId 建index(这个是只读操作倒还好, messageId是按 timeStamp生成的) 。
MessageTable的messageId用timestamp + userId来实现。
为了实现对同一组人不建两个群聊的方法, 可以有如下两种做法:

  1. 对thread table按participantIds(String) 建index,
    查的时候先根据用户的id,去确定哪台机器上肯定有。然后在这台机器上找有没有这个participantsIds,
    participantId内部要排序。
    2。 也可以单独建一个participantIds Thread table. 先生成 participantIds字符串,再去对应的机器上查找有没有这个thread, 这样虽然多了一张表,但是这张表很小呀。第一种方式那个index文件其实也可以是蛮大的。

分页

Select * From thread table where userId = user1 order by lastUpdatedAt desc
offset 10 fetch next 50.

Scale

Sharding:
User table按user id sharding,
thread table 按user id sharding
message table 按thread id sharding
messageUser table按user id sharding (这个表可要可不要)
如果是Slack channel的话,对于一个post下面可能有回复。
这的话可以在message table里面加一个parent message 那一项。

消息推送服务

用户上线之后可以每十秒钟问服务器要一下我最新的inbox,
getMostRecentMessages(userId)
Post(user, Id, threadId, content),
Post(user, Id, participantIds, content)
对于实时性要求高的聊天来说,需一个real time service给用户进行推送。
用户登录以后,web server会给用户指派一个real timer server让用户去联接,用户用web socket和real time server保持联接。
另外一个用户B给这个用户A发消息后,消息服务会找到用户所在的real time service 推送给用户A。
如果是群聊的话, 消息服务直接发找到群聊的channel service, 让channel去考虑推送给谁。


3.31.2019的第一版。

Clarify
1。是否需要保存聊天记录。
2。 如果用户不在线了, 是否向用户移动端发push notification?(先不考虑)

Scenario:

1。多人聊天,发送消息,查看消息,保留聊天记录
2。列出用户参与的聊天小组
3。 给定聊天小组 列出最近的聊天记录
4。支持实时聊天

  1. 用户在线状态
  2. 支持FB Scale

其他功能: 历史消息, 多机登录

设计多牛的系统:

MAU, DAU, QPS,都 要仔细 算一算
存储。
写多读少还是读多写少? 写多读少。因为有fanout。上线了才算读。但发消息是一条一条发的。

Service

User1 - Chat Server - Data Storage
User2 |
\
Real Timer server
Message service
Real time service

Working solution

用户登录服务器, 服务器拿着user id去thread table查询用户有哪些会话最近更新了, 并按倒序排序。对每个会话去message table查询它有多少条是未读的。对于每个thread列出最近的一条用来preview。返回给客户端前20条。
用户刚开始通过http协议连接。最基本的操作是用户每十秒钟去找服务器要一下最新的消息。
优化后用户连上之后服务器会给用户安排一个real time service服务器地址, 用户连接那个real time service, 一量有新的消息,就会推送给用户。

发消息: 用户通过Chat Server向Message Table和Thread Table写入最近的消息。

B用户发了消息之后, web service会通过real time service把消息推送给A
用户通过heartbeat来向服务器请安保持存在感。(heartbeat的信息是不是不需要存在table里面,存在内存里就好了吧 ? )

群聊:

群聊的问题是当一条信息发出去之后,服务器可能需要向所有人push消息,如果那个人不在线或者很久没有活跃了,就会浪费资源。 所以对每个群聊,系统保持记录谁还在线,收到消息时只推送给那些在线的用户。 A用户发了消息之后,ThreadBroadCastingTube(其实是channel service , 为了和slack的channel区分起了这个怪名字 ) 看群里还有谁在线, 不在线的话,就不发了。只推送给在线的人。不在线的人登录之后才会看到。

几个难点:

根据最新消息的时间排序 支持分页 如何实现?
为了加快速度,这个要对thread table 按照 owner id + updatedTime 建立index
用数据库读的时候, page number 1, size 30 , 翻滚的时候 再拿 30条

time stamp secondary.
messageId, key, timestamp,
给定聊天小组 列出最近的聊天记录(根据消息发送时间排序 支持分页)如何实现
要对message table根据ThreadId + createdTime 进行secondary index
难点? 如果用no sql实现 message table, 则不好进行secondary index。
用Canssandra应该可以实现,三层结构,Row key 可以是 thread id, colum key是message id...

标记已读如何实现?

增加一个message_user table

Storage

是点对点聊天吗 ? 需要经过服务器吗?需要存下来吗?
User Table (userId, name, password)
Message Table (messageId, userId, threadId, senterId, content, timeStamp, readOrNot)
Thread Table (threadId, channelId, userId, participantIds, createdAt, mutedOrNot, lastUpdatedTime )
SlackChannel Table (channelId, channel_name, description, create date)
Subscription Table (channelId, userId)

ThreadBroadCastingTube(ThreadId, ListOfActiveIds) 这个并不需要存table, 直接内存就可以。

Message Table也可以拆成 Message Table 和 MessageUser Table:
Message Table (messageId, userId, threadId, senterId, content, timeStamp, readOrNot)
MessageUser Table (messageId, userId, readOrNot)

用什么数据库
User Table, 用 SQL, 原因结构化的,不经常改
Message Table 用Cassandra: 原因,只有写操作,不会修改,只有。 支持根据Thread然后按messageId 查询。 (Message Id可以前缀放个时间戳)

关于Thread Table里面Participant_ids的问题 :
Thread Table里面为什么 Participant_ids不用拆开,不会经常更新
为什么 like table 必须要拆开 : 很多操作。不能进行原子操作,所以要拆开。
相比存单独的表有什么 好处?查的快。如果用单独的表,还得join。这个操作太频繁了 。

有些Thread信息是私有的 比如isMuted, 未读的,呢称。所以还有些细节需要处理。
需要把Thread table增加一个owner id, 谁的thread.
A, B 聊天会在Thread table里产生 两条记录

在数据库里最好少用join
uuid??

用什么 样的数据库

Message Table存在 No SQL
Thread Table存在SQL.

Owner ID + thread ID (primary index)
Owner ID + updated time (按更新时间排序)
同时可以给participant id建 index,这样如果三个人聊天以前建过群聊就不用再建新的群聊了。

Scale

  1. 按什么sharding?
    User table按user id sharding
    message table按thread id sharding

  2. 如何建index
    哪些地方要建index,
    Thread Table 要对 thread id 按 user id + updated time 建 index
    Message Table里面如果用了Canssandra的话,可以直接进行range query(假设message id是按那个时间排序的),就不需要再建index了。

Working Solution

如何发消息
Client把消息和接受者信息发给服务器
Server创建thread(如果不是已经存在的话)
创建一条message (with thread)
如何收消息
每隔十秒钟要一次
有新信息就通知用户

相关文章

  • 设计聊天系统

    https://www.slideshare.net/brizzzdotcom/facebook-messages...

  • 蓝牙通信app设计文档

    功能模块拆分 系统流程 数据库聊天记录缓存设计

  • 设计微信的聊天系统

    Intro 一开始是被邀回答这个问题, 如果好设计微信, 需要学哪些技术? 我觉得时间比空口罗列技术关键词要稍微有...

  • 工作小结和聊天系统设计

    最近一段时间在做优化,继续关注线上bug,额外是安全,压测和容灾相关的工作。 先总结下这段时间发现的问题,主要是稳...

  • 2018-06-14 群里小论聊天系统后台怎么存聊天记录

    杨老板在群里讨论了一个系统设计题的内容。 聊天系统后台怎么存聊天记录? 开宇提出declearing 看需求了 什...

  • 系统设计(八)

    1. 系统设计 什么是系统设计 系统设计需要掌握哪些知识 如何设计和实现一个后端系统服务的设计 系统设计是一个初高...

  • 设计系统 Design Systems

    什么是设计系统?为什么要使用设计系统?如何建立设计体统?设计系统有没有弊端?有哪些相关的资源? 什么是设计系统? ...

  • 自制聊天系统

    今天是星期五,周末又到了,又是一个人在家路代码的黄金时期,这次给大家分享一个用js做的在线聊天界面。 1 参数设置...

  • 简单聊天系统

    之前在 f2e-server 里面做了一个有关监听文件更新,实时刷新预览页面的功能,基于这个原理做一个实时消息的推...

  • IM聊天系统

    编解码 protobuf 视频 webrtc 服务器netty 传送门:https://github.com/zh...

网友评论

      本文标题:设计聊天系统

      本文链接:https://www.haomeiwen.com/subject/smjvmqtx.html