12306订单,比如我们买了一张票,一般会给30分钟的支付时间,如果30分钟内没有支付,则系统会自动取消订单,然后释放锁定座位。
那么超时订单有哪几种实现方式呢?
1、数据库轮询(30S)
订单表(订单ID,状态,创建时间)
轮询数据库会带来什么问题?
2、使用DelayQueue 实现
DelayQueue: 阻塞队列(先进先出)
Delayed接口使对象成为延迟对象,它使存放在DelayQueue类中的对象具有了激活日期。该接口强制实现下列两个方法。
应用重启带来的问题
解决之道
从系统伸缩性角度考虑:应用集群化了怎么办?
集群化了会带来什么问题?应用之间会相互抢夺订单,特别是在应用重启的时候,重新启动的那个应用会把不属于自己的订单,也全部加载到自己的队列里去,一是造成内存的浪费,二来会造成订单的重复处理,而且加大了数据库的压力。
解决方案:
1、 给每台服务器编号,然后在订单表里登记每条订单的服务器编号;2,更简单的,在订单表里登记每台服务器的IP地址,修改相应的sql语句即可。
几个问题:如果有一台服务器挂了怎么办?运维吃干饭的吗?服务器挂了赶紧启动啊。如果是某台服务器下线或者宕机,起不来怎么办?这个还是还是稍微有点麻烦,需要人工干预一下,手动把库里的每条订单数据的服务器编号改为目前正常的服务器的编号,不过也就是一条sql语句的事,然后想办法让正常的服务器进行处理(重启正常的服务器)。
能不能同时解决伸缩性和扩展性问题?
用delayqueue是队列,分布式情况我们何不直接引入消息中间件呢?一举解决我们应用的伸缩性和扩展性问题
我们可以使用ActiveMQ的延迟和定时投递
3、ActiveMQ延迟队列
修改配置文件(activemq.xml),增加延迟和定时投递支持
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.data}" schedulerSupport="true">
需要把几个描述消息定时调度方式的参数作为属性添加到消息,broker端的调度器就会按照我们想要的行为去处理消息。
一共有4个属性:
ActiveMQ也提供了一个封装的消息类型:org.apache.activemq.ScheduledMessage,可以使用这个类来辅助设置,使用例子如:延迟60秒
MessageProducer producer = session.createProducer(destination); TextMessage message = session.createTextMessage("test msg"); long time = 60 * 1000; message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time); producer.send(message);
例子:延迟30秒,投递10次,间隔10秒:
TextMessage message = session.createTextMessage("test msg"); long delay = 30 * 1000; long period = 10 * 1000; int repeat = 9; message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, delay); message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_PERIOD, period); message.setIntProperty(ScheduledMessage.AMQ_SCHEDULED_REPEAT, repeat); 也可使用 CRON 表达式,如message.setStringProperty(ScheduledMessage.AMQ_SCHEDULED_CRON, "0 * * * *");
也可使用 CRON 表达式,如message.setStringProperty(ScheduledMessage.AMQ_SCHEDULED_CRON, "0 * * * *");
4、Redis有序集合
Redis 有序集合
Redis sortedSet 集合(sorted set 也叫zset) 是一个有序集合,每个元素(member)都关联了一个score,可以通过score排序获取集合中的值。
zset常用命令:
将订单超时时间戳(long)与订单号分别设置为score与member,系统扫描第一个元素判断定是否超时,拿到分数最小的,超时时间最早的。判断与当前时间戳的关系
生产者
消费者
5、Redis Set 集合
将订单延迟时间的秒级时间戳设置为set集合的key,value 为订单ID
sadd set的key item的项值,item项可以有多个
按秒级的时间进行聚合,即 key为时间戳,里面可以由多个ID
总结
1、DB轮询
2、DelayedQueue
3、redis
优点 ; 解耦、异常恢复、支持分布式/集群环境
缺点
领取专属 10元无门槛券
私享最新 技术干货