首页 » PHP教程 » phpsadd数组技巧_Redis布隆过滤器实现与总结

phpsadd数组技巧_Redis布隆过滤器实现与总结

访客 2024-11-24 0

扫一扫用手机浏览

文章目录 [+]

问题二:打仗过爬虫的,该当有这么一个需求,须要爬虫的网站万万千万,对付一个新的网站url,我们如何判断这个url我们是否已经爬过了?

问题三:一个邮件系统,有上亿的邮件数量,我们要检测某一个邮箱是否精确发送了邮件信息?

phpsadd数组技巧_Redis布隆过滤器实现与总结

问题四:提到Redis做缓存查询,我们须要考虑几个问题,缓存穿透、缓存击穿和缓存雪崩。
我们该如何办理缓存这种缓请安题呢?

phpsadd数组技巧_Redis布隆过滤器实现与总结
(图片来自网络侵删)
布隆过滤

布隆过滤器实在便是,一种数据构造,是由一串很长的二进制向量组成,可以将其算作一个二进制数组。
既然是二进制,那么里面存放的不是0,便是1,但是初始默认值都是0。

大致的数据构造如下图:

添加数据:

向布隆过滤器中添加 key 时,会利用多个 hash 函数对 key 进行 hash 算得一个整数索引值然后对位数组长度进行取模运算得到一个位置,每个 hash 函数都会算得一个不同的位置。
再把位数组的这几个位置都置为 1 就完成了 add 操作。

获取数据时:

只须要将这个新的数据通过上面自定义的几个哈希函数,分别算出各个值,然后看其对应的地方是否都是1,如果存在一个不是1的情形,那么我们可以说,该新数据一定不存在于这个布隆过滤器中。

Redis配置

在Redis中要利用布隆过滤器,可以直接参照该文档,文档地址

推举利用docker利用办法,如果要编译成so动态库,则须要运行在Linux环境中。
// 安装 docker run -p 6377:6379 --name redis-redisbloom redislabs/rebloom:latest安装完之后,查看docker容器。

进入Redis容器,并查看容器模块状态。

# 进入容器docker exec -it 4a695ead6577 /bin/sh# 登录到Redisredis-cli# 查看Redis模块127.0.0.1:6379> info Modules# Modulesmodule:name=bf,ver=20205,api=1,filters=0,usedby=[],using=[],options=[]

【文章福利】:

操作演示

添加数据

// 单个添加127.0.0.1:6379> bf.add blkey 1(integer) 1127.0.0.1:6379> bf.add blkey 2(integer) 1127.0.0.1:6379> bf.add blkey 2(integer) 0127.0.0.1:6379> bf.add blkey 3(integer) 1127.0.0.1:6379> bf.add blkey 4(integer) 1

// 批量添加127.0.0.1:6379> bf.madd blkey 5 6 7 8 41) (integer) 12) (integer) 13) (integer) 14) (integer) 15) (integer) 0

通过添加会创造,如果元素已经存在,则返回的是0值。

检测数据

// 检测单个值127.0.0.1:6379> bf.exists blkey 1(integer) 1127.0.0.1:6379> bf.exists blkey 2(integer) 1127.0.0.1:6379> bf.exists blkey 3(integer) 1

// 批量检测127.0.0.1:6379> bf.mexists blkey 1 2 3 4 5 101) (integer) 12) (integer) 13) (integer) 14) (integer) 15) (integer) 16) (integer) 0

通过演示会创造,如果元素不存在,则返回的是0值。

代码演示

这里用composer来对Redis布隆过滤器进行操作。
官方也罗列了几种编程措辞的客户端。

文档地址

composer require palicao/php-rebloom

<?phpdeclare(strict_types=1);namespace App\Http\Controllers\Redis;use Illuminate\Http\Request;use Palicao\PhpRebloom\BloomFilter;use Palicao\PhpRebloom\RedisClient;use Palicao\PhpRebloom\RedisConnectionParams;use Redis;/ Redis布隆过滤器 Class BloomFilterController @package App\Http\Controllers\Redis /class BloomFilterController{ private $request; private $host = '192.168.0.112'; private $port = 6377; private $bloomFilter; public function __construct(Request $request) { $this->request = $request->all(); $this->bloomFilter = new BloomFilter( new RedisClient( new Redis(), new RedisConnectionParams($this->host, $this->port) ) ); } / 添加删除数据 @throws \RedisException @author kert / public function index() { // 文章:https://www.cnblogs.com/ysocean/p/12594982.html / @var string $cacheKey 缓存key / $cacheKey = 'bloom'; / @var int $cacheValue 缓存value / $cacheValue = mt_rand(0, 100); // 单个添加缓存 var_dump('插入缓存', $this->bloomFilter->insert((string)$cacheKey, (string)$cacheValue)); // 单个查询缓存 var_dump('验证缓存', $this->bloomFilter->exists((string)$cacheKey, (string)$cacheValue)); / @var array $batchCacheValue 批量缓存value / $batchCacheValue = [mt_rand(0, 100), mt_rand(0, 100), mt_rand(0, 100), mt_rand(0, 100), mt_rand(0, 100)]; // 批量添加缓存 var_dump('批量插入缓存', $this->bloomFilter->insertMany((string)$cacheKey, $batchCacheValue)); // 批量获取缓存 var_dump('批量验证缓存', $this->bloomFilter->manyExist((string)$cacheKey, $batchCacheValue)); }}内存比拟

这里我们通过仿照邮件发送来比拟布隆过滤器和凑集各自占用的内存比拟。

布隆过滤器

public function email(){ / @var string $cacheKey 缓存key / $cacheKey = 'bloom:email'; / @var array $email 缓存邮箱数据 / $emailArray = []; for ($i = 0; $i < 1000; $i++) { array_push($emailArray, $i . 'wangyi@163.com'); } / @var array $insertResult 插入结果 / $insertResult = $this->bloomFilter->insertMany((string)$cacheKey, $emailArray); foreach ($insertResult as $value) { if ($value === false) { echo '插入失落败' . PHP_EOL; } } / @var array $queryResult 查询结果 / $queryResult = $this->bloomFilter->manyExist((string)$cacheKey, $emailArray); foreach ($queryResult as $value) { if ($value === false) { echo '查询失落败' . PHP_EOL; } }}

凑集

public function emailSet(){ / @var string $cacheKey 缓存key / $cacheKey = 'set:email'; / @var array $email 缓存邮箱数据 / $emailArray = []; for ($i = 0; $i < 1000; $i++) { array_push($emailArray, $i . 'wangyi@163.com'); } $redis = new Redis(); $redis->connect($this->host, $this->port); var_dump($redis->sAddArray($cacheKey, $emailArray));}

内存比拟

/ 初始内存:854.40K 布隆过滤器:857.50K ~3k 凑集:912.52K ~55k /

通过比拟创造,同样的邮箱数量,利用set的办法比利用过滤器的办法,内存至少多利用18倍多。

案例办理

在文章开头,我们引入了几个问题?首先我们想到的第一个技能方案便是通过数据库查询。
这样数据更加准确。
但是我们须要考虑一个问题,如果数据量很大,没查询一次都走数据库,无疑是给数据库增加了包袱。

如果我们通过布隆过滤器来实现,既能办理我们实际的需求,也能办理数据库压力过重的情形。

下面演示代码实现逻辑。

/ 检测某一个手机号是否已经发送短信内容 @author kert/public function filterMobile(){ / @var string $cacheKey 缓存key / $cacheKey = 'bloom:mobile'; / @var array $email 缓存手机号数据(仿照发送过的手机号) / $mobileArray = []; for ($i = 0; $i < 1000; $i++) { array_push($mobileArray, substr(md5((string)$i), 0, 11)); } // 插入布隆过滤器 $this->bloomFilter->insertMany((string)$cacheKey, $mobileArray); // 检测某一个值是否存在 var_dump($this->bloomFilter->exists((string)$cacheKey, (string)substr(md5((string)100), 0, 11))); // output bool(true)}

通过上面的演示,我们不丢脸出,布隆过滤在对数据检测是否存在的情形,要比走数据库好很多。

优缺陷剖析通过上面内存比拟的内容,以及对布隆过滤器实现事理、存储数据格式的理解,我们可以得出布隆过滤器可以节省内存,尤其是数据大的情形下。
布隆过滤器是不支持删除数据的,如果须要删除数据则须要重修缓存信息。
布隆过滤器利用多次hash打算,也会存在hash冲突情形。
这几会导致一个问题,当检测过滤器是否存在数据时,检测到存在,实际不一定存在。
同时检测到不存在,则缓存中一定不存在。
总结

布隆过滤器节省内存,但是也存在一种偏差。
对付开篇提到的几个案例场景是一种非常不错的选择。

标签:

相关文章

交换机画布,绘制网络世界的蓝图

随着互联网技术的飞速发展,网络已经成为现代社会不可或缺的一部分。而交换机作为网络通信的核心设备,其作用不言而喻。本文将从交换机的定...

PHP教程 2025-01-02 阅读0 评论0

交响乐之美,聆听与品鉴的艺术之旅

交响乐,作为西方古典音乐的代表,以其独特的魅力和丰富的表现力,吸引了无数音乐爱好者的关注。对于初涉交响乐的听众而言,如何欣赏、品鉴...

PHP教程 2025-01-02 阅读0 评论0