最新要闻
- 焦点消息!“人为失误”击落乌克兰客机致176人遇难,伊朗判处10名军人有期徒刑
- 天天快看:时长2小时15分钟!真人版《小美人鱼》主演地广海报来了 黑美人鱼美吗
- 48个月流畅!小米平板6开机就是MIUI Pad 14:光子引擎性能飙升
- 环球快看点丨1254MB暴力缓存!AMD 96核心超级旗舰霄龙9684X首次亮相
- 天天简讯:“网红裤”+平底鞋,今夏必穿 !巨显腿长巨时髦!
- 纯白外观质感绝了!小米13 Ultra白色版首度亮相:已中毒
- 今日报丨79元!米家多功能充电台灯发布:无可视频闪、一灯三用秒变手电筒
- 全球热资讯!普通工人月薪1万 五险一金心动?特斯拉上海工厂被爆恶意克扣绩效奖 员工不满
- 每日观察!游客淄博买饼被宰?网友转账补差价 Up主回应:感谢山东人的实在和热情
- 【世界聚看点】苹果每三天赚10亿美元! 马斯克大赞:领导力改变一切
- 要闻:官方:CBA公司及各俱乐部将深刻汲取教训
- 【播资讯】酱香科技过去式!中国移动市值超越贵州茅台成A股股王:加速千兆宽带
- 为五一假期调休:本周要上六天班 别忘定周日闹钟
- 硬核!马斯克母亲获得荣誉博士学位:目前经营一家营养企业
- iPhone 11用户换Redmi Note 12 Turbo:妥妥的体验升级 再也不买苹果了
- 每日观察!余承东称2025年是汽车行业分水岭 专家:淘汰赛刚刚开始
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
全球焦点!布隆过滤器:后端开发者必学的知识点!
摘要:对于后端程序员来讲,学习和理解布隆过滤器有很大的必要性。来吧,我们一起品味布隆过滤器的设计之美。
本文分享自华为云社区《品味布隆过滤器的设计之美》,作者:勇哥java实战分享。
布隆过滤器是一个精巧而且经典的数据结构。
你可能没想到: RocketMQ、 Hbase 、Cassandra 、LevelDB 、RocksDB 这些知名项目中都有布隆过滤器的身影。
(资料图)
对于后端程序员来讲,学习和理解布隆过滤器有很大的必要性。来吧,我们一起品味布隆过滤器的设计之美。
1 缓存穿透
我们先来看一个商品服务查询详情的接口:
public Product queryProductById (Long id){ // 查询缓存 Product product = queryFromCache(id); if(product != null) { return product ; } // 从数据库查询 product = queryFromDataBase(id); if(product != null) { saveCache(id , product); } return product;}
假设此商品既不存储在缓存中,也不存在数据库中,则没有办法回写缓存,当有类似这样大量的请求访问服务时,数据库的压力就会极大。
这是一个典型的缓存穿透的场景。
为了解决这个问题呢,通常我们可以向分布式缓存中写入一个过期时间较短的空值占位,但这样会占用较多的存储空间,性价比不足。
问题的本质是:"如何以极小的代价检索一个元素是否在一个集合中?"
我们的主角布隆过滤器出场了,它就能游刃有余的平衡好时间和空间两种维度。
2 原理解析
布隆过滤器(英语:Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。
布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。
布隆过滤器的原理:当一个元素被加入集合时,通过 K 个散列函数将这个元素映射成一个位数组中的 K 个点,把它们置为 1。检索时,我们只要看看这些点是不是都是 1 就(大约)知道集合中有没有它了:如果这些点有任何一个 0,则被检元素一定不在;如果都是 1,则被检元素很可能在。
简单来说就是准备一个长度为 m 的位数组并初始化所有元素为 0,用 k 个散列函数对元素进行 k 次散列运算跟 len (m) 取余得到 k 个位置并将 m 中对应位置设置为 1。
如上图,位数组的长度是8,散列函数个数是 3,先后保持两个元素x,y。这两个元素都经过三次哈希函数生成三个哈希值,并映射到位数组的不同的位置,并置为1。元素 x 映射到位数组的第0位,第4位,第7位,元素y映射到数组的位数组的第1位,第4位,第6位。
保存元素 x 后,位数组的第4位被设置为1之后,在处理元素 y 时第4位会被覆盖,同样也会设置为 1。
当布隆过滤器保存的元素越多,被置为 1 的 bit 位也会越来越多,元素 x 即便没有存储过,假设哈希函数映射到位数组的三个位都被其他值设置为 1 了,对于布隆过滤器的机制来讲,元素 x 这个值也是存在的,也就是说布隆过滤器存在一定的误判率。
▍ 误判率
布隆过滤器包含如下四个属性:
k : 哈希函数个数
m : 位数组长度
n : 插入的元素个数
p : 误判率
若位数组长度太小则会导致所有 bit 位很快都会被置为 1 ,那么检索任意值都会返回”可能存在“ , 起不到过滤的效果。 位数组长度越大,则误判率越小。
同时,哈希函数的个数也需要考量,哈希函数的个数越大,检索的速度会越慢,误判率也越小,反之,则误判率越高。
从张图我们可以观察到相同位数组长度的情况下,随着哈希函数的个人的增长,误判率显著的下降。
我们会预估布隆过滤器的误判率 p 以及待插入的元素个数 n 分别推导出最合适的位数组长度 m 和 哈希函数个数 k。
▍ 布隆过滤器支持删除吗
布隆过滤器其实并不支持删除元素,因为多个元素可能哈希到一个布隆过滤器的同一个位置,如果直接删除该位置的元素,则会影响其他元素的判断。
▍ 时间和空间效率
布隆过滤器的空间复杂度为 O(m) ,插入和查询时间复杂度都是 O(k) 。 存储空间和插入、查询时间都不会随元素增加而增大。 空间、时间效率都很高。
▍哈希函数类型
Murmur3,FNV 系列和 Jenkins 等非密码学哈希函数适合,因为 Murmur3 算法简单,能够平衡好速度和随机分布,很多开源产品经常选用它作为哈希函数。
3 Guava实现
Google Guava是 Google 开发和维护的开源 Java开发库,它包含许多基本的工具类,例如字符串处理、集合、并发工具、I/O和数学函数等等。
1、添加Maven依赖
com.google.guava guava 31.0.1-jre<
2、创建布隆过滤器
BloomFilterfilter = BloomFilter.create( //Funnel 是一个接口,用于将任意类型的对象转换为字节流, //以便用于布隆过滤器的哈希计算。 Funnels.integerFunnel(), 10000, // 插入数据条目数量 0.001 // 误判率);
3、添加数据
@PostConstructpublic void addProduct() { logger.info("初始化布隆过滤器数据开始"); //插入4个元素 filter.put(1L); filter.put(2L); filter.put(3L); filter.put(4L); logger.info("初始化布隆过滤器数据结束");}
4、判断数据是否存在
public boolean maycontain(Long id) { return filter.mightContain(id);}
接下来,我们查看 Guava 源码中布隆过滤器是如何实现的 ?
staticBloomFilter create(Funnel super T> funnel, long expectedInsertions, double fpp, BloomFilter.Strategy strategy) { // 省略部分前置验证代码 // 位数组长度 long numBits = optimalNumOfBits(expectedInsertions, fpp); // 哈希函数次数 int numHashFunctions = optimalNumOfHashFunctions(expectedInsertions, numBits); try { return new BloomFilter ( new LockFreeBitArray(numBits), numHashFunctions, funnel, strategy ); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("Could not create BloomFilter of " + numBits + " bits", e); }}//计算位数组长度//n:插入的数据条目数量//p:期望误判率@VisibleForTestingstatic long optimalNumOfBits(long n, double p) { if (p == 0) { p = Double.MIN_VALUE; } return (long) (-n * Math.log(p) / (Math.log(2) * Math.log(2)));}// 计算哈希次数@VisibleForTestingstatic int optimalNumOfHashFunctions(long n, long m) { // (m / n) * log(2), but avoid truncation due to division! return Math.max(1, (int) Math.round((double) m / n * Math.log(2)));}
Guava 的计算位数组长度和哈希次数和原理解析这一节展示的公式保持一致。
重点来了,Bloom filter 是如何判断元素存在的 ?
方法名就非常有 google 特色 , ”mightContain“ 的中文表意是:”可能存在“ 。方法的返回值为 true ,元素可能存在,但若返回值为 false ,元素必定不存在。
publicboolean mightContain( @ParametricNullness T object, //Funnel 是一个接口,用于将任意类型的对象转换为字节流, //以便用于布隆过滤器的哈希计算。 Funnel super T> funnel, //用于计算哈希值的哈希函数的数量 int numHashFunctions, //位数组实例,用于存储布隆过滤器的位集 LockFreeBitArray bits) { long bitSize = bits.bitSize(); //使用 MurmurHash3 哈希函数计算对象 object 的哈希值, //并将其转换为一个 byte 数组。 byte[] bytes = Hashing.murmur3_128().hashObject(object, funnel).getBytesInternal(); long hash1 = lowerEight(bytes); long hash2 = upperEight(bytes); long combinedHash = hash1; for (int i = 0; i < numHashFunctions; i++) { // Make the combined hash positive and indexable // 计算哈希值的索引,并从位数组中查找索引处的位。 // 如果索引处的位为 0,表示对象不在布隆过滤器中,返回 false。 if (!bits.get((combinedHash & Long.MAX_VALUE) % bitSize)) { return false; } // 将 hash2 加到 combinedHash 上,用于计算下一个哈希值的索引。 combinedHash += hash2; } return true;}
4 Redisson实现
Redisson 是一个用 Java 编写的 Redis 客户端,它实现了分布式对象和服务,包括集合、映射、锁、队列等。Redisson的API简单易用,使得在分布式环境下使用Redis 更加容易和高效。
1、添加Maven依赖
org.redisson redisson 3.16.1
2、配置 Redisson 客户端
@Configurationpublic class RedissonConfig { Bean public RedissonClient redissonClient() { Config config = new Config(); config.useSingleServer().setAddress("redis://localhost:6379"); return Redisson.create(config); } }
3、初始化
RBloomFilterbloomFilter = redissonClient. getBloomFilter("myBloomFilter");//10000表示插入元素的个数,0.001表示误判率bloomFilter.tryInit(10000, 0.001);//插入4个元素bloomFilter.add(1L);bloomFilter.add(2L);bloomFilter.add(3L);bloomFilter.add(4L);
4、判断数据是否存在
public boolean mightcontain(Long id) { return bloomFilter.contains(id);}
好,我们来从源码分析 Redisson 布隆过滤器是如何实现的 ?
public boolean tryInit(long expectedInsertions, double falseProbability) { // 位数组大小 size = optimalNumOfBits(expectedInsertions, falseProbability); // 哈希函数次数 hashIterations = optimalNumOfHashFunctions(expectedInsertions, size); CommandBatchService executorService = new CommandBatchService(commandExecutor); // 执行 Lua脚本,生成配置 executorService.evalReadAsync(configName, codec, RedisCommands.EVAL_VOID, "local size = redis.call("hget", KEYS[1], "size");" + "local hashIterations = redis.call("hget", KEYS[1], "hashIterations");" + "assert(size == false and hashIterations == false, "Bloom filter config has been changed")", Arrays.
Redisson 布隆过滤器初始化的时候,会创建一个 Hash 数据结构的 key ,存储布隆过滤器的4个核心属性。
那么 Redisson 布隆过滤器如何保存元素呢 ?
public boolean add(T object) { long[] hashes = hash(object); while (true) { int hashIterations = this.hashIterations; long size = this.size; long[] indexes = hash(hashes[0], hashes[1], hashIterations, size); CommandBatchService executorService = new CommandBatchService(commandExecutor); addConfigCheck(hashIterations, size, executorService); //创建 bitset 对象, 然后调用setAsync方法,该方法的参数是索引。 RBitSetAsync bs = createBitSet(executorService); for (int i = 0; i < indexes.length; i++) { bs.setAsync(indexes[i]); } try { Listresult = (List ) executorService.execute().getResponses(); for (Boolean val : result.subList(1, result.size()-1)) { if (!val) { return true; } } return false; } catch (RedisException e) { } }}
从源码中,我们发现 Redisson 布隆过滤器操作的对象是位图(bitMap)。
在 Redis 中,位图本质上是 string 数据类型,Redis 中一个字符串类型的值最多能存储 512 MB 的内容,每个字符串由多个字节组成,每个字节又由 8 个 Bit 位组成。位图结构正是使用“位”来实现存储的,它通过将比特位设置为 0 或 1来达到数据存取的目的,它存储上限为2^32
,我们可以使用getbit/setbit
命令来处理这个位数组。
为了方便大家理解,我做了一个简单的测试。
通过 Redisson API 创建 key 为mybitset
的 位图 ,设置索引 3 ,5,6,8 位为 1 ,右侧的二进制值也完全匹配。
5 实战要点
通过 Guava 和 Redisson 创建和使用布隆过滤器比较简单,我们下面讨论实战层面的注意事项。
1、缓存穿透场景
首先我们需要初始化布隆过滤器,然后当用户请求时,判断过滤器中是否包含该元素,若不包含该元素,则直接返回不存在。
若包含则从缓存中查询数据,若缓存中也没有,则查询数据库并回写到缓存里,最后给前端返回。
2、元素删除场景
现实场景,元素不仅仅是只有增加,还存在删除元素的场景,比如说商品的删除。
原理解析这一节,我们已经知晓:布隆过滤器其实并不支持删除元素,因为多个元素可能哈希到一个布隆过滤器的同一个位置,如果直接删除该位置的元素,则会影响其他元素的判断。
我们有两种方案:
▍计数布隆过滤器
计数过滤器(Counting Bloom Filter)是布隆过滤器的扩展,标准 Bloom Filter 位数组的每一位扩展为一个小的计数器(Counter),在插入元素时给对应的 k (k 为哈希函数个数)个 Counter 的值分别加 1,删除元素时给对应的 k 个 Counter 的值分别减 1。
虽然计数布隆过滤器可以解决布隆过滤器无法删除元素的问题,但是又引入了另一个问题:“更多的资源占用,而且在很多时候会造成极大的空间浪费”。
▍ 定时重新构建布隆过滤器
从工程角度来看,定时重新构建布隆过滤器这个方案可行也可靠,同时也相对简单。
定时任务触发全量商品查询 ;
将商品编号添加到新的布隆过滤器 ;
任务完成,修改商品布隆过滤器的映射(从旧 A 修改成 新 B );
商品服务根据布隆过滤器的映射,选择新的布隆过滤器 B进行相关的查询操作 ;
选择合适的时间点,删除旧的布隆过滤器 A。
6 总结
布隆过滤器是一个很长的二进制向量和一系列随机映射函数,用于检索一个元素是否在一个集合中。
它的空间效率和查询时间都远远超过一般的算法,但是有一定的误判率 (函数返回 true , 意味着元素可能存在,函数返回 false ,元素必定不存在)。
布隆过滤器的四个核心属性:
k : 哈希函数个数
m : 位数组长度
n : 插入的元素个数
p : 误判率
Java 世界里 ,通过 Guava 和 Redisson 创建和使用布隆过滤器非常简单。
布隆过滤器无法删除元素,但我们可以通过计数布隆过滤器和定时重新构建布隆过滤器两种方案实现删除元素的效果。
为什么这么多的开源项目中使用布隆过滤器 ?
因为它的设计精巧且简洁,工程上实现非常容易,效能高,虽然有一定的误判率,但软件设计不就是要 trade off 吗 ?
参考资料:https://hackernoon.com/probabilistic-data-structures-bloom-filter-5374112a7832
点击关注,第一时间了解华为云新鲜技术~
关键词:
-
世界观点:易基因:全基因组CpG密度和DNA甲基化分析方法比较(MeDIP、RRBS和WGBS)| 研究综述
大家好,这里是专注表观组学十余年,领跑多组学科研服务的易基因。CpG密度(CpGdensity)与各种组织中的...
来源: -
焦点消息!“人为失误”击落乌克兰客机致176人遇难,伊朗判处10名军人有期徒刑
伊朗司法部门宣布对10名未透露姓名的人判处1年至13年不等的有期徒刑,这些人据称应对2020年1月乌克兰国...
来源: 世界观点:易基因:全基因组CpG密度和DNA甲基化分析方法比较(MeDIP、RRBS和WGBS)| 研究综述
全球焦点!布隆过滤器:后端开发者必学的知识点!
焦点消息!“人为失误”击落乌克兰客机致176人遇难,伊朗判处10名军人有期徒刑
天天快看:时长2小时15分钟!真人版《小美人鱼》主演地广海报来了 黑美人鱼美吗
48个月流畅!小米平板6开机就是MIUI Pad 14:光子引擎性能飙升
环球快看点丨1254MB暴力缓存!AMD 96核心超级旗舰霄龙9684X首次亮相
天天简讯:“网红裤”+平底鞋,今夏必穿 !巨显腿长巨时髦!
纯白外观质感绝了!小米13 Ultra白色版首度亮相:已中毒
今日报丨79元!米家多功能充电台灯发布:无可视频闪、一灯三用秒变手电筒
全球热资讯!普通工人月薪1万 五险一金心动?特斯拉上海工厂被爆恶意克扣绩效奖 员工不满
每日观察!游客淄博买饼被宰?网友转账补差价 Up主回应:感谢山东人的实在和热情
【世界聚看点】苹果每三天赚10亿美元! 马斯克大赞:领导力改变一切
世界滚动:JS中Map、WeakMap和Object的区别
从此告别写 SQL!DataLeap 帮你零门槛完成“数据探查”
要闻:官方:CBA公司及各俱乐部将深刻汲取教训
【播资讯】酱香科技过去式!中国移动市值超越贵州茅台成A股股王:加速千兆宽带
为五一假期调休:本周要上六天班 别忘定周日闹钟
硬核!马斯克母亲获得荣誉博士学位:目前经营一家营养企业
iPhone 11用户换Redmi Note 12 Turbo:妥妥的体验升级 再也不买苹果了
每日观察!余承东称2025年是汽车行业分水岭 专家:淘汰赛刚刚开始
微商城怎么注册?微商城和小程序商城有什么区别?
东莞电信的DNS是多少?东莞电信套餐资费一览表2023
联想K900跑分是多少?联想K900搭配的CPU是哪个厂商的?
ipad mini2可以升级到什么版本?ipad mini2参数配置
电信卡欠费多久会自动销户?电信卡用的手机制式是什么?
每日热文:MySQL 处理大数据表的 3 种方案,写的太好了,建议收藏!!
【全球速看料】Spring AOP官方文档学习笔记(二)之基于注解的Spring AOP
全球快资讯:exec 函数族 - 进程替换
今日看点:【创新突破 产业突围】周振宇带队前往陕西西安开展招商考察活动
全球热消息:小米13 Ultra官图公布:传承徕卡M系列相机设计 支持IP68
世界新消息丨埃安高管:特斯拉不是不能战胜 Hyper GT全面超越Model 3
简讯:2TB 1049元 1TB不到600:三星SSD/内存降价不买要涨价 国产存储顶上
售价17万的特斯拉要来了:谁开心、谁恐慌?
每日热点:ChatGPT之父辟谣:并未秘密训练GPT-5 短期内也不会
ST华英说明申请撤销其他风险警示相关情况
当前热文:明晚发布!小米13 Ultra外观正式揭晓:更像相机了
全球热头条丨毁经典!《海贼王》真人剧集口碑扑街:日漫原著粉在线声讨
全球讯息:余承东预言:2025年是汽车行业分水岭、像2013年的手机行业
苹果将于6月推出多款新品!苹果表将迎史上最大的软件更新
我国自研高性能兆瓦级PEM电解水制氢装备发布:国产化率超90%
环球即时看!维生素ABCDE的作用及功能主治(维生素abcde的作用及功能)
环球视讯![Flink] Flink作业报错:Caused by: The connector is trying to read binlog startin
每日热闻!央行圆桌汇:4月17日
今日报丨《百度智能驾驶开放白皮书》发布 面向车企开放四大能力
今头条!特斯拉中国工厂待遇如何?普通工人月薪1万块 父母看病都能报销
女子借朋友摩托车无证驾驶 在隧道“狂飙”拍抖音 朋友也惨了
世界快讯:真人版《小美人鱼》国内将上映!黑小美人鱼喊话自己可爱:我爱的人而战
全球百事通!全系800V高压、一体化铝压铸车身!小鹏SEPA 2.0扶摇架构发布
比原版多50分钟!真人版《小美人鱼》片长超2小时
热议:SoapUI使用教程-九五小庞
实时焦点:债市观察:做多情绪占优 收益率曲线平坦化下移
【读财报】制造主题基金2022年业绩透视:广发基金领亏 摩根基金净值跌幅最大
苹果设备不断要求输入Apple ID密码!客服回应:可尝试修改密码
环球今日讯!猿辅导被举报单日加班超6小时:上厕所需报备 时薪仅17元
当前快报:2022年全国共登记计算机软件著作权183.5万件:比十年前高12倍
全球快报:国内成品油零售价迎今年最大涨幅 加满多花70元:沙特俄罗斯减产 国际油价大涨
环球新资讯:卢谈G1:我们没有太多容错空间&不是试探性比赛 必须全力以赴
环球观点:学系统集成项目管理工程师(中项)系列08a_合同管理(上)
杭州萧山国际机场T3航站楼出现冒烟现象:无人受伤
天天视讯!今晚开始!国内成品油零售价迎今年最大涨幅:加满一箱多花20元
【全球报资讯】考研数据结构模板:顺序表、链表、栈、队列
世界热资讯!王一博、梁朝伟主演电影《无名》结束公映:85天票房9.31亿
热讯:RTX 4060 Ti、RTX 4060严重缩水:除了显存 还有一点没法看
天天视点!人类真是动物界最优秀的长跑运动员?别闹了
环球快报:一款车发布两年还没影!长城怎么这么难产?
当前聚焦:机械硬盘卖不动了 销量暴跌35%!三大品牌抱团哭惨
三代同堂!46岁皇马传奇古蒂升级当爷爷,22岁网红大女儿产下一子
天天关注:Node.js的安装以及配置npm全局模块路径和缓存路径
使用Sentieon加速甲基化(WGBS)分析
世界短讯!【明日方舟】4周年活动更新预测(第二版)
当前头条:4年不卡的骁龙8+旗舰来了!一加Ace 2原神限定版明天发:抢到赚到
全球视点!iOS 17控制中心将有大变化:有一批老设备不支持 将被淘汰
AMD、NVIDIA新一代显卡全部破发!次旗舰双双最惨
环球热议:扎实打牢数据结构算法根基,从此不怕算法面试系列之005 week01 02-05 使用自定义类测试我们前面实现的支持泛型的线性查找法
如何获取软件包的下载地址 wget curl
基于GPT3的代码编辑器Cursor试用-你的智能代码编辑助手
每日快播:React onBlur回调中使用document.activeElement返回body解决方案
世界观察:民营天龙二号液体火箭首飞成功:还隐藏了一个中国第一
天天看热讯:不知道这几点!你买电动牙刷就是花冤枉钱
世界热资讯!热泵干衣机被严重低估了!浑身都是宝
环球快播:致聂红的一封信
环球快报:2023上海车展丨这些即将首发的热门新车你一定不要错过!
云南泼水节白天是热闹夜晚是浪漫:市民游客共狂欢
员工回应公司发布高薪招聘老板公告:不是开玩笑
热推荐:java -- File类和递归
贾跃亭憋了九年的车终于量产?结果 又一张大饼!
环球快报:四边等宽的鸿蒙手机来了!华为nova 11明天发
潍坊风筝节放飞打工人的心声:引发网友热议
Intel鸡血驱动暴涨63%!Arc A750性价比秒杀RTX 3060 72%!
当前最新:天舟六号飞船、长征七号火箭抵达文昌!五次发射 100%成功
山东泰山队vs上海申花首发出炉:四外援先发,韩镕泽镇守球门
每日热讯!“泼水节被撕扯雨衣”女生发声:很崩溃
世界快报:众人狂欢!泼水节连狗路过都得淋两桶水再走
贝贝健电蚊香液到手14.9元:驱赶蚊虫神器 夏天必备
全球信息:超级SSD 21合一组成168TB!价格直奔20万元
全球视点!扎实打牢数据结构算法根基,从此不怕算法面试系列之001 week01 02-01 什么是算法?
焦点快报!女子花2万为猫移植鱼皮被网暴 本人:救治一半不可能放弃
全球热头条丨女子澄清妈妈做月嫂存款482万为虚构:觉得好玩就发了 现在很后悔
环球热文:养男三不碰,养女三讲究,教出来的孩子才能立足社会!
世界信息:Air724UG开发板串口教程