如果以用户为单位上锁,你们会怎么实现这个功能?

2019-01-29 14:59:24 +08:00
 abcbuzhiming
有这么个场景。用户日程安排,要保证时间段设定的唯一性(时间段不能冲突),所以没法在数据库层面上用唯一约束解决问题。一定得想办法在应用层解决。但是同时,每个用户的日程彼此独立,所以不会发生冲突。因此,这个场景是 一个用户可能会和自己发生资源争抢(当压力比较大的时候,用户可能提交两个一样的时间段数据到数据库去),但是用户和用户之间不会发生资源争抢的问题。因此,如果单独在方法阶段加锁,对性能损失就很大——因为它对应的其实是用户争抢资源问题。而我希望的是,是针对用户本身进行加锁,也就是 A 用户如果已经提交了一次设定时间段的请求,在此次提交还没处理完前,因为种种原因 A 用户再次提交了请求,那么这个请求只能等待上一次请求处理完,才能进行处理。同时,其它用户的请求不受影响
5256 次点击
所在节点    Java
32 条回复
wccc
2019-01-29 17:37:05 +08:00
@timsims #19 单个队列 串行的化 还不如直接一个全局的锁吧.....
Raymon111111
2019-01-29 17:39:56 +08:00
用户 id 维度上 redis 的锁?

应该是我没看懂题目, 不知道问题的难点在哪
pabupa
2019-01-29 17:44:40 +08:00
@wccc (⊙o⊙)哦,,我的
prolic
2019-01-29 17:46:21 +08:00
hash 分桶,打到队列或者机器内,然后串行就行了
guyeu
2019-01-29 18:18:21 +08:00
这个显然应该是串行化队列来处理,当然没必要每个用户一个队列。了解一下一致性哈希,把同一用户的所有操作扔到同一个队列去处理就行了。
limuyan44
2019-01-29 18:29:57 +08:00
怎么感觉是防重复提交的问题
fishfisher
2019-01-30 11:48:03 +08:00
@fashy12306 也有这个问题,我同时用多个抢票软件去提交订单,应该就是并发了,抢到了两张时间冲突的票,
用一个软件就只有行程冲突的提示。。。
fishfisher
2019-01-30 11:50:43 +08:00
@fanshy ,,,12306 也有这个问题,我同时用多个抢票软件去提交订单,应该就是并发了,抢到了两张时间冲突的票,
用一个软件就只有行程冲突的提示。。。
fishfisher
2019-01-30 11:52:37 +08:00
@fashy 晕,手残老是 @不到正确的人
deming
2019-01-30 12:14:08 +08:00
锁的粒度控制在用户身上就可以,多个用户同时进来,互不影响,因为锁的粒度在 userId 身上。
利用工具将 一个 userId 并发进来的时候,因为锁的存在也是互斥的。伪代码:
```
addTask(param...){
long userId = getUserId();

//get lock
lockValue=genLockValue();
if(!getLock(userId,lockValue)){
return "some message";
}
//do business
...
releseLock(userId,lockValue);

}


getLock(userId,lockValue){
int retryTime=5;
do{
retryTime--;
redis.setNx(genKey(userId),lockValue);
}while(retryTime>0);
}
releseLock(userId,lockValue){
释放锁的时候判断 key 是这个 key,lockValue 也是这个我的 lockValue 才释放。
否则会错误释放。
}
```
abcbuzhiming
2019-01-31 14:09:47 +08:00
@deming 你的想法就是我的想法。不过,一定非得上 redis 才能实现这个功能? Java 自己的锁搞不定?
PazuLee
2019-02-12 19:27:12 +08:00
拆分成两个问题:
1. 重复提交:增加 token 机制解决,每次提交校验 token 是否相同;前段增加等待的提示,实现方式比较多。
2. 1 之后,剩下问题是如何判断历史 N 条数据与当前新插入数据是否重叠,如果存储只有 MySQL,则必须取出来吧?如果记录数较大,DB 扛不住,可以考虑在缓存中维护一份 user 级别的已提交时间的数据,保存条记录中的 start_time & end_time

以上~应该能解决了吧

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

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

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

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

© 2021 V2EX