对于秒杀类似的高并发大流量处理问题,采用消息中间件处理比较合适。网上大部分解决方式似乎都在消费者端,采用basicQos限制消息取出个数,basicAck手动处理执行结果。其实很大部分不需要到消费者来处理,直接限制死队列的消息数,拒绝超过指定消息数的请求。可以考虑使用控制队列长度来完成。rabbitmq默认是超过数量的先废弃或进入死信,文档有个overflow的参数可以指定废弃的顺序,默认dropHead,改为reject-publish后会废弃最新的消息。
public Queue queue() {
return QueueBuilder
.nonDurable("mk")
.maxLength(3)
.overflow(QueueBuilder.Overflow.rejectPublish)
.build();
}
然而,通过测试发现,不管设置reject-publish或drop-head均没效果,都是采用废弃最新的消息,这样就无法满足我们秒杀的排队规则。也试过使用每次获取队列数量来控制队列消息数,但测试发现耗时太高。
public void getMessageCount() {
long a = ToolKang.getUnixTimeDateMillisecond();
String queue = "mk";
AMQP.Queue.DeclareOk declareOk = template.execute(new ChannelCallback<AMQP.Queue.DeclareOk>() {
public AMQP.Queue.DeclareOk doInRabbit(Channel channel) throws Exception {
return channel.queueDeclarePassive(queue);
}
});
long b = ToolKang.getUnixTimeDateMillisecond();
}
Redis自增key 的好处
原子性(atomicity):一个事务是一个不可分割的最小工作单位,事务中包括的诸操作要么都做,要么都不做。
Redis所有单个命令的执行都是原子性的,这与它的单线程机制有关;
Redis命令的原子性使得我们不用考虑并发问题,可以方便的利用原子性自增操作
简单解释就是你的服务即使是多机器多进程的,incr也能保证每次返回的结果不会出现相同的值。
通过自增来实现队列数量的控制,效果比较好,同时也减轻消费端的压力,在源头就限制了队列消息数量。(虽然消费端也控制了读取数量)