简单的聊聊,分布式里商品的超卖和电商秒杀

商品减库存的线程安全问题(商品的超卖问题)。

    提到线程安全我们就想到了同步问题,但是由于这里是分布式的微服务,可能还要搭集群,以前的一台服务器下的代码可以加同步锁现在服务器都不一样,那么这种方案肯定行不通。

    其实也可以考虑分布式锁去解决这个问题,但是由于是电商项目 执行效率的问题肯定是首先要考虑的。所以这里就想到了第二种解决方案,这里会涉及到悲观锁和乐观锁,悲观锁又会存在一个问题 是锁一行呢还是锁一整张表?

    取决于这条sql语句。例如:select...from for update;但是不管是锁行还是锁表都会导致效率变低,当前线程访问时其他线程会阻塞,这样的话在项目高并发的情况下肯定是不合适的。而乐观锁就不会阻塞线程,它认为线程安全问题不会发生,因此在查询过程中不锁表,也同时保证了线程的安全问题,比如说:下单先查询库存,得到num=10,再判断if(num>0),执行 update tb_item set num=num-1 where id='' ''num=10;这样写就表示了如果这条语句在执行的时候num依然为10,那就证明没有人修改过,那么这条sql语句就执行成功,如果查询的结果已经是被修改过的,那么这条sql语句就执行失败,立马返回影响行数0。这样就达到了既不会锁表导致线程阻塞,比如说更新失败直接返回结果 服务器正在忙。

    就算有很多个用户同时访问也只会有十个人执行成功,剩下的就执行失败。这种方案已经可以解决99%的问题,但是还是会有一个毛病,那就是数据库写的评率过高,很有可能高并发的情况下就导致了数据库崩溃。如果不是做秒杀这两种方案已经足以解决问题。

再说另外的一种情况,商品的秒杀

    试想一下,如果商品只有剩下10件 有一百个人买,然后十个人买到了,剩下的90个人会怎么样?肯定会不停的刷新发送请求啊,是不是导致了数据库写的概率成倍增加。

     于是乐观锁的这种解决方案可能就会导致整个数据库的崩溃。怎么解决这个问题,可以变同步写为异步写。也就是说当请求过来不是直接访问数据库,而是让它慢慢的访问数据库。首先把库存量读写操作挪到内存中去,在内存中完成减库存的操作,如果库存减完是成功的再把成功的生成订单和减库存的任务通过mq交给数据库操作。

      这样一来的话内存中的读写效率相对于数据库来说肯定是高出很多倍的。这样一来也就是把高并发的压力从数据库转移到了内存中,那么如何保证内存中线程的安全问题呢,可以采用redis 因为他是单线程的,而且并发能力强,刚好适合这样的解决思路,利用redis的数据结构,队列的list结构,push 十条数据进去,每个数据都有一个编号,再使用lpop命令 删除并获取第一条数据,如果没有就返回空,判断如果返回的不为空则执行mq里面的下单和减库存操作。这样一来即解决了线程的安全问题和高并发下数据库的读写压力。另外一种利用事务和whtch监控批处理 这种比较麻烦。这里就不细说了。

       这个时候秒杀活动还没结束可能没买到的人还不死心,高并发还会持续一段时间,那么nginx服务器的压力也就来了。可以把服务器的一些静态资源放到cdn服务器上,页面的静态化。也可以搭nginx集群来解决。

你可能感兴趣的:(简单的聊聊,分布式里商品的超卖和电商秒杀)