求教大神一个 flask 技术问题,百思不得其解 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
leochan32767
V2EX    Python

求教大神一个 flask 技术问题,百思不得其解

  •  
  •   leochan32767 2019 年 1 月 29 日 4314 次点击
    这是一个创建于 2567 天前的主题,其中的信息可能已经有所发展或是发生改变。

    使用 python 的 flask 框架搭建了一个服务,用于公司内部的管理系统,公司比较大,员工比较多,有时候访问比较频发,最近发生了如下的一个问题,苦思冥想各种解决方法都试过了,还是无法解决,江湖告急 1 用的数据库是 mysql
    2 表的引擎是 innodb 3 orm 用的是 SQLAlchemy

    问题:

    添加数据的时候,使用 load.reqMOney= 100000 db.session.add(load) db.session.commit() 并且在添加数据前使用了 db.session.query(func.sum(Load.reqMoney)).filter(Load.uid == xxx).scalar() 的语句,进行查询 load 的 reqMoney 的总和 ,然后判断是否允许添加数据 [总和大于某一值时,不允许添加]

    但是生产环境的时候,经常会出现 !!!判断失效的情况!!!,用户连续点击添加数据(请求时间非常短), 判断失效,用户可以添加总和大于某一值的情况,请问这个是为什么,怎么解决 [个人对数据库的知识比较薄弱,是否是数据库锁的问题?代码层面怎么解决] ?

    能帮小弟解决的大神送小蓝杯咖啡十杯,以表敬意

    16 条回复    2019-01-29 23:06:00 +08:00
    pabupa
        1
    pabupa  
       2019 年 1 月 29 日 via Android
    t/531596

    看一下这个帖子吧,,,应该有帮助。
    kaneg
        2
    kaneg  
       2019 年 1 月 29 日 via iPhone
    你的 flask server 应该是运行在多线程或者多进程模式,所以出现了并发问题。

    如果是多线程模式,不考虑太复杂的情况下,可以加个锁
    leochan32767
        3
    leochan32767  
    OP
       2019 年 1 月 29 日
    @kaneg 的确,开了 16 个 gunicorn 请问下加锁有什么教程吗?
    wwqgtxx
        4
    wwqgtxx  
       2019 年 1 月 29 日
    借助 redis 或者是 multiprocessing.Manager 很容易实现跨进程锁,我自己还造过这方面的轮子
    https://github.com/wwqgtxx/RedisTools
    kaneg
        5
    kaneg  
       2019 年 1 月 29 日
    可以看看这个链接最后的 Lock 部分: http://blog.jobbole.com/52060/
    Trim21
        6
    Trim21  
       2019 年 1 月 29 日 via Android
    你需要一个分布式锁
    okwork
        7
    okwork  
       2019 年 1 月 29 日
    多个 worker 不加锁,出现超卖的情况不可避免,严谨的做法就是加锁。也有粗暴的做法,很多秒杀排队也是简单粗暴的抛弃请求,比如你可以把相邻时间小于 1 秒钟的请求丢弃,具体返回个什么值或提升,根据具体场景设计。
    cz5424
        8
    cz5424  
       2019 年 1 月 29 日 via iPhone
    看看能否把高频的判断值扔在 redis,或者函数上 redis 锁,保证高并发只有单个在处理
    guog
        9
    guog  
       2019 年 1 月 29 日 via Android
    最简单的就是使用 redlock,一个基于 Redis 的简单锁。加几行代码的事。
    ziding
        10
    ziding  
       2019 年 1 月 29 日
    pg 的话可以意向锁或者 for updte,mysql 看看有没有 for update 的等价物。
    dagger
        11
    dagger  
       2019 年 1 月 29 日   1
    查询语句把用户表一起 join 出来,用 for update 锁住,记得建好索引,不然 mysql 的 for update 会锁全表
    zeraba
        12
    zeraba  
       2019 年 1 月 29 日 via Android   1
    锁 MySQL 已经自己做了,判断大于总和这个逻辑可以在执行插入的时候判断 比如 update price where amount > 10000 而不是前端拿这个作为条件去判断能否执行插入
    ericls
        13
    ericls  
       2019 年 1 月 29 日 via iPhone
    在数据库那边应该加个锁
    MySQL 有 select for update. Isolation 等级可能要改一下
    zsen
        14
    zsen  
       2019 年 1 月 29 日
    如果基于以下的条件:
    1、用于公司内部的管理系统
    2、用户连续点击添加数据(请求时间非常短)

    前端加一个点击后禁掉点击事件,根据后台返回结果再处理是否可行呢?
    tomczhen
        15
    tomczhen  
       2019 年 1 月 29 日
    数据库上根据 select 结果来 update,多线程下要么使用幂等逻辑,类似:update status = 1 where id =1 and status =0; update sum = 19 where id= 1 and sum = 10,要么 select 就要上锁。

    加锁是为了保证一致性,会影响并发数。而且还得注意索引,确保锁的粒度,当然,内部系统没那么讲究的话其实也没所谓。

    redis 也行,毕竟单线程。另外如果取 key,重新写 value 不是原子( redis lua )操作的话,还是会出现并发问题。

    至于前端限制,为了并发最好也是要做的,减少无谓的请求,web 页面可以考虑 Redirect After Post。
    alvin666
        16
    alvin666  
       2019 年 1 月 29 日 via Android
    并发大的话用乐观锁,改一下表结构和 update 语句就行了,并发小的话用悲观锁
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     498 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 51ms UTC 07:52 PVG 15:52 LAX 23:52 JFK 02:52
    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