需求是要支持春节百万并发高并发抢购红包商品。
架构师经过多方技术调研,整理开发以下几个核心步骤:
1.使用redis缓存icon支持高并发
2.商品数据量先存入缓存icon中
3.抢购商品锁定,并从缓存中读取数量减1
4.释放商品锁
代码
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RAtomicLong;
import org.redisson.config.Config;
public class RedPacketPurchaseService {
private static final Redisson redisson = initRedisson();
private static final String PRODUCT_ID = "product_id";
private static final String STOCK_KEY = "stock:" + PRODUCT_ID;
private static final String LOCK_KEY = "lock:" + PRODUCT_ID;
private static Redisson initRedisson() {
Config config = new Config();
config.useSingleServer().setAddress("redis://localhost:6379");
return Redisson.create(config);
}
public boolean purchase() {
RLock lock = redisson.getLock(LOCK_KEY);
try {
// 使用公平锁并设置超时时间防止死锁
if (lock.tryLock(10, TimeUnit.SECONDS)) {
try {
RAtomicLong stock = redisson.getAtomicLong(STOCK_KEY);
if (stock.decrementAndGet() > 0) {
System.out.println("用户成功抢购一个红包商品,剩余库存: " + stock.get());
// 这里省略了持久化到数据库的操作,实际应用中需要异步保存购买记录
return true;
} else {
// 库存不足,正常情况下不需要还原库存,这里仅作为演示
stock.incrementAndGet();
}
} finally {
lock.unlock();
}
} else {
System.out.println("当前抢购人数过多,请稍后再试");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("线程中断,抢购失败");
}
return false;
}
// 在服务启动时或者定时任务中预加载商品库存至Redis Atomic Long
public void preloadStock(int initialStock) {
RAtomicLong stock = redisson.getAtomicLong(STOCK_KEY);
stock.set(initialStock);
}
}
**注意事项**:
- 上述代码使用了Redisson提供的`RLock`实现分布式锁,并结合`RAtomicLong`进行原子性的库存扣减,能在一定程度上保证在高并发下的数据一致性。
- 实际生产环境中还需要考虑更多的因素,如网络延迟、服务器性能、数据库写入瓶颈等,并可能需要引入更复杂的策略,例如队列、延时消息队列(如RabbitMQ或RocketMQ)、降级处理等手段来确保系统的稳定性和可用性。
- 另外,为了应对百万级甚至更高的并发,通常还会对系统进行水平扩展,增加服务器数量并通过负载均衡器分配请求,同时也要注意数据库层面的优化和分库分表等操作。