讨论下 卡密下发 保证不重发 除了不用 redis 还有啥方案

2022-01-05 14:48:13 +08:00
 lipaa

业务背景:公司采购了一批爱奇艺会员卡密,导入到了 mysql 现在的做法是有用户购买就获取最后一张未使用的, 更新时判断状态(可能已被使用 会失败),如果失败就自旋重试 redis 的方案已经启弃用了 感觉难以保证一致性... 各大 v 友还有啥方案 麻了

5218 次点击
所在节点    程序员
54 条回复
philchang1995
2022-01-05 16:29:56 +08:00
@abigeater 还有你的那个给领取表填数据的定时任务是不是不太合理,领取表的数据来源只有用户触发领取操作这一个途径才对吧
Rache1
2022-01-05 16:32:26 +08:00
如果觉得单独引入 redis 做锁成本太高的话,又想用类似可铐的方案,可以用 flock
boozer
2022-01-05 16:37:09 +08:00
说个题外话, 有时候业务问题不该让技术来买单
hgc81538
2022-01-05 16:55:08 +08:00
我想到這個方法:

UPDATE key_table set user_id="123" where id = (Select min(id) from key_table where user_id=null);

如果 affected rows == 0 就重試一, 兩次, 都不成功就報錯, 叫用戶稍後再試
如果 affected rows == 1, 則成功.
這方法不用鎖, 請問可行嗎?
abigeater
2022-01-05 17:04:25 +08:00
@philchang1995 主要目标是将领取这个过程变成异步填充
和 13 的有区别吧 毕竟我更希望是有 ID 关联 有日志可查
假设一共有 2 张表卡密表 和 领取表
卡密表 id,code
领取表 id,user_id,code
通过 ID 获取是指,领取表的 ID 找到该条记录 (如果怕被穷举 可以用 hash 或者鉴权 user_id ) 轮询到 code 不为空为止。

正如你所说领取表数据来源是用户触发,用户写入了 user_id 到领取表后,一个队列(假设是定时任务或者 mq 消费队列)只需要取出 code 等于空的数据 从卡密表获取数据后 update 即可。

主要目的把这个领取过程交给后台异步队列填充,避免并发。
ZXCDFGTYU
2022-01-05 17:28:39 +08:00
之前遇到过类似的问题,用 for update 结合 order by 使用次数 asc 解决的
ganbuliao
2022-01-05 17:33:49 +08:00
redis list 不是挺好的吗
gam2046
2022-01-05 17:45:45 +08:00
这样可以嘛?

cursor = select ... for update from ... where status = unused limit 1

update set cursor.status = used

return cursor
Pythoner666666
2022-01-05 17:46:52 +08:00
@EileenJ 没有·
dzdh
2022-01-05 17:49:52 +08:00
难道不是给 code +个 order_id 的字段么
Pythoner666666
2022-01-05 17:54:00 +08:00
归根结底就是个并发问题。下发的时候加锁,可以解决 99%的下发。剩下 1%的锁冲突就丢到队列,然后消费队列即可。
lipaa
2022-01-05 17:55:07 +08:00
@ZXCDFGTYU for update 只是锁住了 b 如果 a 事务释放 b 之后还是可以拿到锁的
lipaa
2022-01-05 17:55:23 +08:00
@ganbuliao 领导觉得一致性难以保证
lipaa
2022-01-05 17:56:17 +08:00
感谢 大家 还是自旋把 一次性取一大批 再去乐观锁更新 也基本可以保证不出问题
philchang1995
2022-01-05 17:56:40 +08:00
@abigeater 那是我一开始理解错你的队列的意思了,按这样的逻辑来的话确实可以避免发卡的并发操作 只是领卡并发高的时候用户轮询等待卡密这一块可能会等的久一点 不过我个人感觉这个方案可行👍
whcoding
2022-01-05 17:58:27 +08:00
我公司给你这差不多的一个业务
whcoding
2022-01-05 18:00:24 +08:00
我公司给你这差不多的一个业务 是这么处理的 导入的时候 同时导入 mysql 和 redis list, 用户来取码直接取 list 中的 然后去走个队列去修改数据库. 完事 ~
Building
2022-01-05 18:00:35 +08:00
分成几张表放,再加锁,并发不就好了吗。
Chad0000
2022-01-05 18:05:06 +08:00
这种并发应该不高吧,可能使用队列,然后只有一个消费者,外加乐观锁,外加先写日志,就差不多了吧。
philchang1995
2022-01-05 18:08:47 +08:00
@whcoding 这种方案 redis 的集群和数据保持做的好的话还不错 如果不好的话数据一致性和数据丢失确实是个问题

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/826349

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX