场景题:让你设计一个微信发红包的api,你会怎么设计,不能有人领到的红包里面没钱,红包数值精确到分。

设计一个 微信发红包 API ,需要确保 所有红包总金额等于发出金额 ,并且 不能有红包为空 。以下是 API 设计思路

📝 需求分析

输入参数

• total_amount(int):红包总金额(单位:分)

• num_packets(int):红包个数(必须 ≤ total_amount)

• sender_id(string):发红包的用户 ID

• group_id(string):群 ID(可选)

• mode(string):分配模式,支持 "均分""随机"

输出

• 每个红包的金额

• 红包领取状态

约束条件

  1. 所有红包加起来的总金额必须等于 total_amount

  2. 每个红包至少 1 分,不能为 0

  3. 随机模式下,每个红包的金额应该有随机性

🚀 API 设计

请求方式

bash 复制代码
POST /api/send_red_packet
Content-Type: application/json
Authorization: Bearer <token>

请求参数

json 复制代码
{
  "total_amount": 1000,
  "num_packets": 5,
  "sender_id": "user_123",
  "group_id": "group_456",
  "mode": "random"
}

响应数据

json 复制代码
{
  "status": "success",
  "red_packet_id": "rp_789",
  "packets": [200, 180, 220, 190, 210]
}

🎯 关键实现

红包金额分配有两种模式:

  1. 均分模式(Equal Mode)

• 每个红包 amount = total_amount / num_packets。

• 可能存在除不尽的问题,需要把余数补到前几个红包

  1. 随机模式(Random Mode,二倍均值法)

保证每个红包最少 1 分

• 采用 二倍均值法 确保总额不变:

• 第 i 个红包的随机金额 r = random(1, 2 * 平均值 - 已分配最小值)。

• 递减分配,最后一个红包获得剩余金额。

🔧 代码实现(Python)

python 复制代码
import random

class RedPacket:
    def __init__(self, total_amount, num_packets):
        self.total_amount = total_amount
        self.num_packets = num_packets

    def split_equal(self):
        """均分模式"""
        avg = self.total_amount // self.num_packets
        remainder = self.total_amount % self.num_packets  # 余数

        packets = [avg] * self.num_packets
        for i in range(remainder):
            packets[i] += 1  # 补足余数

        return packets

    def split_random(self):
        """随机模式(二倍均值法)"""
        packets = []
        remaining_amount = self.total_amount
        remaining_packets = self.num_packets

        for i in range(self.num_packets - 1):
            max_amount = remaining_amount - (remaining_packets - 1)  # 保证至少留 1 分
            avg = remaining_amount // remaining_packets
            rand_amount = random.randint(1, min(max_amount, 2 * avg))  # 取随机值
            packets.append(rand_amount)
            remaining_amount -= rand_amount
            remaining_packets -= 1

        packets.append(remaining_amount)  # 最后一个红包

        return packets

# 示例调用
def send_red_packet(total_amount, num_packets, mode="random"):
    if total_amount < num_packets:
        return {"error": "每个红包至少 1 分"}

    rp = RedPacket(total_amount, num_packets)
    if mode == "equal":
        packets = rp.split_equal()
    else:
        packets = rp.split_random()

    return {
        "status": "success",
        "packets": packets
    }

# 运行示例
print(send_red_packet(1000, 5, "random"))  # 1000 分 5 个随机红包
print(send_red_packet(1000, 5, "equal"))   # 1000 分 5 个均分红包

🔍 API 设计要点

  1. 数据校验

• total_amount 不能小于 num_packets(每个红包至少 1 分)。

• num_packets 不能为 0。

  1. 高并发处理

• 采用 Redis 计数器防止超发:

arduino 复制代码
redis.decr("red_packet:rp_789:remaining_count")

• 采用 消息队列(Kafka/RabbitMQ) 处理领取请求,防止超卖。

  1. 安全性

• 认证方式:使用 JWT 鉴权(Authorization: Bearer )。

• 防刷机制:限制 单用户 1 秒内最多创建 3 个红包

🔥 终极优化方案

数据库设计

🎯 结论

最关键的是 "二倍均值法" ,保证总金额不变 ,每个红包至少 1 分

Redis & MQ 确保并发安全 ,防止超发、超领

API 设计清晰 ,支持 均分 / 随机模式

这套方案适用于 高并发场景 ,能处理 微信级别的红包系统!🚀

相关推荐
Dubhehug2 分钟前
4.B树和B+树的区别?为什么MySQL选择B+树作为索引?
数据库·b树·mysql·面试·b+树
何遇er5 分钟前
大厂的前端面试——低代码混合
低代码·面试
前端小巷子18 分钟前
Cookie与Session:Web开发中的身份验证与数据存储
前端·javascript·面试
汪子熙21 分钟前
Visual Studio Code 中排除指定文件夹搜索的最佳实践与实现原理
后端·面试
开开心心就好2 小时前
高效报价软件,简化商铺定价流程
服务器·数据库·安全·面试·职场和发展·电脑·symfony
yanlele10 小时前
我用爬虫抓取了 25 年 5 月掘金热门面试文章
前端·javascript·面试
小兵张健11 小时前
武汉拿下 23k offer 经历
java·面试·ai编程
爱莉希雅&&&11 小时前
技术面试题,HR面试题
开发语言·学习·面试
天天扭码12 小时前
《很全面的前端面试题》——HTML篇
前端·面试·html
zhuiQiuMX14 小时前
脉脉maimai面试死亡日记
数据仓库·sql·面试