未付款订单占用库存的MQ实现方案

用户下完订单到支付完成期间,需要锁定库存防止超卖,如何不依赖数据库,实现较高负载呢?

常见的方案是频繁的读取数据库中的订单,统计总库存占用,检查是否付款超时。如果系统的负载量较高,这种方案很快将数据库的CPU占用达到极限,系统响应速度迅速下隆。

我在一个项目中应用了消息队列(RabbitMQ)的方案实现的这个需求,分享一下。

简化流程:

下单时,第一步要操作的,就是遍历订单里的商品列表,将商品数量累加到 Redis 库存占用上,防止超卖。

在商品详情页,展示的 商品可用库存 = 商品库存 - 库存占用

第二步操作,将订单写入MQ队列,因为订单是按时间顺序写入队列的,所以最先失效的订单一定是队首的订单。因此,计划任务只需要循环检查队首的订单

  • 如果订单付款时间未超时,假如还有 50 秒,则休眠 50 秒后继续处理。
  • 如果订单已到达超时时间,则检醒订单原始状态
  • 如果订单原始状态已非未付款(如已付款,已取消),则将订单移出队列,处理下一单
  • 如果订单原始状态仍为未付款,则释放库存占用

注意,取消订单操作需要主动释放库存占用。

计划任务内流程:

在我们的项目中,有一种特殊 VIP 的用户,他们的未付款超时时间长达12小时(普通用户半小时),他们常用这种方式免费锁定库存,我们暂不关注这种需求的合理性,系统如何实现呢?

在MQ中加一条队列即可,半小时超时的一个队列,12小时超时的一个队列

本文原始网址:未付款订单占用库存的MQ实现方案,转载请保留出处

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
这里提供一个Java语言实现MQ代码示例,基于Apache Kafka: 发送消息代码: ```java import java.util.Properties; import org.apache.kafka.clients.producer.Producer; import org.apache.kafka.clients.producer.ProducerRecord; import org.apache.kafka.clients.producer.KafkaProducer; public class MQProducer { private String topic; private Properties props; private Producer<String, String> producer; public MQProducer(String topic) { this.topic = topic; this.props = new Properties(); props.put("bootstrap.servers", "localhost:9092"); props.put("acks", "all"); props.put("retries", 0); props.put("batch.size", 16384); props.put("linger.ms", 1); props.put("buffer.memory", 33554432); props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); this.producer = new KafkaProducer<>(props); } public void sendMessage(String message) { producer.send(new ProducerRecord<>(topic, message)); } public void close() { producer.close(); } } ``` 消费消息代码: ```java import java.util.Properties; import org.apache.kafka.clients.consumer.Consumer; import org.apache.kafka.clients.consumer.ConsumerRecords; import org.apache.kafka.clients.consumer.KafkaConsumer; import org.apache.kafka.common.TopicPartition; public class MQConsumer { private String topic; private Properties props; private Consumer<String, String> consumer; public MQConsumer(String topic) { this.topic = topic; this.props = new Properties(); props.put("bootstrap.servers", "localhost:9092"); props.put("group.id", "test"); props.put("enable.auto.commit", "true"); props.put("auto.commit.interval.ms", "1000"); props.put("session.timeout.ms", "30000"); props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); this.consumer = new KafkaConsumer<>(props); consumer.subscribe(Collections.singletonList(topic)); } public String receiveMessage() { ConsumerRecords<String, String> records = consumer.poll(1000); String message = ""; for (TopicPartition partition : records.partitions()) { List<ConsumerRecord<String, String>> partitionRecords = records.records(partition); for (ConsumerRecord<String, String> record : partitionRecords) { message = record.value(); } long lastOffset = partitionRecords.get(partitionRecords.size() - 1).offset(); consumer.commitSync(Collections.singletonMap(partition, new OffsetAndMetadata(lastOffset + 1))); } return message; } public void close() { consumer.close(); } } ``` 以上代码是基于Apache Kafka的实现,你也可以使用其他MQ实现,例如RabbitMQ等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值