前言
缓存穿透:某个数据redis不存,mysql也不存在,而且一直尝试读,数据最终压力依然堆积在mysql,可能造成mysql不堪重负而崩溃
读取步骤:
1.先访问redis,如果存在,直接返回,不存在走2
2.访问mysql,如果不存在,直接返回,如存在走3
3.将mysql存在的key写回redis
一、STL::SET和STL::MAP?
- C++标准库(STL)中的set和map结构都是采用红黑树实现,它增删改查的时间是O(logN)
- 优点:存储效率高,访问速度高效
- 解决缓存穿透不是使用理由:字符串太长,比较效率也比较低
二、STL::unordered_map?
- C++标准库(STL)中采用hashtable实现,增删改查的效率是O(1)
- 构成:数组+hash函数
- hash函数的作用:避免插入的时候字符串的比较,函数计算出来的值通过对数组长度的取模能随机分布在数组当中
- 选取hash函数:1选取计算速度快 2哈希相似字符串能保持强随机分布性(murmurhash1,murmurhash2,murmurhash3,siphash)
- 负载因子:数组存储元素的个数/数组长度;负载因子越小,冲突越小;负载因子越大,冲突越大
- hash冲突解决方案:
- 链表法:冲突的链表过长,可以将这个链表转换为红黑树
- 开放寻址法:将所有的元素放在哈希表的数组中,不使用额外的数据结构;一般使用线性探查的思路解决。
- 线性探查
- 插入新元素时,使用哈希函数定位位置
- 检查是否已经存在,不存在,插入,否则3
- 在2检测的是槽位索引上加一定步长接着,检查2
- 加步长分为几种:
- 1.i+1,i+2, i+3, i+4…i+n
- 2.i-1^2, i+2^2
- 这两种会导致同类hash聚集
- 使用双重哈希 hash1+k*hash2
- 优点:访问速度更快,不需要进行字符串比较
- 缺点:需要引入策略避免冲突,存储效率不高,空间换时间
三、布隆过滤器
- 定义:概率型数据结构,他的特点是高效的插入和查询,能明确告知某个字符串一定不存在或者可能存在
- 缺点:概率性返回,结果存在误差,不支持删除操作
- 原理:元素加入位图时,通过k个hash函数将这个元素映射到位图的k个点,并把它们置为1;当检索时,再通过k个hash函数运算检测位图的k个点是否都为1;如果有不为1的点,那么认为不存在;如果全部为1,则可能存在(存在误差)
n -- 布隆过滤器中元素的个数,如上图 只有str1和str2 两个元素 那么 n=2
p -- 假阳率,在0-1之间 0.000000
m -- 位图所占空间 k -- hash函数的个数
公式如下:
n = ceil(m / (-k / log(1 - exp(log(p) / k)))) ;
p = pow(1 - exp(-k / (m / n)), k);
m = ceil((n * log(p)) / log(1 / pow(2, log(2))));
k = round((m / n) * log(2));
选值网站:https://hur.st/bloomfilter/
四、解决
1.发现MySQL不存在,将redis设置为<key,nil>设置过期时间 下次访问key的时候 不再访问mysql 容易造成redis缓存很多无效数据
2.布隆过滤器,将mysql当中已经存在的key,写入布隆过滤器,不存在的直接pass掉