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

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

相关推荐
C4程序员3 小时前
北京JAVA基础面试30天打卡14
java·开发语言·面试
秋名山码民3 小时前
面试压力测试破解:如何从容应对棘手问题与挑战
面试·职场和发展·压力测试
ERP老兵_冷溪虎山8 小时前
从ASCII到Unicode:"国际正则"|"表达式"跨国界实战指南(附四大语言支持对比+中医HIS类比映射表)
后端·面试
一块plus9 小时前
创造 Solidity、提出 Web3 的他回来了!Gavin Wood 这次将带领波卡走向何处?
javascript·后端·面试
Aphasia3119 小时前
性能优化之重绘和重排
前端·面试
掘金安东尼10 小时前
代理式AI,从被动响应到主动执行的技术演进
面试
Java技术小馆13 小时前
InheritableThreadLoca90%开发者踩过的坑
后端·面试·github
诗和远方149395623273414 小时前
iOS 异常捕获原理详解
面试
希尔伯特旅馆14 小时前
市值残差Alpha策略
面试
我是哪吒15 小时前
分布式微服务系统架构第167集:从零到能跑kafka-redis实战
后端·面试·github