券池重构
程序员文章站
2022-04-21 10:32:33
...
之前的券池分成两个部分,一个 Job 和 一个 Service 。
Job 会每分钟 loop 券首位(1-9),生成一批券码往数据库里面插,这里需要做一些过滤:老券池、新券池、内存券池和券表 。
Service 里面有9个内存券池。它会在外部请求发券时定位到某个券池,看它的券够不够,够的话直接返回,否则重新去数据库捞一批进来。捞进来之后把数据库的券码删掉。
数据库有一个额外的“捞取批次表”,主要用来做幂等(防止分布式环境下捞取相同的券):
1. 生成批次 ID
INSERT INTO TG_ReceiptDistributePoolBatchFetch ..
SELECT @@IDENTITY AS receiptDistributePoolBatchFetchID
2. 查找券池表可用券码,以备插入内存券池
SELECT * FROM TG_ReceiptDistributePool
WHERE HeadNumber = #headNumber# AND Status = 0 AND DealID = 0 LIMIT 0, #quantity#
###### Transaction begin ######
3. 更新这批券码的批次号(使用乐观锁)
UPDATE TG_ReceiptDistributePool
SET STATUS = 1, ReceiptDistributePoolBatchFetchID = #fetchID#
WHERE STATUS = 0 AND ReceiptDistributePoolBatchFetchID = 0 AND ReceiptDistributePoolID IN #poolIDs[]#
4. 重新抓取这个批次的券码
SELECT * FROM TG_ReceiptDistributePool WHERE ReceiptDistributePoolBatchFetchID = #fetchID#
5. 券码被输出至内存券池
6. 异步将券码从物理券池删除
DELETE FROM TG_ReceiptDistributePool WHERE ReceiptDistributePoolID IN #poolIDs[]#
###### Transaction end ######
问题
1. 显式使用 synchronized ,性能堪忧
2. 代码问题,如取券池逻辑(先检查后执行,非原子操作)
3. 性能问题,取券码发现不够时,才急急忙忙的去数据库 load
改进
1. 使用生产者消费者模式
2. 券池使用 BlockingQueue
3. Service 初始化时启动生产者线程,启10个线程向各自的内存券池填充数据
4. 外部的发券请求相当于消费者线程,根据券首位从相应券池拿券。 注意限时 take 的使用
Job 会每分钟 loop 券首位(1-9),生成一批券码往数据库里面插,这里需要做一些过滤:老券池、新券池、内存券池和券表 。
Service 里面有9个内存券池。它会在外部请求发券时定位到某个券池,看它的券够不够,够的话直接返回,否则重新去数据库捞一批进来。捞进来之后把数据库的券码删掉。
数据库有一个额外的“捞取批次表”,主要用来做幂等(防止分布式环境下捞取相同的券):
1. 生成批次 ID
INSERT INTO TG_ReceiptDistributePoolBatchFetch ..
SELECT @@IDENTITY AS receiptDistributePoolBatchFetchID
2. 查找券池表可用券码,以备插入内存券池
SELECT * FROM TG_ReceiptDistributePool
WHERE HeadNumber = #headNumber# AND Status = 0 AND DealID = 0 LIMIT 0, #quantity#
###### Transaction begin ######
3. 更新这批券码的批次号(使用乐观锁)
UPDATE TG_ReceiptDistributePool
SET STATUS = 1, ReceiptDistributePoolBatchFetchID = #fetchID#
WHERE STATUS = 0 AND ReceiptDistributePoolBatchFetchID = 0 AND ReceiptDistributePoolID IN #poolIDs[]#
4. 重新抓取这个批次的券码
SELECT * FROM TG_ReceiptDistributePool WHERE ReceiptDistributePoolBatchFetchID = #fetchID#
5. 券码被输出至内存券池
6. 异步将券码从物理券池删除
DELETE FROM TG_ReceiptDistributePool WHERE ReceiptDistributePoolID IN #poolIDs[]#
###### Transaction end ######
问题
1. 显式使用 synchronized ,性能堪忧
2. 代码问题,如取券池逻辑(先检查后执行,非原子操作)
3. 性能问题,取券码发现不够时,才急急忙忙的去数据库 load
改进
1. 使用生产者消费者模式
2. 券池使用 BlockingQueue
3. Service 初始化时启动生产者线程,启10个线程向各自的内存券池填充数据
4. 外部的发券请求相当于消费者线程,根据券首位从相应券池拿券。 注意限时 take 的使用