如何才能做到尽可能快的实现热点数据变动并记录? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
qxdo1234
V2EX    程序员

如何才能做到尽可能快的实现热点数据变动并记录?

  •  
  •   qxdo1234
    qxdo 2024-04-10 14:31:11 +08:00 2564 次点击
    这是一个创建于 581 天前的主题,其中的信息可能已经有所发展或是发生改变。
    之前遇到的一个面试题,一直在想有没有什么好的答案。
    大概意思就是说,在支付宝里,假设我经营着一个很火爆的业务,这个业务的个人客户认为是无限多的,但是我们公司账户只有有限个。我和我的客户要转来转去,量也可以认为是相当大的。公司账户需要写账户余额表,账户流水表(包含变动之前余额,变动金额,变动之后金额)完整的记录下来,寻找最快的解决方案。现在的方案是采用 MySQL 事务,每个账户是一条数据记录,钱都在这一条数据里,在人多的时候,会出现很多失败的情况,因为业务量很大的情况下,一个账户变成了热点数据,一行记录被很多线程抢,就会出现问题。之前一个大佬 的想法是 把一个账户的钱,拆分出来,拆成 N 多个小账户,每次转账找到其中一个,结掉再根据此时的其他账户的总余额,写交易记录。相当于是把一条数据变成 N 多条,每次取 1 条,但是他这个方案,是不是在找账户的时候 要引入一定的随机性,不然 每次按照一定的规律去找,符合条件的这一条数据也会变成新的热点数据,问题实际上还是存在的。
    9 条回复    2024-04-12 10:16:38 +08:00
    qxdo1234
        1
    qxdo1234  
    OP
       2024-04-10 14:35:48 +08:00
    有类似的解法的,也可以一起回复,大家一起开放讨论,不限制具体使用的存储和计算的方式,但是想了解一下,有没有比较完善的解决方案。
    wenxueywx
        2
    wenxueywx  
       2024-04-10 16:19:52 +08:00   1
    一、同时跟你发生交易的客户数量是有限的;
    二、采用 mysql 事务实现,受限于行锁,高并发下会有严重的锁等待现象,分桶可以缓解,例如你可以把公司账号分为 0-9 共计 10 个子账号。查找账号时引入随机性没有用,因为你总的并发不会因为你的随机性降低。
    三、 高并发下,随着并发数( n )的增加,innodb 的死锁检测占用的资源会以 n^2 级数上升,你可以简单暴力地关闭死锁检测,但是这治标不治本;治本的方法是在 innodb 中明确地需要串行执行地操作不要进入引擎层,可以在业务上进行排队,排队时还可以对队列进行优化,比如同时 100 人并发转入到子账号 0 ,此时数据库中给子账号 0 增加余额,以及记录流水的操作是明确需要串行执行的,如果进行业务上进行排队优化,你可以合并这些转入操作到一次数据库变更中。
    wenxueywx
        3
    wenxueywx  
       2024-04-10 16:23:50 +08:00
    @wenxueywx 简单说就是把串行操作变成批处理
    KIDJourney
        4
    KIDJourney  
       2024-04-10 16:34:05 +08:00   1
    啥业务要求即时到账啊,在线转离线呗

    搞个队列或者搞个 mysql 任务表慢慢离线扫去
    qxdo1234
        5
    qxdo1234  
    OP
       2024-04-10 16:46:49 +08:00
    @KIDJourney 假定的是一个对并发,以及到账处理时效要求比较高的场景,毕竟你也不想你的客户做完操作以后 还要等大概 1-2min 之后才能离线看到自己的账户变动嘛,你可以理解成,比如我们运营一个超高价值波动的产品,晚 1-2min 的话 就一个天上一个地下了。肯定在有解决方案的情况下,要求更快的处理时效,如果真的是没有解决方案的话,才可以接受大概延迟几秒的处理时效。慢慢扫 可以解决问题,但是不是太符合本场景,不过还是谢谢。
    waitingChou
        6
    waitingChou  
       2024-04-10 17:34:31 +08:00   1
    分桶是一个简单的抗高并发的思路,还要继续优化出一个复杂思路的话,感觉 innodb 处理写入操作的思路也可以参考一下。

    简单来说就是把数据加载到内存, 有请求先改内存数据, 再写入到 "redolog"。 后台任务有空再把 redolog 落盘,落盘的时候没有并发,可以做得比较快。

    把高并发的冲突操作改成了纯内存 + 无锁顺序写
    justRua
        7
    justRua  
       2024-04-10 18:19:36 +08:00   1
    是不是可以把加钱、扣钱两个动作区分对待,扣钱失败的场景一般是用户余额不足之类的业务异常需要立马回滚事务,但是加钱失败则可能是出现锁竞争、网络之类的系统异常导致,重试就好了不需要回滚整个事务,可以适当延迟。

    用户余额加钱逻辑:
    1.写入账户流水;
    2.发送 MQ ,流水表加一个同步状态字段。
    后面异步执行:
    3.用消费者根据 MQ 消息去扫描流水表、批量的把多个加钱的记录金额合并为一个 update 操作用户余额,把同步状态更新为已同步。

    查看用户余额逻辑:
    查询用户余额表 + 流水表未同步的记录金额

    扣钱逻辑不变,但可能出现扣钱时,余额还没加上流水表未同步的加钱金额,导致余额不足扣钱失败,应该也还好。
    dode
        8
    dode  
       2024-04-11 11:13:59 +08:00
    引入 Redis 记录公司账号变化状态
    haxixi
        9
    haxixi  
       2024-04-12 10:16:38 +08:00
    公司账户的变化用 redis 记录
    账户流水用 mq ,然后写流水表
    如果 redis 出现宕机消息丢失,用流水表恢复 redis 丢失的消息
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5725 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 35ms UTC 01:42 PVG 09:42 LAX 17:42 JFK 20: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