腾讯二面:有 40 亿个 QQ 号,限制 1G 内存,问如何去重?被问懵了!

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 腾讯二面:有 40 亿个 QQ 号,限制 1G 内存,问如何去重?被问懵了!

40亿个QQ号,限制1G内存,如何去重?


40亿个unsigned int,如果直接用内存存储的话,需要:


4*4000000000 /1024/1024/1024 = 14.9G ,考虑到其中有一些重复的话,那1G的空间也基本上是不够用的。


想要实现这个功能,可以借助位图。


使用位图的话,一个数字只需要占用1个bit,那么40亿个数字也就是:


4000000000 * 1 /8 /1024/1024 = 476M

相比于之前的14.9G来说,大大的节省了很多空间。


比如要把我的QQ号"907607222"放到Bitmap中,就需要找到第907607222这个位置,然后把他设置成1就可以了。


1bb3565b0085c99264d9d9d7dc747535_1e7b903a6492405ca29a908d46edf278.png


这样,把40亿个数字都放到Bitmap之后,所有位置上是1的表示存在,不为1的表示不存在,相同的QQ号只需要设置一次1就可以了,那么,最终就把所有是1的数字遍历出来就行了。


什么是BitMap?有什么用?

位图(BitMap),基本思想就是用一个bit来标记元素,bit是计算机中最小的单位,也就是我们常说的计算机中的0和1,这种就是用一个位来表示的。


所谓位图,其实就是一个bit数组,即每一个位置都是一个bit,其中的取值可以是0或者1


49a53edcb99cfb869814b7d92f3c5ac3_cfdfd2cb25bc4f4ab0d2ce9c91fe7626.png


像上面的这个位图,可以用来表示1,4,6:


fea598203ea4fab882a25a35ba9f2d80_e7a438a23b004c8fb75747e4a033479d.png


如果不用位图的话,我们想要记录1,4,6 这三个整型的话,就需要用三个unsigned int,已知每个unsigned int占4个字节,那么就是3*4 = 12个字节,一个字节有8 bit,那么就是 12*8 = 96 个bit。


所以,位图最大的好处就是节省空间。


位图有很多种用途,特别适合用在去重、排序等场景中,著名的布隆过滤器就是基于位图实现的。


但是位图也有着一定的限制,那就是他只能表示0和1,无法存储其他的数字。所以他只适合这种能表示ture or false的场景。


推荐一个开源免费的 Spring Boot 实战项目:


https://github.com/javastacks/spring-boot-best-practice


什么是布隆过滤器,实现原理是什么?

布隆过滤器是一种数据结构,用于快速检索一个元素是否可能存在于一个集合(bit 数组)中。


它的基本原理是利用多个哈希函数,将一个元素映射成多个位,然后将这些位设置为 1。当查询一个元素时,如果这些位都被设置为 1,则认为元素可能存在于集合中,否则肯定不存在


所以,布隆过滤器可以准确的判断一个元素是否一定不存在,但是因为哈希冲突的存在,所以他没办法判断一个元素一定存在。只能判断可能存在。


5383a94bbad582646dbee2409e71084b_8f9526010ad546f096960653ee5d7501.png


所以,布隆过滤器是存在误判的可能的,也就是当一个不存在的Hero元素,经过hash1、hash2和hash3之后,刚好和其他的值的哈希结果冲突了。那么就会被误判为存在,但是其实他并不存在。


95a5d0bb0b24353f565509bb03defd6f_95791225cde14ce999c120dde5ef1c7c.png


想要降低这种误判的概率,主要的办法就是降低哈希冲突的概率及引入更多的哈希算法。


下面是布隆过滤器的工作过程:


1、初始化布隆过滤器


在初始化布隆过滤器时,需要指定集合的大小和误判率。布隆过滤器内部包含一个bit数组和多个哈希函数,每个哈希函数都会生成一个索引值。


2、添加元素到布隆过滤器


要将一个元素添加到布隆过滤器中,首先需要将该元素通过多个哈希函数生成多个索引值,然后将这些索引值对应的位设置为 1。如果这些索引值已经被设置为 1,则不需要再次设置。


3、查询元素是否存在于布隆过滤器中


要查询一个元素是否存在于布隆过滤器中,需要将该元素通过多个哈希函数生成多个索引值,并判断这些索引值对应的位是否都被设置为 1。如果这些位都被设置为 1,则认为元素可能存在于集合中,否则肯定不存在。


布隆过滤器的主要优点是可以快速判断一个元素是否属于某个集合,并且可以在空间和时间上实现较高的效率。但是,它也存在一些缺点,例如:


布隆过滤器在判断元素是否存在时,有一定的误判率。、

布隆过滤器删除元素比较困难,因为删除一个元素需要将其对应的多个位设置为 0,但这些位可能被其他元素共享。

应用场景


布隆过滤器因为他的效率非常高,所以被广泛的使用,比较典型的场景有以下几个:


1、网页爬虫: 爬虫程序可以使用布隆过滤器来过滤掉已经爬取过的网页,避免重复爬取和浪费资源。


2、缓存系统: 缓存系统可以使用布隆过滤器来判断一个查询是否可能存在于缓存中,从而减少查询缓存的次数,提高查询效率。布隆过滤器也经常用来解决缓存穿透的问题。


3、分布式系统: 在分布式系统中,可以使用布隆过滤器来判断一个元素是否存在于分布式缓存中,避免在所有节点上进行查询,减少网络负载。


4、垃圾邮件过滤: 布隆过滤器可以用于判断一个邮件地址是否在垃圾邮件列表中,从而过滤掉垃圾邮件。


5、黑名单过滤: 布隆过滤器可以用于判断一个IP地址或手机号码是否在黑名单中,从而阻止恶意请求。


如何使用


Java中可以使用第三方库来实现布隆过滤器,常见的有Google Guava库和Apache Commons库以及Redis。


如Guava:


import com.google.common.hash.BloomFilter;

import com.google.common.hash.Funnels;

public class BloomFilterExample {

   public static void main(String[] args) {

       // 创建布隆过滤器,预计插入100个元素,误判率为0.01

       BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringFunnel(), 100, 0.01);

       // 插入元素

       bloomFilter.put("Lynn");

       bloomFilter.put("666");

       bloomFilter.put("八股文");

       // 判断元素是否存在

       System.out.println(bloomFilter.mightContain("Lynn")); // true

       System.out.println(bloomFilter.mightContain("张三"));  // false

   }

}


Apache Commons:


import org.apache.commons.lang3.StringUtils;

import org.apache.commons.collections4.BloomFilter;

import org.apache.commons.collections4.functors.HashFunctionIdentity;

public class BloomFilterExample {

   public static void main(String[] args) {

       // 创建布隆过滤器,预计插入100个元素,误判率为0.01

       BloomFilter<String> bloomFilter = new BloomFilter<>(HashFunctionIdentity.hashFunction(StringUtils::hashCode), 100, 0.01);

       // 插入元素

       bloomFilter.put("Lynn");

       bloomFilter.put("666");

       bloomFilter.put("八股文");

       // 判断元素是否存在

       System.out.println(bloomFilter.mightContain("Lynn")); // true

       System.out.println(bloomFilter.mightContain("张三"));  // false

   }

}



Redis中可以通过Bloom模块来使用,使用Redisson可以:


Config config = new Config();

config.useSingleServer().setAddress("redis://127.0.0.1:6379");

RedissonClient redisson = Redisson.create(config);

RBloomFilter<String> bloomFilter = redisson.getBloomFilter("myfilter");

bloomFilter.tryInit(100, 0.01);

bloomFilter.add("Lynn");

bloomFilter.add("666");

bloomFilter.add("八股文");

System.out.println(bloomFilter.contains("Lynn"));

System.out.println(bloomFilter.contains("张三"));

redisson.shutdown();


首先创建一个RedissonClient对象,然后通过该对象获取一个RBloomFilter对象,使用tryInit方法来初始化布隆过滤器,指定了最多能添加的元素数量为100,误判率为0.01。


然后,使用add方法将元素"犬小哈"、"666"和"八股文"添加到布隆过滤器中,使用contains方法来检查元素是否存在于布隆过滤器中。


或者Jedis也可以:


Jedis jedis = new Jedis("localhost");

jedis.bfCreate("myfilter", 100, 0.01);

jedis.bfAdd("myfilter", "Lynn");

jedis.bfAdd("myfilter", "666");

jedis.bfAdd("myfilter", "八股文");

System.out.println(jedis.bfExists("myfilter", "Lynn"));

System.out.println(jedis.bfExists("myfilter", "张三"));

jedis.close();

————————————————

版权声明:本文为CSDN博主「Java技术栈」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/youanyyou/article/details/130954898

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
5天前
|
存储 监控 Java
处理40亿个QQ号的挑战:如何在1GB内存中实现高效管理
在大数据时代,如何高效管理和处理海量数据是每个开发者和数据工程师面临的挑战。以40亿个QQ号为例,如何在仅有1GB内存的条件下完成数据的存储、查询和处理,成为了一个值得深入探讨的问题。本文将分享一些有效的策略和技术,帮助你在内存受限的情况下高效处理海量数据。
14 3
|
4月前
|
移动开发 监控 Serverless
函数计算操作报错合集之机器配置显示为1G内存,但报错显示0.12G,是什么原因
在使用函数计算服务(如阿里云函数计算)时,用户可能会遇到多种错误场景。以下是一些常见的操作报错及其可能的原因和解决方法,包括但不限于:1. 函数部署失败、2. 函数执行超时、3. 资源不足错误、4. 权限与访问错误、5. 依赖问题、6. 网络配置错误、7. 触发器配置错误、8. 日志与监控问题。
|
6月前
|
人工智能 算法 BI
【经典问题】给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?
【1月更文挑战第26天】【经典问题】给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?
|
缓存 监控 JavaScript
IM跨平台技术学习(九):全面解密新QQ桌面版的Electron内存优化实践
本文我们将和大家分享新版 QQ 在内存优化方面的探索和阶段性优化进展。虽然本文的讨论主要集中在 Windows 平台,但由于 Electron 的跨平台特性,大部分优化措施也同样适用于 macOS 和 Linux 平台。
230 0
|
6月前
|
SQL 分布式计算 Spark
PolarDB-X用15M内存跑1G的TPCH
在数据时代,过多耗内存的大查询都有可能压垮整个集群,所以其内存管理模块在整个系统中扮演着非常重要的角色。而PolarDB-X 作为一款分布式数据库,其面对的数据可能从TB到GB字节不等,同时又要支持TP和AP Workload,要是在计算过程中内存使用不当,不仅会造成TP和AP相互影响,严重拖慢响应时间,甚至会出现内存雪崩、OOM问题,导致数据库服务不可用。CPU和MEMORY相对于网络带宽比较昂贵,所以PolarDB-X 代价模型中,一般不会将涉及到大量数据又比较耗内存的计算下推到存储DN,DN层一般不会有比较耗内存的计算。这样还有一个好处,当查询性能低的时候,无状态的CN节点做弹性扩容代价相对于DN也低。鉴于此,所以本文主要对PolarDB-X计算层的内存管理进行分析,这有助于大家有PolarDB-X有更深入的理解。
247 4
PolarDB-X用15M内存跑1G的TPCH
|
数据处理
海量数据处理面试题:给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url?
海量数据处理面试题:给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url?
789 0
海量数据处理面试题:给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url?
|
存储 算法
利用bitmap处理海量数据问题:43亿QQ号所占内存大小为什么是512M?40亿个QQ号如何去重?
利用bitmap处理海量数据问题:43亿QQ号所占内存大小为什么是512M?40亿个QQ号如何去重?
441 0
利用bitmap处理海量数据问题:43亿QQ号所占内存大小为什么是512M?40亿个QQ号如何去重?
|
SQL 存储 分布式计算
PolarDB-X 是如何用15M内存跑1G的TPCH
本文主要对PolarDB-X计算层的内存管理进行分析,这有助于大家有PolarDB-X有更深入的理解。 PolarDB-X内存管理机制的设计,主要为了几类问题: 1. 让用户更容易控制每个查询的内存限制; 2. 预防内存使用不当,导致内存溢出进而引发OOM; 3. 避免查询间由于内存争抢出现相互饿死现象; 4. 避免AP Workload使用过多内存,严重拖慢TP Workload
909 0
PolarDB-X 是如何用15M内存跑1G的TPCH
|
3月前
|
存储 编译器 C语言
【C语言篇】数据在内存中的存储(超详细)
浮点数就采⽤下⾯的规则表⽰,即指数E的真实值加上127(或1023),再将有效数字M去掉整数部分的1。
360 0
|
19天前
|
存储 C语言
数据在内存中的存储方式
本文介绍了计算机中整数和浮点数的存储方式,包括整数的原码、反码、补码,以及浮点数的IEEE754标准存储格式。同时,探讨了大小端字节序的概念及其判断方法,通过实例代码展示了这些概念的实际应用。
41 1