场景题:让你设计一个微信发红包的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 设计清晰 ,支持 均分 / 随机模式

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

相关推荐
拉不动的猪8 小时前
TS常规面试题1
前端·javascript·面试
Joseit9 小时前
从零打造AI面试系统全栈开发
人工智能·面试·职场和发展
江城开朗的豌豆9 小时前
JavaScript篇:"闭包:天使还是魔鬼?6年老司机带你玩转JS闭包"
前端·javascript·面试
江城开朗的豌豆10 小时前
JavaScript篇:解密JS执行上下文:代码到底是怎么被执行的?
前端·javascript·面试
数据艺术家.12 小时前
Java八股文——Redis篇
java·redis·缓存·面试·nosql数据库·nosql·八股文
想用offer打牌13 小时前
面试官问我:库存预扣减之后,用户订单超时之后怎么补偿库存?我的方案让他满意...
后端·面试·架构
用户05956611920914 小时前
互联网公司校招 Java 面试题总结及答案含实操示例
java·面试
lecepin15 小时前
前端技术月刊-2025.6
前端·javascript·面试
零狐冲16 小时前
您的 ”芝士“ 外卖 《React 18》 已送达。速来领取!!!
前端·react.js·面试
真的没有脑袋16 小时前
机器学习基础相关问题
人工智能·算法·机器学习·计算机视觉·面试