架构师_程序员_码农网

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2192|回复: 3

[资料] .NET/C# 使用 Redis 基于 BitMap 实现布隆算法

[复制链接]
发表于 2023-1-2 17:37:01 | 显示全部楼层 |阅读模式
需求:最近在 B 站看到一个 Redis 布隆算法的视频,解决缓存穿透的问题,简单来说就是在访问数据库前在加一层逻辑判断,判断数据是否存在,存在的话再去访问数据库。例如:某网站是一个新闻系统,文章的 URL 都是通过自增主键 Id 生成的(网址格式示例:/news-1.html),网站可能只有几万篇文章并且有缓存,如果攻击者通过这个规则恶意构造几百万的 Id 去访问,那么这些肯定无法命中缓存,从而直接访问数据库,从而对数据库造成压力。

原来:

请求新闻资源 -> 判断缓存是否存在 -> 存在 -> 缓存返回数据。
请求新闻资源 -> 判断缓存是否存在 -> 不存在 -> 从数据库查询 -> 存在 -> 缓存并返回数据。
请求新闻资源 -> 判断缓存是否存在 -> 不存在 -> 从数据库查询 -> 不存在 -> 返回 404 错误。

现在:

请求新闻资源 -> 布隆算法 -> 存在 -> 走原来的逻辑。
请求新闻资源 -> 布隆算法 -> 不存在 -> 直接返回 404错误。

布隆算法(BloomFilter)

BloomFilter算法,是一种大数据排重算法。在一个数据量很大的集合里,能准确断定一个对象不在集合里;判断一个对象有可能在集合里,而且占用的空间不大。它不适合那种要求准确率很高的情况,零错误的场景。通过牺牲部分准确率达到高效利用空间的目的。

布隆算法是一个以牺牲一定的准确率来换取低内存消耗的过滤算法,可以实现大量数据的过滤、去重等操作。

布隆算法只是一个抽象的概念,实现方式有很多种,文章中利用 Redis 中 BitMap 只是简单的实现。

参考:https://www.cnblogs.com/liyulong1982/p/6013002.html

BitMap 介绍

BitMap就是位图,其实也就是字节数组(byte array),用二进制表示,只有 0 和 1 两个数字,位图就是用每一个二进制位来存放或者标记某个元素对应的值。通常是用来判断某个数据存不存在的,因为是用bit为单位来存储所以Bitmap本身会极大的节省储存空间。

如下图字符串在计算机里是由二进制的形式保存的。

QQ截图20230102163903.jpg

Redis 中 BitMap 数据类型

Redis提供的数据类型BitMap(位图),每个bit位对应0和1两个状态。虽然内部还是采用String类型存储,但Redis提供了一些指令用于直接操作BitMap,可以把它看作一个bit数组,数组的下标就是偏移量。

它的优点是内存开销小,效率高且操作简单。

节省空间:通过一个bit位来表示某个元素对应的值或者状态,其中key就是对应元素的值。实际上8个bit可以组成一个Byte,所以是及其节省空间的。
效率高:setbit和getbit的时间复杂度都是O(1),其他位运算效率也高。

使用set集合和BitMap存储的对比如下:

数据类型每个 userid 占用空间需要存储的用户量全部占用内存量
set(集合)32位也就是4个字节(假设userid用的是整型,实际很多网站用的是长整型)50,000,00032位 * 50,000,000 = 200 MB
BitMap1 位(bit)100,000,0001 位 * 100,000,000 = 12.5 MB


时间在拉长一点

一天一个月一年
set(集合)200M6G72G
BitMap12.5M375M4.5G


计算后发现随着时间的增加,要记录数据量的增加,对比更加明显了,BitMap所占的空间比set(集合)更少。

Redis提供了以下几个指令用于操作BitMap:

命令说明可用版本时间复杂度
SETBIT对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。>= 2.2.0O(1)
GETBIT对 key 所储存的字符串值,获取指定偏移量上的位(bit)。>= 2.2.0O(1)
BITCOUNT计算给定字符串中,被设置为 1 的比特位的数量。>= 2.6.0O(N)
BITPOS返回位图中第一个值为 bit 的二进制位的位置。>= 2.8.7O(N)
BITOP对一个或多个保存二进制位的字符串 key 进行位元操作。>= 2.6.0O(N)
BITFIELDBITFIELD 命令可以在一次调用中同时对多个位范围进行操作。>= 3.2.0O(1)


命令文档:https://redis.io/commands/

既然简单了解了算法和 Redis 的 Bitmap 特性和语法,使用 redis 简单操作一下。

SETBIT 语法:SETBIT key offset value

设置文章 Id:9、10、156 为 1,命令如下:

GETBIT 语法:GETBIT key offset

判断 Id:10、11 是否存在,命令如下:


QQ截图20230102172639.jpg

.NET/C# 操作 Redis 的 BitMap 类型

我们了解到了 redis 中的几个 BitMap 命令,如何以编程的方式操作呢?新建 .NET 3.1 的控制台项目,引用 StackExchange.Redis 包,命令如下:

源码如下:

QQ截图20230102173529.jpg

Redis的 bitmap 应用场景还有很多,如下:

  • 可以作为简单的布隆过滤器来判断用户是否执行过某些操作。
  • 用户日活,月活,留存率的统计
  • 实现用户上线次数的统计
  • 用户在线状态和人数统计

(完)




上一篇:【译】虚拟演员:Dapr vs Orleans
下一篇:阿里云 SLB 负载均衡 503 错误解决方案
码农网,只发表在实践过程中,遇到的技术难题,不误导他人。
 楼主| 发表于 2023-1-2 17:41:56 | 显示全部楼层
码农网,只发表在实践过程中,遇到的技术难题,不误导他人。
发表于 2023-1-2 20:42:47 | 显示全部楼层
学习了,感谢感谢,长见识了
码农网,只发表在实践过程中,遇到的技术难题,不误导他人。
发表于 2023-1-6 20:34:22 | 显示全部楼层
学习学习
码农网,只发表在实践过程中,遇到的技术难题,不误导他人。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

免责声明:
码农网所发布的一切软件、编程资料或者文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。

Mail To:help@itsvse.com

QQ|手机版|小黑屋|架构师 ( 鲁ICP备14021824号-2 )|网站地图

GMT+8, 2024-4-26 07:30

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表