场景:
内卷现象, 供不应求(高峰期打车、电商秒杀), 热点数据更新
社会现象: 资源有限而需求无限的情况(春运时期的火车票、学生报补习班、企业里面的资源地盘争夺等)
挑战:
当系统中出现热点row时, 意味着大量的并发请求更新同一行数据, 因为数据库最小粒度的锁为行锁, 所以这些并发请求只能串行执行,
一个会话在更新的时候其他所有会话都处于等待状态, 可能导致连接打爆, 其他会话连不进来引起雪崩.
如果被秒杀的商品库存只有10个, 那么实际上只有10个请求能达成交易, 其他等待中的会话都属于无用功. 浪费大量的连接和等待时间.
1、传统方法
vi test.sql
update a set cnt=cnt-1, ts=clock_timestamp() where id=1 returning *;
pgbench -M prepared -n -r -P 1 -f ./test.sql -c 12 -j 12 -T 120
2、skip locked 跳过被锁的行
update a set cnt=cnt-1 , ts=clock_timestamp() where
ctid =
(select ctid from a where id=1 and cnt>=1 for update skip locked)
returning *;
3、advisory lock, 彻底消除行锁
update a set cnt=cnt-1, ts=clock_timestamp() where id=1 and pg_try_advisory_xact_lock(id) returning *;
tps 性能提升
12个并发:
19177(传统方法) -> 59717(skip locked) -> 89184(advisory lock)
800个并发:
374(传统方法) -> 34495(skip locked) -> 70444(advisory lock)