听说你会架构设计?来,弄一个群聊系统( 二 )

  • 数据库服务器集群:用于存储用户文本数据、图片的缩略图、音视频元数据等;
  • 分布式文件存储集群:存储用户图片、音视频等文件数据 。
  •  
    3.2 业务概要说明在业务概要说明里,我们关注用户的交互方式和数据存储......
    面试官:稍等一下 , 群聊系统的好友建群功能比较简单,拉好友列表存数据就可以了!你用过面对面建群吧,可以简要说一下如何设计面对面建群功能吗?
    我:(内心 OS,还好之前在吃饭时用过面对面建群结账 , 不然就G了),好的,群聊系统除了拉好友建群外,还支持面对面建群的能力 。
     
    4. 面对面建群用户发起面对面建群后,系统支持输入一个 4 位数的随机码,周围的用户输入同一个随机码便可加入同一个群聊 , 面对面建群功能通常涉及数据表设计和核心业务交互流程如下 。
    4.1 数据库表设计
    1. User 表:存储用户信息 , 包括用户 ID、昵称、头像等 。
    2. Group 表:存储群组信息 , 包括群 ID、群名称、创建者 ID、群成员个数等 。
    3. GroupMember 表:关联用户和群组 , 包括用户 ID 和群 ID 。
    4. RandomCode 表:存储面对面建群的随机码和关联的群 ID 。
     
    4.2 核心业务交互流程
    听说你会架构设计?来,弄一个群聊系统

    文章插图
    图片
    用户 A 在手机端应用中发起面对面建群,并输入一个随机码 , 校验通过后 , 等待周围(50 米之内)的用户加入 。此时,系统将用户信息以 HashMap 的方式存入缓存中,并设置过期时间为 3min 。
    {随机码,用户列表[用户A(ID、名称、头像)]}用户 B 在另一个手机端发起面对面建群,输入指定的随机码,如果该用户周围有这样的随机码,则进入同一个群聊等待页面,并可以看到其它群员的头像和昵称信息 。
    此时,系统除了根据随机码获取所有用户信息,也会实时更新缓存里的用户信息 。
    听说你会架构设计?来,弄一个群聊系统

    文章插图
     
    成员A进群当第一个用户点击进入该群时,就可以加入群聊 , 系统将生成的随机码保存在 RandomCode 表中,并关联到新创建的群 ID,更新群成员的个数 。
    然后,系统将用户信息和新生成的群聊信息存储在 Group、GroupMember 表中,并实时更新群成员个数 。
     
    成员B加入然后,B 用户带着随机码加入群聊时,手机客户端向服务器后端发送请求,验证随机码是否有效 。后台服务检查随机码是否存在于缓存中,如果存在 , 则校验通过 。
    然后,根据 Group 中的成员个数,来判断当前群成员是否满员(目前普通用户创建的群聊人数最多为 500 人) 。
    如果验证通过,后台将用户 B 添加到群成员表 GroupMember 中,并返回成功响应 。
    面试官:如果有多个用户同时加入,MySQL 数据库如何保证群成员不会超过最大值呢?
    我:有两种方式可以解决 。一个是通过 MySQL 的事务,将获取 Group 群成员数和插入 GroupMember 表操作放在同一个事务里,但是这样可能带来锁表的问题,性能较差 。
    另一种方式是采用 redis 的原子性命令incr 来记录群聊的个数,其中 key 为群聊ID,value 为当前群成员个数 。
    当新增群员时,首先将该群聊的人数通过 incr 命令加一 , 然后获取群成员个数 。如果群员个数大于最大值,则减一后返回群成员已满的提示 。
    使用 Redis 的好处是可以快速响应,并且可以利用 Redis 的原子特性避免并发问题,在电商系统中也常常使用类似的策略来防止超卖问题 。
     
    位置算法同时,在面对面建群的过程中相当重要的能力是标识用户的区域,比如 50 米以内 。这个可以用到 Redis 的 GeoHash 算法,来获取一个范围内的所有用户信息 。
    由于篇幅有限 , 这里不展开赘述,想了解更多位置算法相关的细节,可以看我之前的文章:听说你会架构设计?来 , 弄一个公交&地铁乘车系统 。
    面试官:嗯不错,那你再讲一下群聊系统里的消息发送和接收吧!
     
    5. 消息发送与接收我:当某个成员在微信群里发言,系统需要处理消息的分发、通知其他成员、以及确保消息的显示 。


    推荐阅读