PHP 在高并发下,怎么正确处理,才能保持数据的一致性? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
madaima
V2EX    PHP

PHP 在高并发下,怎么正确处理,才能保持数据的一致性?

  •  
  •   madaima 2018-03-15 10:05:13 +08:00 7862 次点击
    这是一个创建于 2842 天前的主题,其中的信息可能已经有所发展或是发生改变。
     //流程一 class Factory { public static function get($item) { switch ($item->status){ case 1; return new a($item); case 2; return new b($item); ... } } } //流程二 class a { public function aa($item) { //DB BEGIN //set status = 2 //DB COMMIT //catch DB ROLLBACK } } 

    首先我们排除使用悲观锁这种方法。

    如代码所示,现在处理数据时会先进入工厂类判断数据状态,然后到不同的类中去处理数据。

    但是在高并发下,流程二没走完的情况下,数据状态没更新,第二次请求还会走到流程二中去处理。

    这种情况 有什么好的方法去处理?

    36 条回复    2018-03-16 10:07:44 +08:00
    jack010love
        1
    jack010love  
       2018-03-15 10:08:54 +08:00
    PHP 的话,我们一般都是在 Redis 加个 flag。
    extreme
        3
    extreme  
       2018-03-15 10:19:33 +08:00
    才疏学浅,坐等高人回答
    TIGERB
        4
    TIGERB  
       2018-03-15 10:23:32 +08:00
    和语言无关吧

    方案 1: 串行操作
    方案 2: 锁
    vus520
        5
    vus520  
       2018-03-15 10:34:18 +08:00
    高并发下,还用数据库的锁来实现,我感觉这是要炸啊,数据库的性能得多好?
    madaima
        6
    madaima  
    OP
       2018-03-15 10:43:00 +08:00
    @jack010love 做类似乐观锁的操作吗?
    kimmykuang
        7
    kimmykuang  
       2018-03-15 10:46:03 +08:00   1
    你的问题是要实时一致性还是最终一致性?现在高并发场景下一般都是舍弃实时一致性保证吞吐,借助队列或 redis 锁或幂等表等方式来实现最终一致性
    robinchina
        8
    robinchina  
       2018-03-15 10:51:09 +08:00 via Android
    因为搞不定别的方法所以锁表一锁解千愁
    puritania
        9
    puritania  
       2018-03-15 10:52:42 +08:00 via iPhone
    Redis setnx 了解一下
    puritania
        10
    puritania  
       2018-03-15 10:53:11 +08:00 via iPhone
    或者串行消息队列
    solaya
        11
    solaya  
       2018-03-15 10:53:47 +08:00
    MVCC ?
    madaima
        12
    madaima  
    OP
       2018-03-15 10:55:41 +08:00
    @l57t7q 谢谢你提供的资料 我一会研究一下。
    madaima
        13
    madaima  
    OP
       2018-03-15 10:59:46 +08:00
    @vus520 对啊 所以问一下有没有其他好的实现方法学习一下。
    harborM
        14
    harborM  
       2018-03-15 11:04:46 +08:00
    之前看了点文章,一般都是串行或者锁实现的,文件锁数据库锁在高并发情况下都挺粗糙的,可以用 redis 来锁,毕竟锁作为一个同步原语只要实现 acquire 和 release 理论上就成立了,而且 redis 本身可以分布式部署,应该是个可行的方案;串行的话对于部分语言有些难言之隐,php 的话如果回调形式返回结果有点难以主动推.只是我的一点思路
    dilu
        15
    dilu  
       2018-03-15 11:06:48 +08:00
    加锁
    如果需要更高的性能 我才疏学浅 看别的大神怎么回答吧
    rqrq
        16
    rqrq  
       2018-03-15 11:09:43 +08:00
    缓存加标志怎么弄都可以,并发了直接返回一个提示给用户,操作失败,让用户自己重试。
    数据库乐观锁有个好处是并发了会挂着等前面的处理完毕,然后自动再读取,只要不超时,用户只需要等待。
    看实际情况用哪种。
    这是我的理解,也不知道对不对,这也应该就是 @kimmykuang 说的实时一致性和最终一致性。
    rqrq
        17
    rqrq  
       2018-03-15 11:11:48 +08:00
    我还没试过 redis 的锁是不是可以像数据库锁那样,如果可以肯定优先用 redis 来实现。
    madaima
        18
    madaima  
    OP
       2018-03-15 11:16:38 +08:00
    感谢 楼上各位热心回复 我现在大概有个思路了 现在去实现下 试试效果。
    eslizn
        19
    eslizn  
       2018-03-15 11:16:40 +08:00
    事务化,每次请求一个 id,然后这个请求中的任何原子操作,都需要额外具备确认(用于超时等情况下的重试)、回滚接口。不能确定的失败操作一律丢入队列进行重试、回滚或人工处理
    Junjunya
        20
    Junjunya  
       2018-03-15 11:17:32 +08:00
    码一下, 等高人回答完了, 来学习
    onepunch
        21
    onepunch  
       2018-03-15 11:43:44 +08:00
    Redis 锁,感觉 aa 应该被保护起来吧 ,如果并发很容易就达到 aa,那么数据库的压力还是很大的吧。

    战略 mark 下
    yao978318542
        22
    yao978318542  
       2018-03-15 11:58:13 +08:00
    队列?我觉得可以吧
    RorschachZZZ
        23
    RorschachZZZ  
       2018-03-15 12:17:59 +08:00
    目前我用队列来解决,坐等高手回答 码之
    lqtriks
        24
    lqtriks  
       2018-03-15 12:23:32 +08:00
    Mark.
    prolic
        25
    prolic  
       2018-03-15 13:03:38 +08:00 via Android
    redlock 了解一下
    kobe123
        26
    kobe123  
       2018-03-15 13:41:44 +08:00
    异步 work
    Xrong
        27
    Xrong  
       2018-03-15 13:46:45 +08:00
    楼主弄完,分享下方案撒。
    wekw
        28
    wekw  
       2018-03-15 14:08:56 +08:00   1
    1. 分布式系统的核心功能是“队列消息传递”。
    2. 并发量不太高的时候,用原子化锁:redis 字段标记。
    3. 并发量太高的时候就得时间换性能了:用高性能消息队列。本质依然是原子化,不过将简单的标记又抽象成了队列数据存储+后期执行,实现了单机更高性能。
    4. 当单机消息队列都扛不住的时候就要上真正的分布式消息队列了,如 kafka
    90safe
        29
    90safe  
       2018-03-15 14:46:15 +08:00
    @qfdk 来研究这个啊,整天研究速度优化有啥用
    youqiantu
        30
    youqiantu  
       2018-03-15 18:28:06 +08:00
    高并发 redis 也不行啊。。。
    shisang
        31
    shisang  
       2018-03-15 18:45:38 +08:00
    乐观锁
    liuxu
        32
    liuxu  
       2018-03-15 18:58:48 +08:00
    要不楼主别两次 get,直接 case1 执行完后回调 case2?
    vtwoextb
        33
    vtwoextb  
       2018-03-15 19:17:31 +08:00
    队列
    afeicool
        34
    afeicool  
       2018-03-15 21:59:30 +08:00 via Android
    不知道是不是我的理解能力太弱,完全没看懂你的业务,如果只是改状态的话 完全可以用 set status=2 where status = 1, 何必又是这个锁那个队列,甚至跑到分布式上去了…
    madaima
        35
    madaima  
    OP
       2018-03-16 08:56:25 +08:00
    @afeicool 这里只是举个大概的流程,每个流程里面有很多业务方法,单改变状态的话就没有这么复杂了。
    th00000
        36
    th00000  
       2018-03-16 10:07:44 +08:00
    redis 串行
    否则 乐观锁 悲观锁
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     952 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 22:42 PVG 06:42 LAX 14:42 JFK 17:42
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86