• 高并发解决的几种办法


    Reference

    [1] https://zhuanlan.zhihu.com/p/38969245

    方法1:

    对单个数据的更新,可以使用CAS(Compare-and-Swap)指令。

    伙计们的操作变成下面这个过程:

    伙计A看了下总账户余额是1200,然后记住这个数字,回来计算1200+50=1250,回去修改,一看总账户余额还是1200,于是成功修改为1250;

    伙计B看了下总账户余额是1200,然后记住这个数字,回来计算1200-50=1150,回去修改,一看总账户余额是1250,不是原来的1200,说明数据被修改了,需要重新计算,于是记住新的值1250,回去重新计算1250-50=1200,在回去修改,一看总账户余额是1250,于是成功修改为1200。

    上面的操作过程就是运用了CAS指令,修改之前先对比,数据没变化说明没有被修改过,这时候才能进行更新。

    但是CAS操作时,还有一个ABA的问题。

    例如:伙计A动作很快,改了一笔1200->1250,又改了一笔1250->1200;这时候伙计B回来改,看到的1200虽然数量没变,但是已经被改动两次了。

    虽然上面的这种情况ABA问题不会有什么影响,但是有时候还是会出问题。

    例如:总账户余额是每天记录一个数。

    伙计A在今天的总账户余额上面改了一笔1200->1250,掌柜过来翻了一下总账户,翻到了昨天那页,而那页的总账户余额刚好是1200;

    伙计B过来更新数据,一看还是1200,就改成了1150,这个改动是有问题的,因为伙计B改的是昨天的总账户余额。

    要怎么解决这种ABA问题呢?

    只需要在之前的数据基础上,再增加一个日期数据,检查的时候,需要同时检查总账户余额的数据和日期的数据,都没有变化才可以成功更新。

    方法2:

    引入队列,让一个任务专门来做数据的更新,避免并行运算。

    这时候,就是让掌柜一个人来更新总账户余额,伙计们只需要把自己的每一笔业务结果记录在总账户下面。

    伙计A有一笔业务是存50两,则在总账户下面记录上+50;

    伙计B有一笔业务是取50两,则在总账户下面记录上-50;

    而掌柜只需要从总账户里面,顺序的把+50,-50的操作更新到总账户余额就可以了。

    这种方法的好处是,避免伙计并行更新总账户余额,发生冲突时的等待,既提高了伙计的效率也保证了数据更新的安全。

    方法3:

    还是需要有锁的操作,但是让运算的过程更快,减少锁冲突的频率和时间。

    前面是伙计先上锁,然后看总账户余额,再回去运算,再回来更新和解锁。

    把这个过程改一下,伙计带着算盘过来,先上锁,然后现场运算,更新后解锁,再回去。

    这样一来,整个的读写时间变短了,锁的冲突时间也就减少了,效率和性能也就能有所提高。

    方法4:

    能否进一步减少锁的冲突时间,比如:将读、写的锁分开考虑,毕竟大部分业务中读的次数会远多于写的次数。

    A 使用读写锁而不是互斥锁,可以提高并发读的效率,减少读时候的锁冲突。

    例如:大量的业务都需要查看总账余额才可以做决定,那么就会有大量的读需求。而多个人一起读不冲突,只是在需要写的时候才独占总账余额的锁。

    B 将大的数据分拆为多段的小数据,这样通过多个锁分别作用在小数据上,避免一个锁作用在大的数据中,减少冲突的概率。

    例如:对总账余额的每一位设置单独的锁,而不是对整个数设置一个锁。这样的话,+50只需要得到十位数的锁,-3只需要得到个位的锁,如果是+55则要个位和十位两个锁。

    C 读的时候不需要锁,而写入的时候串行化同时只能一个人更新

    例如:总账余额对所有人公开的,大家可以随便看,但是修改的时候,只能由掌柜来操作。

  • 相关阅读:
    Flask 服务器设置host=0.0.0.0之后外部仍然无法访问
    HTB::Sauna
    VulnHub::DC-4
    【CTFHub 技能树】RCE
    【CTFHub 技能树】反射型XSS
    VulnHub::DC-3
    HashMap中add()方法的源码学习
    equals和HashCode深入理解(转)
    AQS原理分析
    初步认识线程安全性
  • 原文地址:https://www.cnblogs.com/codingforum/p/9286954.html
Copyright © 2020-2023  润新知