商品抢购-高并发问题实战

https://blog.csdn.net/wwd0501/article/details/88663621
mysql默认可重复读模式,就会出现可重复读问题,比如秒杀的超发现象,这时候如果用悲观锁悲观锁就是数据库的串行化,只有单线程可以操作数据库,这个时候问题就是高并发性能问题,脏读、不可重复读、幻读统统解决,悲观锁我们利用数据库自己的隔离机制,在sql最后面加上 for update 。但是实际应用中高并发是一个很需要解决的问题,主要手段就是乐观锁,乐观锁采用CAS(Compare And Swap)算法,CAS算法简单说更新一个变量的时候,只有当变量的预期值A和内存地址V当中的实际值相同时,才会将内存地址V对应的值修改为B。具体理解:

在线程开启的时候,会从主存中给每个线程拷贝一个变量副本到线程各自的运行环境中,CSA算法中包含三个参数(V,E,N),V表示要更新的变量(也就是从主存中拷贝过来的值)、E表示预期的值、N表示新值。实现过程:假如现在有两个线程t1,t2,,他们各自的运行环境中都有共享变量的副本V1=20、V2=20,预期值E1=20、E2=20,预期主存中的值还没有被改变,假设现在在并发环境,并且t1先拿到了执行权限,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次发起尝试,然后t1比较预期值E1和主存中的V,发现E1=V,说明预期值是正确的,执行N1=V1+1,并将N1的值传入主存。这时候贮存中的V=21,然后t2又紧接着拿到了执行权,比较E2和主存V的值,由于V已经被t1改为21,所以E2!=V,t2线程什么都不做。

但是其存在一个ABA问题,不过此问题随着版本的引入也已解决,规定version只会递增不论什么修改。举个例子比如商品秒杀,需要在product属性中新增version字段用来应用乐观锁,查询商品时也就是获取旧值获取version,然后扣减库存的时候把version当做参数提交上去,扣减的实现sql  update product set stock(库存属性) = stock - #{quantity(购买数量)},version =version+1  where id=#{id} and version = #{version} 。同时此serviceImpl方法上事务隔离级别设为读写提交即可,因为我们已经自己实现了数据一致性。这样下来我们既能解决性能问题也能解决数据一致性问题。结合深入浅出springboot实战案例来看我们确实解决了上面的问题,但是也存在新的问题就是请求次数过多失败率较多,大量请求更新失败,比如我们卖3w商品,可能请求了5w次,但是还剩余1.5w商品没有卖出,那么我们怎么再进一步提升性能呢?乐观锁其实可以引入重入机制,也就是一旦更新失败就重做一次,而不是直接返回false结束整个请求,乐观锁属于可重入的锁。原理就是一旦发现版本号被更新不是结束请求而是重新执行乐观锁流程,直至成功为止。当时这样会导致大量的sql被重复执行,使得数据库的压力变大,为了克服这个问题我们一般会考虑使用限制时间或者重入次数的办法,以压制过多的SQL被执行。先说下时间戳限制时间的方法,说白了就是限制单次请求的生存期比如100ms,100ms内的请求如果失败可以继续重入,但是超过100ms此次请求就失败返回。听起来高大上,其实实现起来很简单直接用System.currentTimeMillis获取时间戳,使用将所有逻辑放在while(true)中,返回false的条件是超过100ms放在第一行,下面就开始执行获取产品、判断库存不足返回false,充足则执行扣减库存逻辑,如果失败则执行continue;直接从头开始执行while逻辑如果成功则执行插入购买记录的逻辑。加入这个时间限制一定程度上可以解决我们上面的问题,但是也有个弊端就是如果系统或者是数据库繁忙,性能下降,会导致我们的时间戳重入次数大大下降因此有时候也会采用重入次数的方法,至于实现方式跟上面就基本类似了把while换成for循环指定次数就可以了。
redis缓存抢购,此种方法十分迅速,因为redis是数据库处理数据的数倍甚至是数十倍,基于内存,redis抢购使用的是Lua的脚本执行的原子性,虽然redis也支持事务但是Lua性能以及易用性相对更强,因为我们也不用考虑分布式事务啥的,Lua脚本执行的方式之前已经了解过:只在第一次之行时把脚本逻辑缓存在redis服务器中,然后Redis服务器返回一个32位的SHA1码,并缓存到白能量sha1中,再通过它将程序需要的键和参数传递给后台去执行Lua脚本,其Lua逻辑只在第一次传输存储为sha1之后,程序后面传输的只有sha1以及具体执行的参数,此时完全使用redis来相应用户的请求,全部数据都存储在redis中,但是我们也知道redis具有不稳定性(集群高可用必备),因此保险起见我们还是落地磁盘,可以采用@Scheduled定时拉取存mysql

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Python可以通过使用多线程、多进程和协程等技术来提高并发性能,实现高并发的爬虫和毫秒级的抢购。 对于爬虫来说,可以使用多线程或多进程来同时进行多个请求,并行地获取网页内容。通过多线程可以实现简单的并发,但是由于Python的全局解释锁(GIL)限制了多线程的并行度,所以在需要大量并发的场景中,更推荐使用多进程。多进程可以充分利用多核CPU的性能,实现更高的并发度。此外,还可以使用协程技术,如asyncio库,来实现高效的异步IO操作,进一步提高爬虫的并发性能。 而针对毫秒级抢购需求,可以使用异步框架如Tornado、asyncio等,通过非阻塞IO和事件驱动的方式来实现高性能的抢购。异步框架可以充分利用操作系统底层的事件循环机制,在等待IO的时候不会阻塞其他任务的执行,从而实现高并发、高性能的抢购操作。 另外,为了进一步提高性能,还可以使用一些优化技巧。例如,可以使用连接池来复用HTTP连接,减少连接和请求的创建销毁开销;对于爬虫来说,可以通过合理的设置请求头、使用反爬虫机制来提高请求的成功率;对于抢购来说,可以通过预加载、优化请求参数等方式提高请求的响应速度和成功率。 总之,Python在高并发爬虫和毫秒级抢购方面拥有丰富的技术和工具支持,通过合理选择并使用相应的技术和优化方法,可以有效实现高并发和快速响应的需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值