JavaJava 杂谈java Web

消息队列详解,使用redis做秒杀思路详解

2019-07-29  本文已影响312人  唯有努力不欺人丶

因为明天要面的公司要求看起来像是做商城业务的。所以今晚赶紧啃一下高并发和秒杀等常见业务。其实工作经验中虽然有类似商城的项目,但是并没有很注意高并发(当时是外包业务,甲方有自己的团队,所以我们基本上只给实现了功能)。所以我这里用的都是redis。然后再声明一下,我做的都是demo!最简版。理论上是可以实现秒杀的。但是真正跑起来还要测试。
首先说一下术语的介绍:

消息队列

其实所谓的消息队列,仔细分析名字也不是很难理解。就是把需要处理的消息都排成队列处理。用一个实际情况来理解:有时候我们去买火车票(春运期间的人流量),如果大家没有规则都在售票窗口围着,就可能出现各种情况,谁先来的没先买到,谁挤谁了,谁踩谁脚了,谁和谁打起来了,谁把售票的小姐姐打死了,完了,大家都买不了票了,而且还容易一起进局子!所以这种情况下我们要排队。
同样消息队列也差不多是这样的。有时候访问的多了,一个服务器处理不过来了,就一个个先排着队处理。这个其实有个前提就是访问的要愿意等一会儿。不过电脑的反应又不是售票,要那么久,可能几十几百个访问需要的速度也就几秒钟,大多数时候用户是不注意的,而且我们还很鸡贼的给个假反应。比如说秒杀的时候,人家就截取前一千个,其实你点抢的时候就已经注定没你份了,但是因为电脑没算出来,所以这个时候页面告诉你,抢购中~~结果抢购了几秒钟再给你刷个页面,商品抢完了。这种情况大家应该多多少少遇到了,虽然具体的实现是不一样的,但是操作就是类似于消息队列的操作。
我觉得这么说完起家应该对消息队列有一个明确的理解和认识了。我这个题目是秒杀,所以应该都是用消息队列实现的。

消息队列的类别

就跟代码可以用c,java,php等等,消息队列也有多种实现方式。但是因为我们用到消息队列本身就是为了解决高并发,所以用数据库做消息队列太傻了,一般都是使用中间件。
这里简单说一下官方的消息队列的使用场景:当不需要立即获得结果,但是并发量又需要进行控制的时候,差不多就是需要使用消息队列的时候。
然后消息队列的种类很多:当前使用较多的消息队列有RabbitMQ、RocketMQ、ActiveMQ、Kafka、ZeroMQ、MetaMq等,而部分数据库如Redis、Mysql以及phxsql也可实现消息队列的功能。
然后我其实并没有专门使用过消息队列,都是使用redis临时做做秒杀,所以真正的mq中间件也没实际上使用过,最多就是看看文档做做demo,而且现在只接触过ActiveMQ。不过我看了好多介绍,所以在这里也共享一下各个mq的性能比较(我也是找个各种数据贴,最下面会附上参考文章,我不会做成表格,所以对付看吧):
ActiveMQ:java语言开发的,单机吞吐量:万级,时效性:ms级,可用性:高(主从架构)
功能特性:成熟的产品,在很多公司得到应用;有较多的文档;各种协议支持较好
RabbitMQ:erlang语言开发的,单机吞吐量:万级,时效性:us级,可用性:高(主从架构),功能特性:基于erlang开发,所以并发能力很强,性能极其好,延时很低;管理界面较丰富
RocketMQ:java语言开发的,单机吞吐量:10万级,时效性:ms级,可用性:非常高(分布式架构),功能特性:MQ功能比较完备,扩展性佳
kafka:scala语言开发的,单机吞吐量:10万级,时效性:ms级以内,可用性:非常高(分布式架构),功能特性:只支持主要的MQ功能,像一些消息查询,消息回溯等功能没有提供,毕竟是为大数据准备的,在大数据领域应用广。
综合上面的材料得出以下两点:

(1)中小型软件公司,建议选RabbitMQ.一方面,erlang语言天生具备高并发的特性,而且他的管理界面用起来十分方便。正所谓,成也萧何,败也萧何!他的弊端也在这里,虽然RabbitMQ是开源的,然而国内有几个能定制化开发erlang的程序员呢?所幸,RabbitMQ的社区十分活跃,可以解决开发过程中遇到的bug,这点对于中小型公司来说十分重要。不考虑rocketmq和kafka的原因是,一方面中小型软件公司不如互联网公司,数据量没那么大,选消息中间件,应首选功能比较完备的,所以kafka排除。不考虑rocketmq的原因是,rocketmq是阿里出品,如果阿里放弃维护rocketmq,中小型公司一般抽不出人来进行rocketmq的定制化开发,因此不推荐。
(2)大型软件公司,根据具体使用在rocketMq和kafka之间二选一。一方面,大型软件公司,具备足够的资金搭建分布式环境,也具备足够大的数据量。针对rocketMQ,大型软件公司也可以抽出人手对rocketMQ进行定制化开发,毕竟国内有能力改JAVA源码的人,还是相当多的。至于kafka,根据业务场景选择,如果有日志采集功能,肯定是首选kafka了。具体该选哪个,看使用场景。
然后因为我没用过,所以这里就是引用大佬的解释,刚刚也说了,上面这这高大上的东西我都不知道,咱们这里的秒杀用redis来做消息队列。

消息队列的作用和优缺点

这里说一下消息队列的作用,可能说的不全,但是是我目前查到的和想到的全部了:

redis做秒杀

刚刚因为我这篇文章主旨是用redis做个简单的秒杀demo,不过消息队列是一个首要的需要理解的知识点。顺便又写了下消息队列的一些常用知识,接下来回到正题吧。为什么用redis我也说明白了。
说一下大致有几点注意的:

  1. redis中没有整数型,所以value是string类型。
  2. 因为一种直接的秒杀是付款算是完成。还有一种是支付前就可以锁定。付款才算完成比较少见而且不太合理,所以这里要考虑一个锁定后不支付的问题。。
    3.同一用户只能抢购一次(我看好多地方说的是这个防止用户恶意刷商品数量或者用脚本啥的非正常竞争。)
    然后我做的思路很简单,如果说不考虑可能取消订单的情况,就是key是商品id,value是抢购数量。然后这个来一个人抢购redis中value-1.一直到等于0.这块代码块用异步处理,可以防止出现超卖/超买现象。
    如果考虑取消订单的情况,我的做法就是
    redis中,key是商品id,value起始值是商品数量但是它也是一个实时获取的值。另外用商品id+用户id作为key,value自定义,超时时间为付款时间(一般半小时,15分钟等等)。正常一次抢购访问,先判断value是否大于0,如果是则减一,并且生成一条此商品购买记录。(此两个步骤要保证原子性。最好在一个方法里用锁)
    如果用户手动取消订单则直接删除该用户商品购买记录的key。如果用户完成支付流程,将此key的过期时间设置为无限期或者约定时长(一周,一天之类的)。
    定时查询key是商品id的模糊查询条数。并用总商品数-商品购买记录,得到的值改写到key是商品id的value中。如果获取到的值是0,则表示此商品已全部卖完。
    至此,我用redis的秒杀完成。
    因为我测试用的demo比较简陋,所以在此就不贴出来了。因为代码上没有什么难点,主要是思路。然后如果大家有更好的实现方法欢迎提出或者交流。
    主要是在网上说起秒杀都是直接就看做支付,很少有考虑还有退单的可能啊。我觉得我的方法也比较麻烦,应该是有更好的办法的,大神们欢迎指教。
    然后全文手打不易,亲们,如果觉得帮到你了点个喜欢点个关注支持一下哟~~~~~么么哒!
上一篇 下一篇

猜你喜欢

热点阅读