并发部分的通关Boss: 生成、发放大量红包并控制资金流速
大Boss来啦!
这是一道阿里让求职者带回家做的面试题。要求求职者将代码在面试前发送到面试官的邮箱。这样的题目设计的目的是为了检查求职者的思考和Coding能力。。
题目内容
Hi,到了年底了,Wo信公司决定发1亿元红包给1000W个用户:
- 红包金额平均在1元左右(随机)
- 用户会抢红包,红包:用户是1:n的关系。(假设所有红包都会被领取)
- 红包发送要控制速率,这是为了持续发酵用户的感情,举个例子:若要求在1000s内发完,那么平均每秒发出去的金额在10W元。
- 时间不一定是1000s,时间是随时可以改变的输入
对红包和用户的抽象如下:
public class RedPacket {
private int id; // 请实现自增逻辑
private int money; // 单位分
private byte state; // 0-未发送 1-已发送
// 增加难度无意义字段,让红包不要太小
// 水平不够可以删除字段简化题目
// transient 的意思就是不用持久化,但是内存中得存在
transient byte[] padding = new byte[1024];
private RedPacket(int money){
this.money = money;
}
public static RedPacket create(int money) throws InterruptedException {
Thread.sleep((long) (1000 + (Math.random() * 1000)));
// 创建红包的逻辑
}
static class FailToSendException extends Exception {
}
public static void sendTo(User user) throws InterruptedException, FailToSendException {
// 模拟发送,什么都不做
Thread.sleep((long) (1000 + (Math.random() * 1000)));
if(Math.random() > 0.99) {
throw new FailToSendException();
}
}
}
public class User {
private int id; // 请实现自增逻辑
private String name; // 请Mock一个名字
// 增加难度无意义字段,让红包不要太小
// 水平不够可以删除字段简化题目
// transient 的意思就是不用持久化,但是内存中得存在
transient byte[] padding = new byte[1024];
public User(String name){
this.name = name;
}
}
因为生成红包、发送红包都有一定的I/O成本,这里用Thread.sleep替代。生成红包的I/O成本是1~2秒/个,见RedPacket.create方法,请补全实现。
发送红包的RedPacket.send方法成本是1-2秒发送1个,但是有1%的概率失败,如果失败就需要重新发送。
public static void sendTo(User user) throws InterruptedException, FailToSendException {
Thread.sleep((long) (1000 + (Math.random() * 1000)));
if(Math.random() > 0.99) {
throw new FailToSendException();
}
// 记录用户的红包(别忘记排名)
}
要做的事情:
生成用户、红包,并保存到磁盘上(自己设计格式)。
用户并发抢红包不用真的模拟万级QPS的并发,但请画出服务器如何解决这种并发情况的架构图。
红包发送程序是通过读取磁盘程序工作
请你画出你红包发送部分的架构图
请实现你的算法
统计出获得红包最多的100个用户姓名和金额