深入探究微信群聊系统设计:从聊天到红包功能的全面解析

2024-10-18
来源:网络整理

本文来源:苏三说技术



一、简介

那天我拿着手机,在微信群里和朋友们聊着八卦新闻和即将到来的周末计划,突然一条喜气洋洋的消息传来,消息中间写着八个大字:恭喜发财!财富并祝你好运。

快来领取红包吧! !相信大多数人都对此很熟悉,但是微信的群聊系统是如何设计的,让我们可以轻松聊天、分享图片和表情,还有神奇的红包功能呢?

这个问题一直困扰着我,所以我决定深入研究一下微信群聊系统背后的设计到底是什么。

微信群聊系统设计

微信作为一个拥有10亿用户的全民应用,想必大家都用过。微信群功能是微信的核心能力。它可以将数百名朋友或陌生人放入一个群组空间中。

也许你多次体验过微信群聊,但你有没有好奇过这背后的系统是如何设计的?

今天我们来讨论一下。

2. 系统需求 2.1 系统特点及功能需求

微信群聊功能是社交应用的核心功能之一。它允许用户创建自己的社交圈并与家人、朋友或共同兴趣进行友好交流。

以下是微信群聊系统的核心功能:

2.2 非功能性需求:应对高并发、高性能、海量存储

当我们面对每天可能有10亿微信用户使用建群功能的场景时,我们需要处理大规模的用户并发。这就导致了系统的非功能性需求,包括:

3、外形设计

在总体设计中,我们考虑了系统核心组件和基础服务的总体设计。

3.1 核心组件

微信群聊系统将涉及以下核心组件和协议。

3.2 业务提纲设计群聊创建

除了招募好友建群之外,微信还可以实现面对面建群的功能。

接下来,我们深入探讨了面对面建群、消息收发、抢红包功能等三到四个核心功能的详细设计。

4. 面对面团建

用户发起面对面建群,输入4位随机码。周围用户输入随机码后即可加入群聊。面对面的团建功能通常涉及如下数据表设计和核心业务交互流程。

4.1 数据库表设计

用户表:存储用户信息,包括用户ID、昵称、头像等。

表:存储群组信息,包括群组ID、群组名称、创建者ID、群组成员数量等。

表:关联的用户和组,包括用户 ID 和组 ID。

表:存储面对面组创建的随机代码和关联的组 ID。

4.2 核心业务交互流程

用户A在移动应用程序中发起面对面群组创建并输入随机代码。验证通过后,等待周围(50米以内)用户加入。此时系统将用户信息以 的形式存储在缓存中,并设置过期时间为3分钟。

{随机码,用户列表[用户A(ID、名称、头像)]}

用户B在另一部手机上发起面对面建群,输入指定的随机码。如果用户身边有这样的随机码,他就会进入同一个群聊等待页面,并且可以看到其他群成员的头像和昵称。

此时,系统除了根据随机码获取所有用户信息外,还会实时更新缓存中的用户信息。

当第一个用户点击进群后,就可以加入群聊。系统将生成的随机码保存在表中,与新创建的群组ID关联,并更新群组成员数量。

然后系统将用户信息和新生成的群聊信息存储在表中

成员加入并刷新群组成员信息

随后,当用户B和C使用随机码加入群聊时,移动客户端向服务器后端发送请求,验证随机码是否有效。服务器后端对随机码进行验证,检查随机码是否存在于缓存中以及是否在有效期内。

然后判断当前群成员是否已满(目前普通用户创建的群聊最大人数为500人)。如果验证通过,服务器后端将用户B和C添加到群组成员表中,并返回成功响应。

移动客户端应用程序收到成功响应后,会更新用户 B 和 C 的群聊列表,以显示他们加入的新群聊。

其他技术组件

这样,用户A通过创建随机码,周围用户扫描二维码,成功建立了面对面群组。该功能涉及多个技术组件,包括分布式缓存、数据库、二维码生成与验证等。

同时,面对面建群过程中一个非常重要的能力就是识别用户所处的区域,比如50米以内。该算法可用于获取一定范围内的所有用户信息。

5. 消息发送和接收

当成员在微信群中发言时,系统需要处理消息的分发,通知其他成员,并保证消息的显示。下面是该功能的详细交互步骤,以及数据库存储方案。

5.1 交互过程

消息发送和接收时序图如下:

用户A在群内发送带有图片、视频或音频的消息。

移动客户端应用程序将消息内容和媒体文件上传到服务器后端。

服务器后端收到消息和媒体文件后,将消息内容存储到表中,并将媒体文件存储到分布式文件存储集群中。在该表中,不仅记录了媒体文件以便将消息和媒体关联起来;还记录了媒体文件。还记录缩略图、视频封面图像等。

服务器后端将向所有群组成员广播此消息。移动客户端应用程序收到消息后,会根据消息类型(文本、图片、视频、音频)加载相应的显示方法。

当用户点击查看图片、视频或音频缩略图时,客户端应用程序将从对象存储集群中获取相应的媒体文件路径并将其显示给用户。

此过程可确保消息和媒体文件的高效存储和呈现。用户可以上传和查看各种类型的媒体数据,而服务器后端通过关联和对象存储来自服务器的信息来实现高效的消息存储和呈现。

5.2 消息存储与显示

在微信群中保存和展示用户的图片、视频或音频数据通常需要数据存储和展示设计。除了上面面建群功能中提到的用户表和组表外,还需要如下表结构:

表:用于存储消息。每条消息都有唯一的消息类型(文本、图片、视频、音频)、消息内容(文本、图片缩略图、视频封面图等)、发送者、接收组、发送时间等字段。

表:存储用户上传的图片、视频、音频等媒体数据。每个媒体文件都有唯一的文件路径、上传者、上传时间等字段。

表:用于存储用户消息状态,包括用户ID、是否已读等。推送消息时,通过此表计算未读消息,统一推送给用户,离线时显示少量用户的手机来代表未读消息。

我们知道,每次触发查询类型语句时,都会触发全表扫描,所以每次消息加载和未读时,速度都很慢。

微信群不接收群消息_微信收起群消息_微信群直接收某人消息

出于查询性能的考虑,我们可以存储用户的消息条数,并实时记录一个未读值。并且,当未读值大于99时,未读值被设置为100并且不再增加。

推送用户消息时,只要未读值为100,推送消息条数设置为99+,以提高存储性能和交互效率。

6.抢红包

抢红包功能允许用户在群聊中发送任意数量和金额的红包。群成员可以抢随机金额的红包,但每个用户的红包金额不得低于0.01元。

抢红包详细交互流程如下:

用户收到抢红包通知,点击通知打开群聊页面

用户点击抢红包,后台服务验证用户资格,确保用户没有收到红包。

如果用户资质通过验证,后台将分配红包金额并保存领取记录。

用户在微信群中看到收到金额,红包状态更新为“已收到”

异步调用支付接口更新红包金额到钱包

抢红包功能需要关注抢红包的数据库设计、实时抢红包以及红包分发算法。

6.1 数据库设计

红包表字段如下:

该表用于记录用户已经发送了多少红包以及需要维护的剩余金额。

红包记录表如下:

记录表用于存储用户抢到的具体红包信息,也是红包表的子表。

6.2 实时 1. 红包发送

用户设置好红包总量和数量后,在红包表中添加一条数据,开始发送红包。

为了保证抢红包的实时性和效率,添加一条记录来存储红包ID和总人数n

向所有群成员推送红包消息

2.抢红包

从2015年开始,微信抢红包和开红包是分开的。用户点击抢红包后需要进行两次操作。这就是为什么有时你抢了一个红包,打开后却发现红包已经收了。

抢红包互动步骤如下:

抢红包:抢红包操作​​在缓存层完成,通过原子递减操作更新红包数量。当达到0时,说明所有红包都被抢光了。

开红包:开红包时,首先会实时计算金额,通常是通过双均值法(即剩余平均值的0.01到2倍之间)。

红包记录:用户获取红包金额后,通过数据库交易操作累计收到的数量和金额,并更新红包表和记录表。

转账:为了提高效率,最终的转账是异步操作,这也是为什么春节期间红包收到后不能立即在余额中看到的原因。

6.3 红包分发算法

红包金额分发时,由于是随机分发,因此有两种实现方案:实时拆分和预生成。

1. 实时分裂

实时分红是指在抢红包时实时计算每个红包的金额,实现红包分红过程。

这就需要我们设计一个好的分割算法,这样在分割红包的时候,始终保证后续分割的红包金额不能为空。

实时分割时,要保证分割的红包数量服从正态分布规律并不容易。

2. 预生成

预生成是指在抢红包之前已经分割了红包金额。抢红包时,只按顺序取出分割的红包金额。

该方法对分割算法要求较低,可以分割红包金额,随机性较好,但通常需要与队列配合使用,并且需要额外设计一张表来存储分割后的红包金额。

3.双重平均法

考虑到以上优缺点,以及微信群聊人数较少(目前最多500人),我们采用实时拆分,使用双均值方法生成随机红包,仅满足随机性,不需要是正数。状态分布。

所以,可能会有很大的红包差价,但是这样更刺激不是吗?

随机数采用双均值法生成,每次随机数在0.01~剩余平均值*2之间。

假设当前剩余红包金额为10元,剩余数量为5,10/5=2,则当前用户可抢到的红包金额在0.01~4元之间。

4.算法优化

虽然使用双均值法生成的随机红包接近平均值,但我之前在论坛上看到过类似的说法:微信红包金额的随机性与领取时机有关,尤其是当金额为不高。

于是,小❤花了很多钱在微信上发出了多个红包,并得出了结论:如果发送的红包总数=红包数量*0.01+0.01,例如:发送了4个红包,总金额为0.05,那么最后一份收到的红包金额一定是0.02。

无一例外:

因此,大概率红包金额算法并不是随机分配的,而是在红包发放之前就已经经过处理的。例如,在生成红包金额之前,生成了一个不存在的红包。本次红包总额为0.01*红包总数。

发放红包金额时,会在每个红包的随机值上加上0.01,保证每个红包的最小值不为0。

因此,假设用户发送了3个红包,总金额为0.04,他需要先提取3*0.01到“第四个”不存在的红包中,所以第一个人抢到的红包的随机值为0~(0.04-3*0.01)/3。

因为担心红包超出限额,所以除数的商取小数点后两位,0 ~ (0.04-3*0.01)/3 ==> (0 ~ 0) = 0,加上之前提取的最小值为0.01,所以前两个红包抢到的金额为0.01。最后一个红包的金额就是红包余额,为0.02。

算法逻辑用Go语言实现如下:

import (
   "fmt"
   "math"
   "math/rand"
   "strconv"
)

type RedPack struct {

    SurplusAmount float64 // 剩余金额

    SurplusTotal int // 红包剩余个数

}

// 取两位小数

func remainTwoDecimal(num float64) float64 {

    numStr := strconv.FormatFloat(num, 'f', 2, 64)

    num, _ = strconv.ParseFloat(numStr, 64)
    return num
}

// 获取随机金额的红包
func getRandomRedPack(rp *RedPack) float64 {
    if rp.SurplusTotal <= 0 {
        // 该红包已经被抢完了
        return 0
    }

    if rp.SurplusTotal == 1 {
        return remainTwoDecimal(rp.SurplusAmount + 0.01)
    }

       // 向下取整
    avgAmount := math.Floor(100*(rp.SurplusAmount/float64(rp.SurplusTotal))) / float64(100)
    avgAmount = remainTwoDecimal(avgAmount)

       // 生成随机数种子
    rand.NewSource(time.Now().UnixNano())

    var max float64
    if avgAmount > 0 {
        max = 2*avgAmount - 0.01
    } else {
        max = 0
    }
    money := remainTwoDecimal(rand.Float64()*(max) + 0.01)

    rp.SurplusTotal -= 1
    rp.SurplusAmount = remainTwoDecimal(rp.SurplusAmount + 0.01 - money)

    return money
}

func main() {
    rp := &RedPack{
        SurplusAmount: 0.06,
        SurplusTotal:  5,

    }

    // 每个红包先保留 0.01 的余额

    rp.SurplusAmount -= 0.01 * float64(rp.SurplusTotal)
    total := rp.SurplusTotal
    for i := 0; i < total; i++ {
        fmt.Println(getRandomRedPack(rp))
    }
}

打印结果:

0.01, 0.01, 0.01, 0.01, 0.02

符合预期!

七、总结

微信群聊、抢红包等功能的背后,有复杂的交互技术和精心设计的产品体验。通过这些核心组件、数据库表和详细的交互流程,用户可以轻松参与并享受群聊系统带来的便利。

而且,这些有趣功能的加入,也是微信拥有如此多用户的原因之一!

微信群建功能的系统设计不仅是技术的华丽展示,也是数字社交的魔力之一。

传智教育黑马程序员

各个学科的课程现已开放

基础班优惠价28元

分享