本文如有不对之处,欢迎各位拍砖扶正。另源码在文章最下面,大家下载过后先还原一下nuget包,需要改一下redis的配置,rabbitmq的配置以及Ef的连接字符串。另外使用的是CodeFirst,先update-database生成数据库后再进行操作
高并发
高并发一直是网站上线后会遇到的一个严峻的考验,渡过了一切都好,渡不过就是宕机。
在电商时代如此发达的今天,高并发无此不在双十一 、618、双十二,还有雷猴王的某米手机抢购。首先我们要分析高并发究竟会给我们开发者带来什么样的挑战
大量的请求,如果仅仅只有一台服务器肯定是吃不消的,通常一些公司都是一台服务器上部署了很多个网站也充当了数据库服务器、redis服务器。如果要应用高并发没有足够的硬件支持是不行的。我们需要进行 分布式集群 以及 负载均衡
硬件支持有了过后,我们就需要下一步的分析
这时我们还需要提高网站的吞吐量,怎么提高呢?首先我们需要针对IO密集型做异步化操作,抢单的页面不只是有抢单按钮,还有商品的介绍,图片,文字描述等。对于这些数据我们要进行缓存,一万个用户一万次请求都从数据库中取数据与只取一次剩下9999次从缓存中取效率自然是不一样的
上面说的都是为了解决一个 高 字,而并发才是我们真正需要准备的,假如两个用户同时请求,这时库存还有1,程序里先判断库存是不是1,现在都符合条件,然后进行生成订单等操作。就发生了资源共享的问题,明明只有一个订单,但是两个用户都完成了订单,那么这个商品应该给谁呢?
并发
假设现在是一个电商网站,今天要举办活动,有10个商品低价销售,但是会来抢购的人会特别多,最后只有十个人可以成功的买到商品
假设的逻辑,我们用户进行了请求,我们把他们的信息放到库里,但是只有前十个人是可以购买商品的,因为库存只有10个
也许我们可以用锁来解决并发的问题,但是锁无疑带来的是效率的低下,用户体验也极低。我们想要的是快速返回,但是后面那一堆的逻辑怎么办呢?我们可以使用RabbitMq队列,用户的请求到达了抢单接口,我们只向队列中丢一条数据后就立即返回
这时又来了一个问题,会有同一个用户多次进行请求的情况,如果像之前的逻辑,前10条信息有二条是属于一个人的呢,(这里假设每个人只可以购买一次)我们就需要进行判断了,同一个账户发送的多次请求,我们只认为第一次请求是有效的,剩下的都请都直接返回。因为是并发,我们又怎么做到第一次请求有效呢?这时我们可以使用Redis incr存储用户的标识,Redis是单线程的,不存在并发的问题。incr返回为1那么是第一次请求,为N则是第N请求那么它就是无效的。这是请求标识
请求标识我们可以在抢单接口就进行判断,也就是先拿用户的标识去Incr,返回为1则丢到队列,不为1则不丢到队列。
也可以在rabbitmq的消费端进行处理,从rabbitmq消息队列中拿到用户信息后,进行incr。再进行下一步操作
丢到了消息队列中,我们还需要去处理,consumer我们肯定是要有多个的,我们可以使用平分分发与手动交付。在这里我们把用户的信息进行入库,当然入库后我们再向Redis中存入一条入库标识
上面都是在后端,客户端这里点击了抢单按钮后可以立即导向排队界面(是不是很熟悉,某米。。。)在这个界面进行轮询五秒一次,判断当前用户在库中的位置,如果是前十,那么就进行订单操作,不是。。。那就再等,看看会不会有其他用户放弃购买资格。
其实讲到这里,已经差不多了,成功的把并行变成了串行。剩下的就是业务处理,怎么做都可以。其实对于并发还可以有其它的处理方式,比如乐观锁也可以有效的控制并发,可以看我的相关文章,其中就有关于乐观锁的实现
源码下载地址 http://pan.baidu.com/s/1pKFzyYJ 密码 mf50