每秒3K个传入请求的重复检测,推荐的数据结构/算法?

时间:2011-11-16 14:55:32

标签: java algorithm servlets data-structures concurrency

设计一个系统,其中服务端点(可能是一个简单的servlet)必须每秒处理3K个请求(数据将被http发布)。

然后将这些请求存储到mysql中。

我需要指导的关键问题是,他们将发布到此端点的重复数据的百分比很高。

我只需要将唯一数据存储到mysql中,那么您建议我用什么来处理重复?

发布的数据如下所示:

<root>
<prop1></prop1>
<prop2></prop2>
<prop3></prop3>
<body>
maybe 10-30K of test in here
</body>
</root>

我将编写一个方法,将prop1,prop2,pro3哈希,以创建一个唯一的哈希码(主体可以不同,但​​仍然被认为是唯一的)。

我正在考虑创建某种并发字典,这些字典将在请求中共享。

他们更有机会在24小时内重复发布数据。所以我可以在每x小时后从这本字典中清除数据。

有关存储重复的数据结构的任何建议吗?考虑清除以及每秒3K请求应该存储多少记录,即它会变得非常快。

注意:它们是将要发布的10K个不同来源,并且只有给定来源才会出现重复的可能性。意思是我可能有一个以上的字典,可能是一组消息来源。意思是如果source1发布数据,然后source2发布数据,则重复的更改非常低。但如果source1每天发布100次,则重复的可能性非常高。

注意:请暂时忽略将发布的数据保存到mysql的任务,因为这是另一个问题,重复检测是我需要帮助的第一个障碍。

6 个答案:

答案 0 :(得分:1)

有趣的问题。

我可能会在这里查看HashMaps结构的某种HashMap,其中第一级HashMaps将使用源作为键,第二级将包含实际数据(检测重复项的最小值)并使用您的哈希码函数用于散列。对于实际实现,可能会选择Java的ConcurrentHashMap。

这样,如果需要在多台计算机上分配负载,还可以设置结构以根据来源对传入负载进行分区。

关于清除我认为你必须用数据等生产来衡量确切的行为。当您成功消除重复项以及它在HashMaps中的分布方式时,您需要了解数据增长的速度。凭借良好的分销和不太快的增长,我可以想象偶尔进行清理是足够好的。否则,LRU政策可能会很好。

答案 1 :(得分:1)

听起来你需要一个可以在恒定时间内添加和检查密钥存在的散列结构。在这种情况下,尝试实现Bloom filter。请注意,这是一个概率结构,即它可能会告诉您键不存在,但如果仔细调整参数,则可以使失败概率极低。

修改:好的,因此不接受布隆过滤器。要仍然保持常量查找(尽管不是常量插入),请尝试查看Cuckoo hashing

答案 2 :(得分:1)

1)像这样设置数据库

ALTER TABLE Root ADD UNIQUE INDEX(Prop1, Prop2, Prop3);

INSERT INTO Root (Prop1, Prop2, Prop3, Body) VALUES (@prop1, @prop2, @prop3, @body) 
ON DUPLICATE KEY UPDATE Body=@body

2)您不需要任何算法或花哨的哈希ADT

shell> mysqlimport [options] db_name textfile1 [textfile2 ...]

http://dev.mysql.com/doc/refman/5.1/en/mysqlimport.html 使用--replace或--ignore标志,以及--compress。

3)你所有的Java都会......

a)生成CSV文件,然后每隔X秒左右使用StringBuffer类,与新的StringBuffer交换,并将旧的.toString传递给线程,将其刷新到文件/ temp / SOURCE / TIME_STAMP。 CSV

b)偶尔启动mysqlimport命令的Runtime.getRuntime()。exec

c)如果空间有问题,请删除旧的CSV文件,或将其存档到网络存储/备份设备

答案 3 :(得分:0)

嗯,你基本上正在寻找某种非常大的Hashmap和类似

的东西

if (map.put(key, val) != null) // send data

有许多不同的Hashmap实现可用,但您可以查看NBHM。非阻塞放置和设计时考虑到大的可扩展问题可以正常工作。 Map也有迭代器,它们在使用它们遍历地图时不会抛出ConcurrentModificationException,这基本上是我所看到的删除旧数据的要求。另外putIfAbsent就是你真正需要的 - 但不知道这是否比单纯的放置更有效,你必须要求Cliff或检查来源。

然后诀窍是尽量避免通过使其足够大来调整Map的大小 - 否则在调整大小时吞吐量会受到影响(这可能是一个问题)。并考虑如何实现删除旧数据 - 使用一些遍历迭代器的空闲线程并可能删除旧数据。

答案 4 :(得分:0)

使用java.util.ConcurrentHashMap构建哈希的映射,但请确保在创建时将正确的initialCapacity和concurrencyLevel分配给地图。

api docs for ConcurrentHashMap包含所有相关信息:

  

initialCapacity - 初始容量。实施执行   内部尺寸以适应这么多元素。

     

concurrencyLevel - 估计并发更新线程的数量。该   实现执行内部大小调整以尝试适应这种情况   很多线程。

只要您以正确的方式初始化ConcurrentHashMap,您就应该能够使用putIfAbsent来处理3K请求 - 确保将其作为负载测试的一部分进行调整。

但是,在某些时候,尝试处理一台服务器中的所有请求可能会证明太多,并且您将不得不跨服务器进行负载平衡。此时,您可以考虑使用memcached来存储哈希索引,而不是CHP。

但是,你仍然需要解决的有趣问题是:

  • 启动时将所有哈希加载到内存中
  • 确定何时从内存中的地图中清除哈希值

答案 5 :(得分:0)

如果您使用强哈希公式,例如MD5或SHA-1,则根本不需要存储任何数据。重复的概率几乎为空,因此如果您发现两次相同的哈希结果,则第二次重复。 鉴于MD5是16字节,SHA-1 20字节,它应该减少内存需求,因此在CPU缓存中保留更多元素,从而大大提高速度。

存储这些密钥几乎不需要一个小的哈希表,后面跟着树来处理冲突。