03: redis高级
1.1 布隆过滤器
1、布隆过滤器是什么?(判断某个key一定不存在)
1. 本质上布隆过滤器是一种数据结构,比较巧妙的概率型数据结构
2. 特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”。
3. 相比于传统的 List、Set、Map 等数据结构,它更高效、占用空间更少,但是缺点是其返回的结果是概率性的,而不是确切的。
使用:
1. 布隆过滤器在NoSQL数据库领域中应用的非常广泛
2. 当用户来查询某一个row时,可以先通过内存中的布隆过滤器过滤掉大量不存在的row请求,然后去再磁盘进行查询
3. 布隆过滤器说某个值不存在时,那肯定就是不存在,可以显著降低数据库IO请求数量
2、应用场景
1)场景1(给用户推荐新闻)
1. 当用户看过的新闻,肯定会被过滤掉,对于没有看多的新闻,可能会过滤极少的一部分(误判)。
2. 这样可以完全保证推送给用户的新闻都是无重复的。
2)场景2(爬虫url去重)
1. 在爬虫系统中,我们需要对url去重,已经爬取的页面不再爬取
2. 当url高达几千万时,如果一个集合去装下这些URL地址非常浪费空间
3. 使用布隆过滤器可以大幅降低去重存储消耗,只不过也会使爬虫系统错过少量页面
3、布隆过滤器原理
1. 每个布隆过滤器对应到Redis的数据结构是一个大型的数组和几个不一样的无偏hash函数
2. 如下图:f、g、h就是这样的hash函数(无偏差指让hash映射到数组的位置比较随机)
添加:值到布隆过滤器
1)向布隆过滤器添加key,会使用 f、g、h hash函数对key算出一个整数索引,然后对长度取余
2)每个hash函数都会算出一个不同的位置,把算出的位置都设置成1就完成了布隆过滤器添加过程
查询:布隆过滤器值
1)当查询某个key时,先用hash函数算出一个整数索引,然后对长度取余
2)当你有一个不为1时肯定不存在这个key,当全部都为1时可能有这个key
3)这样内存中的布隆过滤器过滤掉大量不存在的row请求,然后去再磁盘进行查询,减少IO操作
删除:不支持
1)目前我们知道布隆过滤器可以支持 add 和 isExist 操作
2)如何解决这个问题,答案是计数删除,但是计数删除需要存储一个数值,而不是原先的 bit 位,会增大占用的内存大小。
3)增加一个值就是将对应索引槽上存储的值加一,删除则是减一,判断是否存在则是看值是否大于0。
1.2 redis事物
1、redis事物介绍
1. redis事物是可以一次执行多个命令,本质是一组命令的集合。
2. 一个事务中的所有命令都会序列化,按顺序串行化的执行而不会被其他命令插入
作用:一个队列中,一次性、顺序性、排他性的执行一系列命令
2、redis事物基本使用
1. 下面指令演示了一个完整的事物过程,所有指令在exec前不执行,而是缓存在服务器的一个事物队列中
2. 服务器一旦收到exec指令才开始执行事物队列,执行完毕后一次性返回所有结果
3. 因为redis是单线程的,所以不必担心自己在执行队列是被打断,可以保证这样的“原子性”
注:redis事物在遇到指令失败后,后面的指令会继续执行
mysql的rollback与redis的discard的区别:
1) mysql回滚为sql全部成功才执行,一条sql失败则全部失败,执行rollback后所有语句造成的影响消失
2) redis的discard只是结束本次事务,正确命令造成的影响仍然还在.
# Multi 命令用于标记一个事务块的开始事务块内的多条命令会按照先后顺序被放进一个队列当中,最后由 EXEC 命令原子性( atomic )地执行
> multi(开始一个redis事物)
incr books
incr books
> exec (执行事物)
> discard (丢弃事物)
[root@redis ~]# redis-cli
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set test 123
QUEUED
127.0.0.1:6379> exec
1) OK
127.0.0.1:6379> get test
""
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set test 456
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> get test
""
127.0.0.1:6379>
在命令行测试redis事物
#定义ip
host = 'localhost' #建立服务连接 r = redis.Redis(host=host)
pipe = r.pipeline() #开启事务
pipe.multi()
#存储子命令
pipe.set('key2', 4)
#执行事务
pipe.execute() print(r.get('key2'))
使用python测试redis事物
3、watch指令
实质:WATCH 只会在数据被其他客户端抢先修改了的情况下通知执行命令的这个客户端(通过 WatchError 异常)但不会阻止其他客户端对数据的修改
1. watch其实就是redis提供的一种乐观锁,可以解决并发修改问题
2. watch会在事物开始前盯住一个或多个关键变量,当服务器收到exec指令要顺序执行缓存中的事物队列时
3. redis会检查关键变量自watch后是否被修改(包括当前事物所在的客户端)
4. 如果关键变量被人改动过,exec指令就会返回null回复告知客户端事物执行失败,这个时候客户端会选择重试
注:redis禁用在multi和exec之间执行watch指令,必须在multi之前盯住关键变量,否则会出错
1.3 redis事物与分布式锁
1、redis事物
1. 严格意义来讲,Redis的事务和我们理解的传统数据库(如mysql)的事务是不一样的;
2. Redis的事务实质上是命令的集合,在一个事务中要么所有命令都被执行,要么所有命令都不执行。
需要注意的是:
1.Redis的事务没有关系数据库事务提供的回滚(rollback),所以开发者必须在事务执行失败后进行后续的处理;
2.如果在一个事务中的命令出现错误,那么所有的命令都不会执行;
3.如果在一个事务中出现运行错误,那么正确的命令会被执行。
2、redis原子操作
1. 原子操作是指不会被线程调度机制打断的操作
2. 这种操作一旦开始,就会一直运行到结束,中间不会切换任何进程
3、分布式锁
1. 分布式锁本质是占一个坑,当别的进程也要来占坑时发现已经被占,就会放弃或者稍后重试
2. 占坑一般使用 setnx(set if not exists)指令,只允许一个客户端占坑
3. 先来先占,用完了在调用del指令释放坑
> setnx lock:codehole true
.... do something critical ....
> del lock:codehole
4. 但是这样有一个问题,如果逻辑执行到中间出现异常,可能导致del指令没有被调用,这样就会陷入死锁,锁永远无法释放
5. 为了解决死锁问题,我们拿到锁时可以加上一个expire过期时间,这样即使出现异常,当到达过期时间也会自动释放锁
> setnx lock:codehole true
> expire lock:codehole 5
.... do something critical ....
> del lock:codehole
6. 这样又有一个问题,setnx和expire是两条指令而不是原子指令,如果两条指令之间进程挂掉依然会出现死锁
7. 为了治理上面乱象,在redis 2.8中加入了set指令的扩展参数,使setnx和expire指令可以一起执行
> set lock:codehole true ex 5 nx
''' do something '''
> del lock:codehole
1.4 redis五种数据结构
说明:
1. redis中所有数据结构都以唯一的key字符串作为名称,然后通过这个唯一的key来获取对应的value
2. 不同的数据类型数据结构差异就在于value的结构不一样
1、 字符串(string)
1)value的数据结构(数组)
1. 字符串value数据结构类似于数组,采用与分配容易空间来减少内存频繁分配
2. 当字符串长度小于1M时,扩容就是加倍现有空间
3. 如果字符串长度操作1M时,扩容时最多扩容1M空间,字符串最大长度为 512M
2)字符串的使用场景(缓存)
1. 字符串一个常见的用途是缓存用户信息,我们将用户信息使用JSON序列化成字符串
2. 取用户信息时会经过一次反序列化的过程
2、list(列表)
1)value的数据结构(双向链表)
1. 列表的数据结构是双向链表,这意味着插入和删除的时间复杂度是0(1),索引的时间复杂度位0(n)
2. 当列表弹出最后一个元素后,该数据结构会被自动删除,内存被回手
2)列表的使用场景(队列、栈)
3、hash(字典)
1)value的数据结构(HashMap)
1. redis中的字典也是HashMap(数组+列表)的二维结构
2. 不同的是redis的字典的值只能是字符串
2)hash的使用场景(缓存)
1. hash结构也可以用来缓存用户信息,与字符串一次性全部序列化整个对象不同,hash可以对每个字段进行单独存储
2. 这样可以部分获取用户信息,节约网络流量
3. hash也有缺点,hash结构的存储消耗要高于单个字符串
4、set(集合)
1)value的数据结构(字典)
1. redis中的集合相当于一个特殊的字典,字典的所有value都位null
2. 当集合中的最后一个元素被移除后,数据结构会被自动删除,内存被回收
2)set使用场景
1. set结构可以用来存储某个活动中中奖的用户ID,因为有去重功能,可以保证同一用户不会中间两次
5、zset(有序集合)
1)value的数据结构(跳跃列表)
1. zset一方面是一个set,保证了内部的唯一性
2. 另一方面它可以给每一个value赋予一个score,代表这个value的权重
3. zset内部实现用的是一种叫做“跳跃列表”的数据结构
4. zset最后一个元素被移除后,数据结构就会被自动删除,内存也会被回收
2)zset应用场景
1. 粉丝列表:value(粉丝ID),score(关注时间),这样可以轻松按关注事件排序
2. 学生成绩:value(学生ID),score(考试成绩),这样可以轻松对成绩排序
1.5 redis雪崩&穿透&击穿
1、缓存穿透
1)定义
1. 缓存穿透是指查询一个一定不存在的数据,由于缓存不命中,接着查询数据库也无法查询出结果,
2. 虽然也不会写入到缓存中,但是这将会导致每个查询都会去请求数据库,造成缓存穿透;
2)解决方法 :布隆过滤
1. 对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力;
2、缓存雪崩
1)定义
1. 缓存雪崩是指,由于缓存层承载着大量请求,有效的保护了存储层,但是如果缓存层由于某些原因整体不能提供服务
2. 于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会挂掉的情况。
2)解决方法
1. 保证缓存层服务高可用性:比如 Redis Sentinel 和 Redis Cluster 都实现了高可用
2. 依赖隔离组件为后端限流并降级:比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
3、缓存击穿
1)定义:
1. 缓存击穿,就是说某个 key 非常热点,访问非常频繁,处于集中式高并发访问的情况
2. 当这个 key 在失效的瞬间,大量的请求就击穿了缓存,直接请求数据库,就像是在一道屏障上凿开了一个洞。
2)解决方法
1. 解决方式也很简单,可以将热点数据设置为永远不过期;
2. 或者基于 redis or zookeeper 实现互斥锁,等待第一个请求构建完缓存之后,再释放锁,进而其它请求才能通过该 key 访问数据。
11111
03: redis高级的更多相关文章
- Redis高级
Redis高级 redis数据备份与恢复 Redis SAVE 命令用于创建当前数据库的备份. redis Save 命令基本语法如下: redis 127.0.0.1:6379> SAVE 实 ...
- 分布式缓存技术redis学习系列(四)——redis高级应用(集群搭建、集群分区原理、集群操作)
本文是redis学习系列的第四篇,前面我们学习了redis的数据结构和一些高级特性,点击下面链接可回看 <详细讲解redis数据结构(内存模型)以及常用命令> <redis高级应用( ...
- NoSQL之Redis高级实用命令详解--安全和主从复制
Android IOS JavaScript HTML5 CSS jQuery Python PHP NodeJS Java Spring MySQL MongoDB Redis NOSQL Vim ...
- 分布式缓存技术redis学习(四)——redis高级应用(集群搭建、集群分区原理、集群操作)
本文是redis学习系列的第四篇,前面我们学习了redis的数据结构和一些高级特性,点击下面链接可回看 <详细讲解redis数据结构(内存模型)以及常用命令> <redis高级应用( ...
- 3.Redis高级功能
3.Redis高级功能3.1 慢查询分析3.1.1 慢查询的两个配置参数3.1.2 最佳实践3.1.3 单线程架构3.2 Redis Shell3.2.1 redis-cli 详解3.2.2 redi ...
- 分布式缓存技术redis系列(四)——redis高级应用(集群搭建、集群分区原理、集群操作)
本文是redis学习系列的第四篇,前面我们学习了redis的数据结构和一些高级特性,点击下面链接可回看 <详细讲解redis数据结构(内存模型)以及常用命令> <redis高级应用( ...
- redis 高级特性 不要太好用
Redis高级特性及应用场景 redis中键的生存时间(expire) redis中可以使用expire命令设置一个键的生存时间,到时间后redis会自动删除它. 过期时间可以设置为秒或者毫秒精度. ...
- Redis学习第八课:Redis高级实用特性(二)
Redis高级实用特性 4.持久化机制 Redis是一个支持持久化的内存数据库,也就是说Redis需要经常将内存中的数据同步到硬盘来保证持久化.Redis支持两种持久化方式:(1).snapshott ...
- Redis学习第八课:Redis高级实用特性(一)
Redis高级实用特性 注:我学习的环境是vmware7.1 + ubantu10.10+ redis 3.0.2 1.安全性 设置客户端连接后进行任何其他指定前需要的密码.因为redis速度相当快, ...
随机推荐
- Qt 5 常用类及基本函数
//主要使用类#include <Qstring> #include <QMenu> #include <QMenuBar> #include <QToolB ...
- TTTTTTTTTTTT CF 653D 送邮递员
链接:给一张n个点m条带权边的有向图,有x个人从起点出发到终点,每个人带的都带相同重量的货物, 规定一条边最多能经过其上权的重量的货物,问最多能带多重的货物? 2 ≤ n ≤ 50, 1 ≤ m ≤ ...
- [LibreOJ 3119]【CTS2019】随机立方体【计数】【容斥】
Description Solution 记\(N=min(n,m,l)\) 首先考虑容斥,记\(f(i)\)为至少有i个位置是极大的,显然极大的位置数上界是N. 那么显然\(Ans=\sum\lim ...
- [NLP] The Annotated Transformer 代码修正
1. RuntimeError: "exp" not implemented for 'torch.LongTensor' class PositionalEncoding(nn. ...
- phoenix-hbase 使用
建表命令 CREATE TABLE IF NOT EXISTS "person_mul"( "ROW" varchar primary key, //主键,必须 ...
- C#程序模拟登录批量获取各种邮件内容信息
一般来说,如果现实中你有这样一种需求“假如你是褥羊毛的羊毛党,你某日发现了一个app有一个活动,通过邮箱注册账号激活可以领5元红包,而恰恰你手上又有一批邮箱可用,那么批量获取邮箱中的激活链接去激活则是 ...
- 添加一个静态JAVA库
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # Build all java files in the java subdirectory L ...
- 四叉树的js实现
基于 https://gamedevelopment.tutsplus.com/tutorials/quick-tip-use-quadtrees-to-detect-likely-collision ...
- Java内存泄漏分析和预防
1. 什么是内存泄漏?有什么危害 书面说法: 内存泄漏:对象已经没有被应用程序使用,但是垃圾回收器没办法移除它们,因为还在被引用着. 在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个 ...
- csp2019 Emiya家今天的饭题解
qwq 由于窝太菜了,实在是不会,所以在题解的帮助下过掉了这道题. 写此博客来整理一下思路 正文 传送 简化一下题意:现在有\(n\)行\(m\)列数,选\(k\)个数的合法方案需满足: 1.一行最多 ...