一个字段金额,一秒可能要更新上百次,就会卡顿死锁,应该怎么处理比较好
1
iyiluo 1 天前
放内存或者 redis ,定期写入数据库
|
2
GPLer 1 天前 via Android
时序数据库或不可变数据库?反正用插入替代修改应该就能解决。
|
3
mark2025 1 天前 ![]() 1. 放内存或者 redis 。不过保持数据一致性需要额外开销
2. 数据库存储用本地高速磁盘,比如 NVME 3. 如果是 pgsql 数据库 3.1 字段 FILLFACTOR 设定很小值(比如 1 )提高写入性能 3.2 关闭 full page write 开关(需要磁盘磁层有相应的安全措施,比如 ZFS 文件系统) 3.3 关闭 sync 同步写入(需要磁盘磁层有相应的安全措施,比如 UPS 、阵列卡电池) |
![]() |
4
godall 1 天前 ![]() 我建议是修改业务逻辑,标准的读写分离:
1 、update 改为 insert ,插入数据同时更新 redis 。 2 、增加 redis ,提供读服务 这样不会有问题,即使突然挂了,数据还在数据库里,重启初始化 redis 就行了。 |
![]() |
6
21231sv 1 天前 ![]() 有没有大佬解释下为什么 1 秒更新上百次就会卡顿死锁
|
7
coderzhangsan 1 天前
现在的问题是数据库更新并发太高,数据库负载扛不住;楼上已经给出了问题相关解决方案,我抛砖引玉总结下楼上解决方案思路。
1. 从降低并发负载角度来看,常规是采取削锋,控制数据库并发流量,例如可以使用消息队列处理,控制好消费流量即可。 2.从提高并发负载角度来看,使用内存缓存替代传统关系型数据库或内存缓存作为中间层. 3.从提高数据库行锁并发角度来看,业务策略调整,用写入替代更新,数据量会飙升,后续是否考虑分表或者定时清理数据。 4. 提升机器配置。 |
![]() |
8
CEBBCAT 1 天前
可不可以请假下是什么业务场景,怎么压力都堆到 DB 来了?
|
![]() |
13
lasuar 1 天前
这不跟交易系统一样了,已经不适合用 mysql 实时存储了,都是放内存数据库,再延时落地 mysql 。
|
![]() |
14
lessMonologue 1 天前
@21231sv 抢锁等待更新,占用数据库链接
|
![]() |
15
vveexx 1 天前
楼上大佬给的方案已经足够多,但是刚又想到一种。如果价格是可预知的,提前生成出来所有可能的值应该也能解决。具体的最好能把场景贴的太详细一点
|
16
qyvlik 1 天前
热点账号的问题。
rds 范畴内: 分散更新,合并读取;追加记录,合并更新;如下: 1. 多个账户,增加资金时哪个空闲用哪个;扣除资金如果不够,还是要锁全部账户。 2. insert 记录,作为待结算数据,然后再批次更新回主记录。 非 rds 范畴: 1. 不考虑用 rds 了,上 redis 等非关系数据库。 2. 如果怕 redis 丢数据,用 in-memory + kafka ,in-memory 就是直接 java ( rust 也许更快)内存维护最新状态(本地内存可比 redis 快多了),kafka 记录变动流水( kafka 容量可比 redis 大多了)。 |
![]() |
19
zpfhbyx 1 天前
可以维护一个 token 池子 这个池子的 token 可以一次性生成, 可以随时补充, 每个 token 对应一个价格, 然后预扣, 最后统计池子中没用的 token 余额加回就好了..
|
![]() |
20
lasuar 1 天前 ![]() @pony2335 #18 既然是写内存,那这种数据肯定是允许丢失的,比如 1s 中变化上百次的字段,丢失其中第 99 次的数据并不影响什么,因为系统恢复后,马上又会收到最新的数据。
如果发生交易,那交易记录是从内存中获取实时价格,然后记录本身要入持久化数据库的(而不是写内存)。 |
![]() |
21
miaomiaotu 1 天前 ![]() 设计的就有问题,为啥都要并发修改在数据库层面,正常不是缓存层面加锁控制数量金额等,业务交互在数据库之前走完了,数据库只是记录最终结果。然后再改数据库,而不是直接操作数据库,任何性能问题都是架构层面的问题,不是改个啥代码能解决的,除非屎山代码
|
22
nicoley 1 天前
@miaomiaotu Redis 不是单线程执行的吗,为什么要在缓存层面加锁控制?如果确实要做业务流程编排,感觉可以把这部分的控制放到 Lua 脚本里面去控制。
|
23
nicoley 1 天前
@miaomiaotu 再就是 Redis 和 数据库数据的一致性该如何保证咧 ? 就是存在 Redis 挂了的情况?
|
24
daybreakfangyang 1 天前 via Android
好奇是什么场景
|
26
mark2025 1 天前
@coderzhangsan 如果实时读取需求不强,用消息队列是个好办法。
|
![]() |
27
silentsky 1 天前
用 hazelcast 或 redis
|
![]() |
28
guanhui07 1 天前
用 redis 然后 定期刷入 db
|
29
angryfish 1 天前
更新上百次,也是不同的记录吧?理论上是不会卡死的啊?
是不是更新字段没走索引啊 |
30
angryfish 1 天前
#29 更新的 where 条件没走索引,造成锁表了
|
31
zmal 1 天前
把你的问题拿去问 deepseek R1 , 给的答案比评论区大部分方案靠谱。
|
32
v2er119 1 天前
同一个字段没关系,不是同一行的就没问题,降低锁的粒,表到行到页。前提能准确定位,又不产生共享锁。
|
![]() |
33
linora 1 天前
业务场景描述太过有限
说白了就是避免行锁,那只能参考数据库的 latch 和 children latch 设计 即将一行尽量拆分成多行 比如 100 块资源池,拆分成 4 行,每行 25 块 不考虑 delete/insert 的话,纯 update 随机一行 如果只是一味的累加,风险不大 否则可能遭遇负数风险,就要引入全局锁定读 所以还得看场景!看场景!看场景! |
![]() |
34
areless 1 天前 via Android
肯定是股票~期货~外汇~数字货币呗,报价随买卖单对挂单的撮合而动,mysql 做不到的,直接用缓存之类的放内存里面。
|
35
Asheet 1 天前
将多次 update 的行锁请求合并到一次上。比如启动一个异步线程和引入一个时间窗口,对这个窗口内的所有请求扣减金额进行相加,进行一次 update 。然后进行多次 insert 操作记录扣减日志,发生异常根据日志情况进行回滚
|
![]() |
38
realpg 1 天前
换一个技术牛逼点的架构师
|
![]() |
39
lqw3030 1 天前
@mark2025 #25 楼主想表达的可能是引入“账单”概念,以此把并发 update 写转化为并发 insert ,从根源上规避了高并发操作同一行的场景,计算余额对所有操作行做累加即可
|
41
nicoley 1 天前
要是设计表的时候,主键字段设置的是数据库自增,那还能提升写入的并发吗
|
![]() |
42
sagaxu 1 天前
确定有死锁,那就排查一下死锁原因,正常情况每秒几百次的单行 update 是吃得消的
|
![]() |
43
hd7771 21 小时 37 分钟前
我之前在阿里做过 MySQL 内核,这种场景阿里是通过修改 MySQL 源码解决的。具体原理其实就是在 MySQL Server 层排队批量提交多个事务,InnoDB 只用拿一次行锁,提交成功之后在 Server 层构造结果。
https://github.com/alibaba/AliSQL/wiki/AliSQL-Performance-benchmark-for-inventory |
![]() |
44
hd7771 21 小时 34 分钟前
AliSQL 这个源码不建议用了,没人维护的,一定要用,可以用 PolarDB-X Engine 这个代码,我走的时候还有团队在负责。
|
![]() |
45
miaomiaotu 20 小时 46 分钟前
@nicoley 加分布式锁,先改缓存,缓存成功再改数据库,一致性保证就行,查询什么的走缓存,然后数据库做主主复制或者主从,再加读写分离,这样方案扩展性强,前提是技术到位再加上服务器到位,完美方案,最主要的是把数据库的读压力和写压力分开,数据库在并发读时候出现锁表问题很低,但是加上并发写就会出现,所以最终目的还是数据库读写分离加上压力在缓存层解决,完美,服务器要给力,不然是累赘这个方案
|
![]() |
46
miaomiaotu 20 小时 39 分钟前
@nicoley 如果架构层次解决不了,只能改业务代码那块,那么就使用乐观锁机制,把事务内部代码减少,尽量一个事务内就是单独修改哪个金额数字,减少事务时间,再加上修改时候尽量走索引这样行锁,避免锁表,这样也可以,但是都是拆东墙补西墙方案,不是最终的,最终的还是之前架构方案
|
![]() |
48
whahuzhihao 20 小时 4 分钟前
问题本质是热点数据写
一种思路是改用 redis 这种能抗热点修改的组件,异步落盘到 DB 。但是针对金额这种敏感字段,不建议这么做,除了需要额外维护一致性,还需要将所有读数据的场景都迁移到 redis 。 另一种思路是在数据库层面进行合并提交,类似 43 楼的的做法,需要魔改 MySQL 。热点行更新能抗几百一两千并发问题不大。 |
![]() |
49
areless 20 小时 3 分钟前
1 秒上百次的写,肯定也得 1 秒上百次读出来,纯 update 写本身毫无意义的。纯数据库方案即便各种方式写进去了,也是读不出来。比如 1 2 3 4 5 6 7 ,读出来就可能是 1 1 1 6 6 。读写都不落数据库是最好的方案,然后再搞个消息队列往数据库里塞海量的价格变动日志,供离线分析。
|
![]() |
51
MoYi123 19 小时 51 分钟前
只是高频更新不会导致死锁, 建议先把死锁的问题修好再看.
|