问题1
两个分别有60亿字节(Byte)的文件存储了空格隔开的IP地址,现提供4核CPU 以及 12G 内存机器,目标是找出两个文件共有的IP地址并存储到文件C中。
解答
1 容量规划:
60亿字节 = (60 * 10 ^ 8) / 1024 / 1024 = 5.5GB
2 暴力法:
读取其中A文件到内存中(Set去重存储),循环分片读取B文件,如在A 中存在则将其加入到C文件中,并从缓存中删除避免重复加入C中。
多线程加速:(如果对响应速度要求很高的情况下才使用,否则只会引入不必要的技术复杂度)
对B 文件 按照线程数目进行分片, 写A缓存和C文件时会存在多线程安全问题,考虑 1 对C 文件进行二次去重操作 考虑2 C 文件按照线程分片成多个小文件,最终去重并合并成一个C文件
科普布隆过滤器
海量数据优先想到布隆过滤器。但是布隆过滤器能解决 1 哪些key是肯定不存在的 2 判定存在时具有一定概率性(如hash冲突,极其优秀的hash函数也无法保证无hash冲突问题 出现hash冲突后布隆过滤器判断这个key可能存在 具体是否存在需要二次校验)。 综上所述,布隆过滤器适用于处理Redis缓存穿透问题,如被恶意拿一个不存在的id调接口查数据 导致把MySQL查崩掉。可以用布隆过滤器处理上述问题。但在本文题中并不适用。
问题2
问题1中每个文件增长10倍怎么处理?
解答1
1 容量规划:
600亿字节 = (600 * 10 ^ 8) / 1024 / 1024 = 55GB
内存还是12GB 此时采用问题1中解法由于内存限制无法解决此问题。
2 分治算法
step1:遍历文件a,对每个key求取hash(key)%10,然后根据所取得的值将url分别存储到10个小文件(记为a0,a1,...,a9,每个小文件约5.5GB),为什么是10?主要根据内存大小和要分治的文件大小来计算,我们就大致可以把55G大小分为10份,每份大约5.5GB(当然,到底能不能分布尽量均匀,得看hash函数的设计)
step2:遍历文件b,采取和a相同的方式将key分别存储到10个小文件(记为b0,b1,...,b9)(为什么要这样做? 文件a的hash映射和文件b的hash映射函数要保持一致,这样的话相同的url就会保存在对应的小文件中,比如,如果a中有一个key记录data1被hash到了a9文件中,那么如果b中也有相同url,则一定被hash到了b9中)
所以现在问题转换成了:找出10对小文件中每一对相同的key(不对应的小文件不可能有相同的key)
step3:因为每个小文件大约5.5GB,所以我们再可以采用 解法1中的解法处理后续问题。
解答2
在解法1 的基础上
如果ip满足规律性 如192.168.xxx.xxx 那么可以在缓存时使用字典树数据结构可以节省掉n * 8个字符空间
但是每次查询是否存在的时间复杂度会由 Set的O(1) 增长到 字段树的 O(logN)
空间和时间的权衡 依据业务场景以及硬件条件进行权衡
本文探讨了在有限内存条件下,如何利用多核CPU处理两个大型文件中共同的IP地址。首先介绍了暴力法和布隆过滤器在解决该问题上的局限性,然后提出了分治算法,通过哈希函数将大文件拆分成小文件,逐一对小文件进行处理。随着文件规模增长10倍,原有的方法不再适用,于是引入了分治策略,通过将文件按哈希值划分,降低了内存需求。最后讨论了空间和时间复杂度的权衡,以及在特定情况下使用字典树数据结构的可能性。
2212

被折叠的 条评论
为什么被折叠?



