实现这个功能是需要注意表单重复提交的危害在于并发问题, 所以实现必须是线程安全的.
定义一下接口
interface FormHashContainer{
// 添加成功之后返回 true, 如果有重复,返回 false
boolean putIfAbsent(Sting hash, Date expireAt)
}
单节点可以使用 hashmap 实现, key 为 hash, value 为过期时间
基本逻辑为:
lock.lock()
try{
// step1
// step2
// step3
}finaly{
lock.unlock();
}
缺点很明显, 所有的 POST 请求到这里都会串行, 影响系统并发
对于绝大多数的请求都是正常的, 非重复提交的, 所以正常请求不应该受到影响.
Date d = hashmap.putIfAbsent(key, value)
if(d == null){
return true;
}else{
lock.lock()
try{
// step1
// step2
// step3
}finaly{
lock.unlock();
}
}
读优化之后性能应该会有所提升, 对于一般的应用也就足够了.
可以考虑使用类似字典树的数据结构, 但是只有 2 -3 层, 每次只锁一个父节点, 这种数据结构实现起来比较复杂, 实际意义也不大.
如果长期不进行清理, 那么 hashmap 会越来越大, 所以我们应该有一个过期方案来释放空间
当发现重复请求之后, 会持有锁, 在这个阶段进行清理是线程安全的, 并且重复请求对于用户来说没有什么实际意义, 所以哪怕响应慢一点也无所谓.
后台跑一个线程定时清理, 清理的时候也应该持有锁, 但是对于非重复请求没有任何性能影响.
当然是 redis 了, // todo
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.