锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

redis所有知识点的详细笔记

时间:2023-08-04 17:07:00 sub4p插头连接器

# redis笔记

## 一、什么是NoSQL

### 1、NoSQL概述

- NoSQL(NoSQL = Not Only SQL),不仅仅是意SQL是一种全新的数据库概念,一般指非关系数据库。
- 随着互联网web2.随着0网站的兴起,传统的关系数据库正在应对web2.0网站,特别是超大规模和高并发网站SNS类型的web2.0纯动态网站似乎无能为力,暴露了许多难以克服的问题,而非关系数据库由于其自身的特点发展迅速。NoSQL数据库的产生是为了解决大规模数据型的挑战,特别是大数据应用问题。

### 2、NOSQL比较关系数据库

- 优点:
1)成本:nosql数据库简单易部署,基本都是开源软件,不需要像使用一样使用oracle与关系数据库相比,购买和使用的成本很高。
2)查询速度:nosql数据库将数据存储在缓存中,关系数据库将数据存储在硬盘中,自然查询速度远低于nosql数据库。
3)存储数据的格式:nosql存储格式是key,value形式、文档形式、图片形式等,因此,基础类型、对象或集合格式可以存储,而数据库只支持基础类型。
4)可扩展性:关系数据库相似join这种多表查询机制的限制使得扩展非常困难。

- 缺点:
由于维护工具和数据有限,1)nosql是属于新的技术,不能和关系型数据库10几年的技术同日而语。
2)不提供对sql如果不支持,支持sql这样的工业标准会产生一定的用户学习和使用成本。
3)事务处理不提供关系数据库。

### 非关系数据库的优点:

- 性能NOSQL它是基于键值对的,可以想象表中主键与值的对应关系,不需要通过SQL层分析,所以性能很高。
- 可扩展性也是容易水平扩展,因为基于键值对,数据之间没有耦合。

### 4.关系数据库的优势:

- 可以使用复杂的查询SQL在一个表和多个表之间进行非常复杂的数据查询很方便。
- 事务支持使安全性能高的数据访问要求得以实现。对于这两种数据库,对方的优势是自身的弱点,反之亦然。

### 5、总结

关系数据库和NoSQL数据库不是对立的,而是互补的,即通常使用适合使用的关系数据库NoSQL的时候使用NoSQL数据库,让NoSQL数据库弥补了关系数据库的不足。数据通常存储在关系数据库中nosql数据库中备份存储关系数据库的数据

### 6、主流的NOSQL产品

? 键值(Key-Value)存储数据库
相关产品: Tokyo Cabinet/Tyrant、Redis、Voldemort、Berkeley DB
典型应用: 内容缓存主要用于处理大量数据的高访问负载。
数据模型: 一系列键值对
优势: 快速查询
劣势: 存储的数据缺乏结构化
? 存储数据库
相关产品:Cassandra, HBase, Riak
典型应用:分布式文件系统
数据模型:以列簇式存储同一列数据
优点:搜索速度快,可扩展性强,分布式扩展更容易
缺点:功能相对有限
? 文档数据库
相关产品:CouchDB、MongoDB
典型应用:Web应用(与Key-Value类似,Value结构化)
数据模型: 一系列键值对
优点:数据结构要求不严格
劣势: 查询性能不高,缺乏统一的查询语法
? 图形(Graph)数据库
相关数据库:Neo4J、InfoGrid、Infinite Graph
典型应用:社交网络
数据模型:图结构
优点:使用图结构相关算法。
缺点:需要计算整个图纸才能得到结果,不容易做分布式集群方案。

## 二、什么是Redis

### 1、redis概述

Redis(Remote Dictionary Server ),即远程字典服务,使用开源ANSI [C语言](https://baike.baidu.com/item/C语言)编写、支持网络、基于内存或可持续的日志,Key-Value[数据库](https://baike.baidu.com/item/数据库/103728),并提供多种语言的API。并发执行发执行1万个请求,阅读速度为1.1万次/s,写作速度为81000次/s ,且Redis为不同场景下的存储需求提供多种键值数据类型。

### 2、Redis支持的键值数据类型如下:

- 字符串类型 string
- 哈希类型 hash
- 列表类型 list
- 集合类型 set
- 有序集合类型 sortedset

### 3、redis的应用场景

- 缓存(数据查询、短连接、新闻内容、商品内容等)
- 聊天室在线朋友列表
- 任务队列。
- 应用排行榜
- 网站访问统计
- 数据过期处理(可精确到毫秒)
- 在分布式集群架构中session分离

### 4、redis基础知识

#### 1、redis数据库切换

> redis 内置16个数据库
>
> 切换:select (0~15)

#### 2、redis数据库清除

- flushdb 清楚这个数据库的所有数据
- flushAll 清楚所有数据库数据

#### 3.自带测试工具(redis-benchmark)

测试语句

gt; redis-benchmark -h localhost -p 6379 -c 100 -n 100000

![image-20201005203936276](D:\NULL\学习资源\md笔记\images\redis\image-20201005203936276.png)

#### 4、redis是单线程

- Redis是很快的,官方表示,Redis是基于内存操作,CPU不是Redis性能瓶颈,Redis的瓶颈是根据机器的内存和网络带
  宽,既然可以使用单线程来实现,就使用单线程了!所有就使用了单线程了!

- Redis 是C语言写的,官方提供的数据为100000+的QPS,完全不比同样是使用key-vale的Memecache差!
  Redis为什么单线程还这么快?
- 误区一:高性能服务器一定是多线程!
  误区二:多线程(CPU上下文会切换!)一定比单线程效率高!
  先去CPU>内存>硬盘的速度要有所了解!
- 核心:redis是将所有的数据全部放在内存中的,所以说使用单线程去操作效率就是最高的,多线程(CPU上下文会切换:耗
  没有操作!!!),对于内存系统来说,如果没有上下文切换效率就是最高的!多次读写都是在一个CPU上的,在内存情况这个就是最佳的方案!

## 三、redis五大数据类型常用操作

> - redis存储的是:key,value格式的数据,其中key都是字符串,value有5种不同的数据结构
> - value的数据结构:
>       1) 字符串类型 string
>         2) 哈希类型 hash : map格式  
>         3) 列表类型 list : linkedlist格式。支持重复元素
>         4) 集合类型 set  : 不允许重复元素
>         5) 有序集合类型 sortedset:不允许重复元素,且元素有顺序

### 1、String常用命令

> 1. 计数器
>
>   string类型的incr和decr命令的作用是将key中储存的数字值加一/减一,这两个操作具有原子性,总能安全地进行加减操作,因此可以用string类型进行计数,如微博的评论数、点赞数、分享数,抖音作品的收藏数,京东商品的销售量、评价数等。
>
>   2. 分布式
>
>   string类型的setnx的作用是“当key不存在时,设值并返回1,当key已经存在时,不设值并返回0”,“判断key是否存在”和“设值”两个操作是原子性地执行的,因此可以用string类型作为分布式锁,返回1表示获得锁,返回0表示没有获得锁。例如,为了保证定时任务的高可用,往往会同时部署多个具备相同定时任务的服务,但是业务上只希望其中的某一台服务执行定时任务,当定时任务的时间点触发时,多个服务同时竞争一个分布式锁,获取到锁的执行定时任务,没获取到的放弃执行定时任务。定时任务执行完时通过del命令删除key即释放锁,如果担心del命令操作失败而导致锁一直未释放,可以通过expire命令给锁设置一个合理的自动过期时间,确保即使del命令失败,锁也能被释放。不过expire命令同样存在失败的可能性,如果你用的是Java语言,建议使用JedisCommands接口提供的String set(String key, String value, String nxxx, String expx, long time)方法,这个方法可以将setnx和expire原子性地执行,具体使用方式如下(相信其它语言的Redis客户端也应当提供了类似的方法)。
>
> `jedisCommands.set("IAmAKey", "1", "NX", "EX", 60);//如果"IAmAKey"不存在,则将其设值为1,同时设置60秒的自动过期时间`
>
> 3. 存储对象
>
>   利用JSON强大的兼容性、可读性和易用性,将对象转换为JSON字符串,再存储在string类型中,是个不错的选择,如用户信 息、商品信息等。
>

>   string类型的常用命令可参考http://www.runoob.com/redis/redis-strings.html。
>
>   加入string类型的应用场景后的思维导图如下。


![ ](D:\NULL\学习资源\md笔记\images\redis\967517-20190405015017041-746069400.png)

```bash
select 3 #切换至3号数据库
dbsize #查看当前数据库的 数据量  一般为 k-v 的对数
keys * #查看当前库中的所有 key
flushdb #清空当前数据库
flushall #清空所有数据库
set name zz #存入一个 name-zz的 k-v数据
get name    #将返回这个key对应的值 zz
exits name  #判断当前key是否存在  存在返回1否则返回0
move name 1 #移动 这个k-v 到指定数据库
expire name 10 #设置这个k-v的过期时间为10秒
ttl name #查看这个k-v剩余的有效期时间
type name #查看当前key的类型
append name "hh" #将name对应的value值拼接  再次get name时会返回  zzhh   如果key不存在则等价于set
strlen name #查看这个key对应的value值的长度
set views 0
incr views #自增1 下次get views将返回1
decr views #自减1 下次get views将又返回0
incrby views 5 #自增5 下次get views将返回5
decrby views 5 #自减5 下次get views将返回0
getrange name 1 2 #返回name对应value的一部分 从下标1开始到下标2结束  即zh
getrange name 0 -1 #返回name对应value的一部分 从下标0开始到末尾  即zzhh
setrange name 1 ab #将name下标1开始的位置 替换为ab  返回  zabh
setex name1 10 "aaa" #如果name1不存在则创建k-v并指定过期时间10秒,具有原子性。 如果存在则覆盖value指定过期时间10秒
setnx name2 bbb #如果不存在这个key则创建成功返回1,如果存在 则创建失败返回0
mset k1 v1 k2 v2 k3 v3 #批量设置这3个k-v对
mget k1 k2 k3 #批量返回相应k值的相应value值
msetnx k1 v1 k4 v4 #批量不存在时设置,具有原子性,如此时k1存在k4不存在,但会全部失败返回0
set user:1 {name:zhangsan,age:10} #保存对象
mset user:1:name zhangsan user:1:ange 10 #也可有上述效果
getset name ccc #先get再set 不存在时 返回nil,但set仍然会生效!等价与创建了一个新的k-v。存在时返回之前的value值且覆盖掉这个value,下次get会返回刚设置的新值
```

### 2、list常用命令

> list类型是简单的字符串列表,按照插入顺序排序。每个列表最多可以存储 232 - 1 个元素(40多亿) ,list类型主要有以下应用场景。。
>
>   1. 消息队列
>
>   list类型的lpop和rpush(或者反过来,lpush和rpop)能实现队列的功能,故而可以用Redis的list类型实现简单的点对点的消息队列。不过我不推荐在实战中这么使用,因为现在已经有Kafka、NSQ、RabbitMQ等成熟的消息队列了,它们的功能已经很完善了,除非是为了更深入地理解消息队列,不然我觉得没必要去重复造轮子。
>
>   2. 排行榜
>
>   list类型的lrange命令可以分页查看队列中的数据。可将每隔一段时间计算一次的排行榜存储在list类型中,如京东每日的手机销量排行、学校每次月考学生的成绩排名、斗鱼年终盛典主播排名等,下图是酷狗音乐“K歌擂台赛”的昨日打擂金曲排行榜,每日计算一次,存储在list类型中,接口访问时,通过page和size分页获取打擂金曲。但是,并不是所有的排行榜都能用list类型实现,只有定时计算的排行榜才适合使用list类型存储,与定时计算的排行榜相对应的是实时计算的排行榜,list类型不能支持实时计算的排行榜,之后在介绍有序集合sorted set的应用场景时会详细介绍实时计算的排行榜的实现。
>
> 3. 最新列表
>
>   list类型的lpush命令和lrange命令能实现最新列表的功能,每次通过lpush命令往列表里插入新的元素,然后通过lrange命令读取最新的元素列表,如朋友圈的点赞列表、评论列表。
>
>   但是,并不是所有的最新列表都能用list类型实现,因为对于频繁更新的列表,list类型的分页可能导致列表元素重复或漏掉,举个例子,当前列表里由表头到表尾依次有(E,D,C,B,A)五个元素,每页获取3个元素,用户第一次获取到(E,D,C)三个元素,然后表头新增了一个元素F,列表变成了(F,E,D,C,B,A),此时用户取第二页拿到(C,B,A),元素C重复了。只有不需要分页(比如每次都只取列表的前5个元素)或者更新频率低(比如每天凌晨更新一次)的列表才适合用list类型实现。对于需要分页并且会频繁更新的列表,需用使用有序集合sorted set类型实现。另外,需要通过时间范围查找的最新列表,list类型也实现不了,也需要通过有序集合sorted set类型实现,如以成交时间范围作为条件来查询的订单列表。之后在介绍有序集合sorted set类型的应用场景时会详细介绍sorted set类型如何实现最新列表。![ ](C:\Users\26321\Desktop\967517-20190415095729512-729127615.png)

```bash
#list的操作
lpush list one #往list顶端插入值
lrange list 0 -1 #返回list中所有值
rpush list four #往list底部插入值
lpop list #移除list顶端元素,并返回该元素
rpop list #移除list底部元素,并返回该元素
lindex list 0 #获取list中指定下标为0的值,同上理解就是顶端
llen list #返回list的长度
lrem list 1 value #移除list中指定个数的value值
ltrim list 1 2 #截断list,保留指定下标中的值
rpoplpush list1 haha2 #从list1底部移除一个元素并返回,且将该元素插入list2的顶端
exists list #判断list是否存在  存在返回1否则返回0
lset list 0 haha #修改列表指定位置的值, 需要列表和该位置元素已存在,否则报错
linsert list before hello new #往指定列表的指定元素的前面插入指定值
linsert list after hello new1 #往指定列表的指定元素的后面插入指定值
```

### 3、set集合

>1. 好友/关注/粉丝/感兴趣的人集合
>
>  set类型唯一的特点使得其适合用于存储好友/关注/粉丝/感兴趣的人集合,集合中的元素数量可能很多,每次全部取出来成本不小,set类型提供了一些很实用的命令用于直接操作这些集合,如
>
>    a. sinter命令可以获得A和B两个用户的共同好友
>
>     b. sismember命令可以判断A是否是B的好友
>
>     c. scard命令可以获取好友数量
>
>     c. 关注时,smove命令可以将B从A的粉丝集合转移到A的好友集合
>
>  需要注意的是,如果你用的是Redis Cluster集群,对于sinter、smove这种操作多个key的命令,要求这两个key必须存储在同一个slot(槽位)中,否则会报出 (error) CROSSSLOT Keys in request don't hash to the same slot 错误。Redis Cluster一共有16384个slot,每个key都是通过哈希算法CRC16(key)获取数值哈希,再模16384来定位slot的。要使得两个key处于同一slot,除了两个key一模一样,还有没有别的方法呢?答案是肯定的,Redis提供了一种**Hash Tag**的功能,在key中使用{}括起key中的一部分,在进行 CRC16(key) mod 16384 的过程中,只会对{}内的字符串计算,例如friend_set:{123456}和fans_set:{123456},分别表示用户123456的好友集合和粉丝集合,在定位slot时,只对{}内的123456进行计算,所以这两个集合肯定是在同一个slot内的,当用户123456关注某个粉丝时,就可以通过smove命令将这个粉丝从用户123456的粉丝集合移动到好友集合。相比于通过srem命令先将这个粉丝从粉丝集合中删除,再通过sadd命令将这个粉丝加到好友集合,smove命令的优势是它是原子性的,不会出现这个粉丝从粉丝集合中被删除,却没有加到好友集合的情况。然而,对于通过sinter获取共同好友而言,Hash Tag则无能为力,例如,要用sinter去获取用户123456和456789两个用户的共同好友,除非我们将key定义为{friend_set}:123456和{friend_set}:456789,否则不能保证两个key会处于同一个slot,但是如果真这样做的话,所有用户的好友集合都会堆积在同一个slot中,数据分布会严重不均匀,不可取,所以,**在实战中使用Redis Cluster时,sinter这个命令其实是不适合作用于两个不同用户对应的集合的**(同理其它操作多个key的命令)。
>
>2. 随机展示
>
>  通常,app首页的展示区域有限,但是又不能总是展示固定的内容,一种做法是先确定一批需要展示的内容,再从中随机获取。如下图所示,酷狗音乐K歌擂台赛当日的打擂歌曲共29首,首页随机展示5首;昨日打擂金曲共200首,首页随机展示30首。
>
>set类型适合存放所有需要展示的内容,而srandmember命令则可以从中随机获取几个。
>
>3. 黑名单/白名单
>
>  经常有业务出于安全性方面的考虑,需要设置用户黑名单、ip黑名单、设备黑名单等,set类型适合存储这些黑名单数据,sismember命令可用于判断用户、ip、设备是否处于黑名单之中。

![967517-20190417162215588-320188667](D:\NULL\学习资源\md笔记\images\redis\967517-20190417162215588-320188667.png)

```bash
# set操作(无序不重复集合)
sadd myset zhangsan lisi  SMEMBERS myset # set集合中添加值
SMEMBERS myset # 查看set集合的所有值
SISMEMBER myset lisi # 判断set集合中是否有这个值
scard myset # 获取set集合中的元素个数
srem myset lisi # 删除set集合指定的元素
SRANDMEMBER myset  # 随机抽取出一个元素
SRANDMEMBER myset 2 # 随机抽选出2个元素
spop myset # 随机删除set集合的元素
spop myset 2 # 随机删除set集合的2ge元素
SDIFF myset myset2 # 两个set集合的差集
SINTER myset myset2 # 两个set集合的交集
SUNION myset myset2 # 两个set集合的并集
```

### 4、Hash(哈希)

Map集合, key-map!时候这个值是一个map集合 !本质和string没有太大区别,还是一个简单的key-value!

>  hash类型是一个string类型的field和value的映射
>
> 表,每个 hash 可以存储 232 - 1 键值对(40多亿),hash类型主要有以下应用场景。
>
> 1. 购物车
>
>   以用户id为key,商品id为field,商品数量为value,恰好构成了购物车的3个要素。
>
> 2. 存储对象
>
>   hash类型的(key, field, value)的结构与对象的(对象id, 属性, 值)的结构相似,也可以用来存储对象。
>
>   在介绍string类型的应用场景时有所介绍,string + json也是存储对象的一种方式,那么存储对象时,到底用string + json还是用hash呢?
>
>   两种存储方式的对比如下表所示。
>
> |        | string + json | hash     |
> | ------ | ------------- | -------- |
> | 效率   | 很高          | 高       |
> | 容量   | 低            | 低       |
> | 灵活性 | **低**        | 高       |
> | 序列化 | 简单          | **复杂** |
>
>   当对象的某个属性需要频繁修改时,不适合用string+json,因为它不够灵活,每次修改都需要重新将整个对象序列化并赋值,如果使用hash类型,则可以针对某个属性单独修改,没有序列化,也不需要修改整个对象。比如,商品的价格、销量、关注数、评价数等可能经常发生变化的属性,就适合存储在hash类型里。
>
>   当然,不常变化的属性存储在hash类型里也没有问题,比如商品名称、商品描述、上市日期等。但是,当对象的某个属性不是基本类型或字符串时,使用hash类型就必须手动进行复杂序列化,比如,商品的标签是一个标签对象的列表,商品可领取的优惠券是一个优惠券对象的列表(如下图所示)等,即使以coupons(优惠券)作为field,value想存储优惠券对象列表也还是要使用json来序列化,这样的话序列化工作就太繁琐了,不如直接用string + json的方式存储商品信息来的简单。

![967517-20190405020705399-1272027899](D:\NULL\学习资源\md笔记\images\redis\967517-20190405020705399-1272027899.png)

```bash
# hash操作
#hash变更的数据user name age,尤其是是用户信息之类的,经常变动的信息! hash更适合于对象的存储, String更加适合字符串存储!
hset myhash k1 v1 # 设置一个key-value
hmget k1 k2 # 根据多个key获取value
hmset myhash l1 v2 l3 v4 # 设置多个key-value
hgetall myhash # 查询hash表的所有值
hdel myhash k1 # 删除指定的field
hlen myhash # 获取hash表的field数量
HEXISTS myhash k2 # 判断hash表中是否存在这个field
hkeys myhash # 只获得hash表中的所有field
HVALS myhash # 只获得hash表中的所有value
HINCRBY myhash k1 1 #自增1 
hsetnx myhash k1 v1 # 如果不存在这个key则创建成功返回1,如果存在 则创建失败返回0
```

### 5、Zset(有序集合)

- 销量排名、积分排名、成绩排名等...
  - 发表时间作为score存储,这样子获取的时候就是自动排好序的\
  - 成绩作为score
  - 带权重队列,让重要的任务优先执行

>1. 延时队列
>
>zset 会按 score 进行排序,如果 score 代表想要执行时间的时间戳。在某个时间将它插入zset集合中,它变会按照时间戳大小进行排序,也就是对执行时间前后进行排序。
>
>起一个死循环线程不断地进行取第一个key值,如果当前时间戳大于等于该key值的score就将它取出来进行消费删除,可以达到延时执行的目的。
>
>2. 排行榜
>
>经常浏览技术社区的话,应该对 “1小时最热门” 这类榜单不陌生。如何实现呢?如果记录在数据库中,不太容易对实时统计数据做区分。我们以当前小时的时间戳作为 zset 的 key,把贴子ID作为 member ,点击数评论数等作为 score,当 score 发生变化时更新 score。利用 ZREVRANGE 或者 ZRANGE 查到对应数量的记录。
>
>3. 限流
>
>滑动窗口是限流常见的一种策略。如果我们把一个用户的 ID 作为 key 来定义一个 zset ,member 或者 score 都为访问时的时间戳。我们只需统计某个 key 下在指定时间戳区间内的个数,就能得到这个用户滑动窗口内访问频次,与最大通过次数比较,来决定是否允许通过。

```bash
# Zset操作
zadd sarly 5000 wangwu # 添加操作
ZRANGE sarly 0 -1 # 输出zset的所有值
ZRANGEBYSCORE sarly -inf +inf  # 升序输出全部的用户
ZRANGEBYSCORE sarly -inf +inf withscores # 序输出全部的用户,且显示工资
ZRANGEBYSCORE sarly -inf +inf 2500 withscores # 序输出全部的用户,且显示大于2500的工资
ZREVRANGEBYSCORE sarly +inf -inf # 降序排序
zrem sarly lisi # 删除用户
zcard  sarly # 获取有序集合的元素个数
ZREVRANGE sarly 0 -1 # 反转
zcount sarly 500 2500 # 获取指定区间的元素的数
```

## 四、三大特殊数据类型常用操作

### 1、geospatial(地理位置)

> geospatial常用命令

- GEOADD

  ```bash
  # getadd 添加地理位置
  #规则:两级无法直接添加,我们一般会下载城市数据,直接通过java程序一 次性导入!
  #有效的经度从-180度到180度。
  #有效的纬度从-85. 05112878度到85.05112878度。
  #当坐标位置超出上述指定范围时,该命令将会返回一个错误。 
  GEOADD china:cipty  31.405 121.4894 shanghai # 添加地理位置
  
  ```

- GEODIST

  ```bash
   geodist china:cipty beijing shanghai km # 获取两个地理之间的距离,单位是km
  ```

- GEOHASH

  ```bash
  geohash china:cipty beijing shanghai # 将二维的经纬度转换为-维的字符串,如果两个字符串越接近,那么则距离越近!
  ```

- GEOPOS

  ```bash
  geopos china:cipty beijing  #获取指定的城市的经度和纬度!
  ```

- GEORADIUS

  ```bash
   GEORADIUS china:cipty 110 30 1000 km  # georadius以给定的经纬度为中心,找出某一半径内的元素
  ```

- GEORADIUSBYMEMBER

  ```bash
  GEORADIUSBYMEMBER china:cipty beijing 10000 km # 找出位于指定元素周围的其他元素!
  ```

总结

> GEO底层的实现原理其实就是Zset !我们可以使用Zset命令来操作geo !
>
> - 删除
> - 查询
> - ...等操作

### 2、Hyperloglog(基数统计)

> ### 应用场景
>
> 说明:
>
> - 基数不大,数据量不大就用不上,会有点大材小用浪费空间
> - 有局限性,就是只能统计基数数量,而没办法去知道具体的内容是什么
> - 和bitmap相比,属于两种特定统计情况,简单来说,HyperLogLog 去重比 bitmap 方便很多
> - 一般可以bitmap和hyperloglog配合使用,bitmap标识哪些用户活跃,hyperloglog计数
>
> 一般使用:
>
> - 统计注册 IP 数
> - 统计每日访问 IP 数
> - 统计页面实时 UV 数
> - 统计在线用户数
> - 统计用户每天搜索不同词条的个数

```bash
PFadd mykey aIa b C defghij #创建第一组元素mykey
PFCOUNT mykey # 统计mykey元素的基数数量
PFadd mykey2 i j z xcvbnm #创建第二组元素mykey2
PFMERGE mykey3 mykey mykey2 #合并两组mykey mykey2 => mykey3 并集
PFCOUNT mykey3 #看并集的数量!
```

如果允许容错,那么-定可以使用Hyperloglog !
如果不允许容错,就使用Iset或者自己的数据类型即可!

### 3、Bitmaps (位图)

- 统计用户信息,活跃,不活跃!登录、未登录!打卡, 365打卡!两个状态的,都可以使用Bitmaps !
- Bitmaps位图,数据结构!都是操作二进制位来进行记录,就只有0和1两个状态!

> ###### 使用场景一:用户签到
>
> 很多网站都提供了签到功能(这里不考虑数据落地事宜),并且需要展示最近一个月的签到情况.
>
> ###### 使用场景二:统计活跃用户
>
> 使用时间作为cacheKey,然后用户ID为offset,如果当日活跃过就设置为1那么我该如果计算某几天/月/年的活跃用户呢(暂且约定,统计时间内只有有一天在线就称为活跃),有请下一个redis的命令命令 `BITOP operation destkey key [key ...]`
> 说明:对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上。
>
> ###### 使用场景三:用户在线状态
>
> bitmap是一个节约空间效率又高的一种方法,只需要一个key,然后用户ID为offset,如果在线就设置为1,不在线就设置为0.
>
> ###### 

```bash
SETBIT sig 0 1 # 设置位图
GETBIT sig 6 # 获取位图
################################
`用户签到`:模拟用户打卡场景,0-6为一周,0为未打卡,1为打卡
BITCOUNT sig  # 统计用户一周打卡天数
```

![image-20201006212348625](D:\NULL\学习资源\md笔记\images\redis\image-20201006212348625.png)

## 五、redis事务

==Redis单条命令式保存原子性的,但是事务不保证原子性!==

==Redis事务没有没有隔离级别的概念!==
所有的命令在事务中,并没有直接被执行!只有发起执行命令的时候才会执行! Exec

> Redis事务本质: 一组命令的集合! -一个事务中的所有命令都会被序列化,在事务执行过程的中,会按照顺序执行!
> 一次性、顺序性、排他性!执行- -些列的命令!

redis的事务:

- 开启事务( multi)

- 命令入队(-----)
- 执行事务(exec)

> redis事务操作步骤

![image-20201007084953524](D:\NULL\学习资源\md笔记\images\redis\image-20201007084953524.png)

> 放弃事务:` DISCARD`

![image-20201007085507640](D:\NULL\学习资源\md笔记\images\redis\image-20201007085507640.png)

> 编译型异常(代码有问题!命令有错! ) , 事务中所有的命令都不会被执行!

![image-20201007090026763](D:\NULL\学习资源\md笔记\images\redis\image-20201007090026763.png)

> 运行时异常( 1/0),如果事务队列中存在语法性,那么执行命令的时候,其他命令是可以正常执行的,错误命令抛出异常!

![image-20201007090449759](D:\NULL\学习资源\md笔记\images\redis\image-20201007090449759.png)

## 六、redis监控

> 监控! Watch
>
> UNWATCH

悲观锁:

- 很悲观,认为什么时候都会出问题,无论做什么都会加锁!
  乐观锁:
- 很乐观,认为什么时候都不会出问题,所以不会上锁!更新数据的时候去判断- - 下,在此期间是否有人修改过这个数据,
- 获取version
- 更新的时候比较version

![image-20201007164958729](D:\NULL\学习资源\md笔记\images\redis\image-20201007164958729.png)

#### 应用场景

> 利用redis来实现乐观锁 
>
> ​     1、利用redis的watch功能,监控这个redisKey的状态值
>  ​    2、获取redisKey的值
>  ​    3、创建redis事务
>  ​    4、给这个key的值+1
>  ​    5、然后去执行这个事务,如果key的值被修改过则回滚,key不+1

## 七、Jedis

### 1、什么是jedis

> jedis是Redis官方推荐的java连接开发工具!使用Java 操作Redis中间件!如果你要使用java操作redis ,那么一定要对Jedis十分的熟悉!

### 2 、jedis方法

> 方法和redis窗口命令基本相同

## 八、springboot整合redis

> springboot进阶已记录:链接:

## 九、redis.config详解

```bash
# 当配置中需要配置内存大小时,可以使用 1k, 5GB, 4M 等类似的格式,其转换方式如下(不区分大小写)
#
# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes
#
# 内存配置大小写是一样的.比如 1gb 1Gb 1GB 1gB
 
 
# daemonize no 默认情况下,redis不是在后台运行的,如果需要在后台运行,把该项的值更改为yes
daemonize yes
 
# 当redis在后台运行的时候,Redis默认会把pid文件放在/var/run/redis.pid,你可以配置到其他地址。
# 当运行多个redis服务时,需要指定不同的pid文件和端口
pidfile /var/run/redis.pid
 
# 指定redis运行的端口,默认是6379
port 6379
 
# 指定redis只接收来自于该IP地址的请求,如果不进行设置,那么将处理所有请求,
# 在生产环境中最好设置该项
# bind 127.0.0.1
 
# Specify the path for the unix socket that will be used to listen for
# incoming connections. There is no default, so Redis will not listen
# on a unix socket when not specified.
#
# unixsocket /tmp/redis.sock
# unixsocketperm 755
 
# 设置客户端连接时的超时时间,单位为秒。当客户端在这段时间内没有发出任何指令,那么关闭该连接
# 0是关闭此设置
timeout 0
 
# 指定日志记录级别
# Redis总共支持四个级别:debug、verbose、notice、warning,默认为verbose
# debug 记录很多信息,用于开发和测试
# varbose 有用的信息,不像debug会记录那么多
# notice 普通的verbose,常用于生产环境
# warning 只有非常重要或者严重的信息会记录到日志
loglevel debug
 
# 配置log文件地址
# 默认值为stdout,标准输出,若后台模式会输出到/dev/null
#logfile stdout
logfile /var/log/redis/redis.log
 
# To enable logging to the system logger, just set 'syslog-enabled' to yes,
# and optionally update the other syslog parameters to suit your needs.
# syslog-enabled no
 
# Specify the syslog identity.
# syslog-ident redis
 
# Specify the syslog facility.  Must be USER or between LOCAL0-LOCAL7.
# syslog-facility local0
 
# 可用数据库数
# 默认值为16,默认数据库为0,数据库范围在0-(database-1)之间
databases 16
 
################################ 快照  #################################
#
# 保存数据到磁盘,格式如下:
#
#   save
#
#   指出在多长时间内,有多少次更新操作,就将数据同步到数据文件rdb。
#   相当于条件触发抓取快照,这个可以多个条件配合
#   
#   比如默认配置文件中的设置,就设置了三个条件
#
#   save 900 1  900秒内至少有1个key被改变
#   save 300 10  300秒内至少有300个key被改变
#   save 60 10000  60秒内至少有10000个key被改变
 
save 900 1
save 300 10
save 60 10000
 
# 存储至本地数据库时(持久化到rdb文件)是否压缩数据,默认为yes
rdbcompression yes
 
 
# 本地持久化数据库文件名,默认值为dump.rdb
dbfilename dump.rdb
 
# 工作目录
#
# 数据库镜像备份的文件放置的路径。
# 这里的路径跟文件名要分开配置是因为redis在进行备份时,先会将当前数据库的状态写入到一个临时文件中,等备份完成时,
# 再把该该临时文件替换为上面所指定的文件,而这里的临时文件和上面所配置的备份文件都会放在这个指定的路径当中。
#
# AOF文件也会存放在这个目录下面
#
# 注意这里必须制定一个目录而不是文件
dir ./
 
################################# 复制 #################################
 
# 主从复制. 设置该数据库为其他数据库的从数据库.
# 设置当本机为slav服务时,设置master服务的IP地址及端口,在Redis启动时,它会自动从master进行数据同步
#
# slaveof
 
# 当master服务设置了密码保护时(用requirepass制定的密码)
# slav服务连接master的密码
#
# masterauth
 
 
# 当从库同主机失去连接或者复制正在进行,从机库有两种运行方式:
#
# 1) 如果slave-serve-stale-data设置为yes(默认设置),从库会继续相应客户端的请求
#
# 2) 如果slave-serve-stale-data是指为no,出去INFO和SLAVOF命令之外的任何请求都会返回一个
#    错误"SYNC with master in progress"
#
slave-serve-stale-data yes
 
# 从库会按照一个时间间隔向主库发送PINGs.可以通过repl-ping-slave-period设置这个时间间隔,默认是10秒
#
# repl-ping-slave-period 10
 
# repl-timeout 设置主库批量数据传输时间或者ping回复时间间隔,默认值是60秒
# 一定要确保repl-timeout大于repl-ping-slave-period
# repl-timeout 60
 
################################## 安全 ###################################
 
# 设置客户端连接后进行任何其他指定前需要使用的密码。
# 警告:因为redis速度相当快,所以在一台比较好的服务器下,一个外部的用户可以在一秒钟进行150K次的密码尝试,这意味着你需要指定非常非常强大的密码来防止暴力破解
#
# requirepass foobared
 
# 命令重命名.
#
# 在一个共享环境下可以重命名相对危险的命令。比如把CONFIG重名为一个不容易猜测的字符。
#
# 举例:
#
# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
#
# 如果想删除一个命令,直接把它重命名为一个空字符""即可,如下:
#
# rename-command CONFIG ""
 
################################### 约束 ####################################
 
# 设置同一时间最大客户端连接数,默认无限制,Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件描述符数,
# 如果设置 maxclients 0,表示不作限制。
# 当客户端连接数到达限制时,Redis会关闭新的连接并向客户端返回max number of clients reached错误信息
#
# maxclients 128
 
# 指定Redis最大内存限制,Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除已到期或即将到期的Key
# Redis同时也会移除空的list对象
#
# 当此方法处理后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作
#
# 注意:Redis新的vm机制,会把Key存放内存,Value会存放在swap区
#
# maxmemory的设置比较适合于把redis当作于类似memcached的缓存来使用,而不适合当做一个真实的DB。
# 当把Redis当做一个真实的数据库使用的时候,内存使用将是一个很大的开销
# maxmemory
 
# 当内存达到最大值的时候Redis会选择删除哪些数据?有五种方式可供选择
#
# volatile-lru -> 利用LRU算法移除设置过过期时间的key (LRU:最近使用 Least Recently Used )
# allkeys-lru -> 利用LRU算法移除任何key
# volatile-random -> 移除设置过过期时间的随机key
# allkeys->random -> remove a random key, any key
# volatile-ttl -> 移除即将过期的key(minor TTL)
# noeviction -> 不移除任何可以,只是返回一个写错误
#
# 注意:对于上面的策略,如果没有合适的key可以移除,当写的时候Redis会返回一个错误
#
#       写命令包括: set setnx setex append
#       incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd
#       sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby
#       zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby
#       getset mset msetnx exec sort
#
# 默认是:
#
# maxmemory-policy volatile-lru
 
# LRU 和 minimal TTL 算法都不是精准的算法,但是相对精确的算法(为了节省内存),随意你可以选择样本大小进行检测。
# Redis默认的灰选择3个样本进行检测,你可以通过maxmemory-samples进行设置
#
# maxmemory-samples 3
 
############################## AOF ###############################
 
# 默认情况下,redis会在后台异步的把数据库镜像备份到磁盘,但是该备份是非常耗时的,而且备份也不能很频繁,如果发生诸如拉闸限电、拔插头等状况,那么将造成比较大范围的数据丢失。
# 所以redis提供了另外一种更加高效的数据库备份及灾难恢复方式。
# 开启append only模式之后,redis会把所接收到的每一次写操作请求都追加到appendonly.aof文件中,当redis重新启动时,会从该文件恢复出之前的状态。
# 但是这样会造成appendonly.aof文件过大,所以redis还支持了BGREWRITEAOF指令,对appendonly.aof 进行重新整理。
# 你可以同时开启asynchronous dumps 和 AOF
 
appendonly no
 
# AOF文件名称 (默认: "appendonly.aof")
# appendfilename appendonly.aof
 
 
# Redis支持三种同步AOF文件的策略:
#
# no: 不进行同步,系统去操作 . Faster.
# always: always表示每次有写操作都进行同步. Slow, Safest.
# everysec: 表示对写操作进行累积,每秒同步一次. Compromise.
#
# 默认是"everysec",按照速度和安全折中这是最好的。
# 如果想让Redis能更高效的运行,你也可以设置为"no",让操作系统决定什么时候去执行
# 或者相反想让数据更安全你也可以设置为"always"
#
# 如果不确定就用 "everysec".
 
# appendfsync always
appendfsync everysec
# appendfsync no
 
# AOF策略设置为always或者everysec时,后台处理进程(后台保存或者AOF日志重写)会执行大量的I/O操作
# 在某些Linux配置中会阻止过长的fsync()请求。注意现在没有任何修复,即使fsync在另外一个线程进行处理
#
# 为了减缓这个问题,可以设置下面这个参数no-appendfsync-on-rewrite
#
# This means that while another child is saving the durability of Redis is
# the same as "appendfsync none", that in pratical terms means that it is
# possible to lost up to 30 seconds of log in the worst scenario (with the
# default Linux settings).
#
# If you have latency problems turn this to "yes". Otherwise leave it as
# "no" that is the safest pick from the point of view of durability.
no-appendfsync-on-rewrite no
 
# Automatic rewrite of the append only file.
# AOF 自动重写
# 当AOF文件增长到一定大小的时候Redis能够调用 BGREWRITEAOF 对日志文件进行重写
#
# 它是这样工作的:Redis会记住上次进行些日志后文件的大小(如果从开机以来还没进行过重写,那日子大小在开机的时候确定)
#
# 基础大小会同现在的大小进行比较。如果现在的大小比基础大小大制定的百分比,重写功能将启动
# 同时需要指定一个最小大小用于AOF重写,这个用于阻止即使文件很小但是增长幅度很大也去重写AOF文件的情况
# 设置 percentage 为0就关闭这个特性
 
 
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
 
################################## SLOW LOG ###################################
 
# Redis Slow Log 记录超过特定执行时间的命令。执行时间不包括I/O计算比如连接客户端,返回结果等,只是命令执行时间
#
# 可以通过两个参数设置slow log:一个是告诉Redis执行超过多少时间被记录的参数slowlog-log-slower-than(微妙),
# 另一个是slow log 的长度。当一个新命令被记录的时候最早的命令将被从队列中移除
 
 
# 下面的时间以微妙微单位,因此1000000代表一分钟。
# 注意制定一个负数将关闭慢日志,而设置为0将强制每个命令都会记录
slowlog-log-slower-than 10000
 
 
# 对日志长度没有限制,只是要注意它会消耗内存
# 可以通过 SLOWLOG RESET 回收被慢日志消耗的内存
slowlog-max-len 1024
 
################################ VM ###############################
 
### WARNING! Virtual Memory is deprecated in Redis 2.4
### The use of Virtual Memory is strongly discouraged.
 
# Virtual Memory allows Redis to work with datasets bigger than the actual
# amount of RAM needed to hold the whole dataset in memory.
# In order to do so very used keys are taken in memory while the other keys
# are swapped into a swap file, similarly to what operating systems do
# with memory pages.
#
# To enable VM just set 'vm-enabled' to yes, and set the following three
# VM parameters accordingly to your needs.
 
vm-enabled no
# vm-enabled yes
 
# This is the path of the Redis swap file. As you can guess, swap files
# can't be shared by different Redis instances, so make sure to use a swap
# file for every redis process you are running. Redis will complain if the
# swap file is already in use.
#
# The best kind of storage for the Redis swap file (that's accessed at random)
# is a Solid State Disk (SSD).
#
# *** WARNING *** if you are using a shared hosting the default of putting
# the swap file under /tmp is not secure. Create a dir with access granted
# only to Redis user and configure Redis to create the swap file there.
vm-swap-file /tmp/redis.swap
 
# vm-max-memory configures the VM to use at max the specified amount of
# RAM. Everything that deos not fit will be swapped on disk *if* possible, that
# is, if there is still enough contiguous space in the swap file.
#
# With vm-max-memory 0 the system will swap everything it can. Not a good
# default, just specify the max amount of RAM you can in bytes, but it's
# better to leave some margin. For instance specify an amount of RAM
# that's more or less between 60 and 80% of your free RAM.
vm-max-memory 0
 
# Redis swap files is split into pages. An object can be saved using multiple
# contiguous pages, but pages can't be shared between different objects.
# So if your page is too big, small objects swapped out on disk will waste
# a lot of space. If you page is too small, there is less space in the swap
# file (assuming you configured the same number of total swap file pages).
#
# If you use a lot of small objects, use a page size of 64 or 32 bytes.
# If you use a lot of big objects, use a bigger page size.
# If unsure, use the default :)
vm-page-size 32
 
# Number of total memory pages in the swap file.
# Given that the page table (a bitmap of free/used pages) is taken in memory,
# every 8 pages on disk will consume 1 byte of RAM.
#
# The total swap size is vm-page-size * vm-pages
#
# With the default of 32-bytes memory pages and 134217728 pages Redis will
# use a 4 GB swap file, that will use 16 MB of RAM for the page table.
#
# It's better to use the smallest acceptable value for your application,
# but the default is large in order to work in most conditions.
vm-pages 134217728
 
# Max number of VM I/O threads running at the same time.
# This threads are used to read/write data from/to swap file, since they
# also encode and decode objects from disk to memory or the reverse, a bigger
# number of threads can help with big objects even if they can't help with
# I/O itself as the physical device may not be able to couple with many
# reads/writes operations at the same time.
#
# The special value of 0 turn off threaded I/O and enables the blocking
# Virtual Memory implementation.
vm-max-threads 4
 
############################### ADVANCED CONFIG ###############################
 
# 当hash中包含超过指定元素个数并且最大的元素没有超过临界时,
# hash将以一种特殊的编码方式(大大减少内存使用)来存储,这里可以设置这两个临界值
# Redis Hash对应Value内部实际就是一个HashMap,实际这里会有2种不同实现,
# 这个Hash的成员比较少时Redis为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的HashMap结构,对应的value redisObject的encoding为zipmap,
# 当成员数量增大时会自动转成真正的HashMap,此时encoding为ht。
hash-max-zipmap-entries 512
hash-max-zipmap-value 64
 
# list数据类型多少节点以下会采用去指针的紧凑存储格式。
# list数据类型节点值大小小于多少字节会采用紧凑存储格式。
list-max-ziplist-entries 512
list-max-ziplist-value 64
 
# set数据类型内部数据如果全部是数值型,且包含多少节点以下会采用紧凑格式存储。
set-max-intset-entries 512
 
# zsort数据类型多少节点以下会采用去指针的紧凑存储格式。
# zsort数据类型节点值大小小于多少字节会采用紧凑存储格式。
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
 
 
# Redis将在每100毫秒时使用1毫秒的CPU时间来对redis的hash表进行重新hash,可以降低内存的使用
#
# 当你的使用场景中,有非常严格的实时性需要,不能够接受Redis时不时的对请求有2毫秒的延迟的话,把这项配置为no。
#
# 如果没有这么严格的实时性要求,可以设置为yes,以便能够尽可能快的释放内存
activerehashing yes
 
################################## INCLUDES ###################################
 
# 指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件
 
# include /path/to/local.conf
# include /path/to/other.conf 
```

## 十、redis持久化操作

> 持久化的作用

Redis是内存数据库,如果不将内存中的数据库状态保存到磁盘,那么- -旦服务器进程退出 ,服务器中的数据库状态也会消失。所
以Redis提供了持久化功能!

### 1、持久化之RDB

> RDB概念

![image-20201008175837117](D:\NULL\学习资源\md笔记\images\redis\image-20201008175837117.png)

在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里。
Redis会单独创建( fork ) -个子进程来进行持久化,会先将数据写入到-一个临时文件中,待持久化过程都结束了,再用这个临时文
件替换上次持久化好的文件。整个过程中,主进程是不进行任何I0操作的。这就确保了极高的性能。如果需要进行大规模数据的恢
复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后- -次持久化后的数据可能丢
失。

> 配置文件参数

```bash
 
################################ 快照  #################################
# 保存数据到磁盘,格式如下:
#   save
#   指出在多长时间内,有多少次更新操作,就将数据同步到数据文件rdb。
#   相当于条件触发抓取快照,这个可以多个条件配合
#   比如默认配置文件中的设置,就设置了三个条件
#   save 900 1  900秒内至少有1个key被改变
#   save 300 10  300秒内至少有300个key被改变
#   save 60 10000  60秒内至少有10000个key被改变
save 900 1
save 300 10
save 60 10000
# 存储至本地数据库时(持久化到rdb文件)是否压缩数据,默认为yes
rdbcompression yes
# 本地持久化数据库文件名,默认值为dump.rdb
dbfilename dump.rdb
```

==RDB保存的文件格式默认是dump.rdb==

> RDB文件保存触发规则

1. save的规则满足的情况下,会自动触发rdb规则
2. 执行flushall命令,也会触发我们的rdb规则!
3. 退出redis ,也会产生rdb文件!

> 如何恢复RDB文件

1、只需要将rdb文件放在我们redis启动目录就可以, redis启动的时候会自动检查dump.rdb恢复其中的数据!
2、查看需要存在的位置

![image-20201008180742770](D:\NULL\学习资源\md笔记\images\redis\image-20201008180742770.png)

> 优点

1、适合大规模的数据恢复!
2、对数据的完整性要不高!

> 缺点

1、需要一定的时间间隔进程操作!如果redis意外宕机了,这个最后一次修改数据就没有的了! .

2、fork进程的时候,会占用一定的内容空间! !

### 2、持久化之AOF ( Append Only File )

**概念**

> 将我们的所有命令都记录下来, history ,恢复的时候就把这个文件全部在执行一遍!

![image-20201008201007537](D:\NULL\学习资源\md笔记\images\redis\image-20201008201007537.png)

以日志的形式来记录每个写操作,将Redis执行过的所有指令记录下来(读操作不记录) , 只许追加文件但不可以改写文件, redis启动之初会读取该文件重新构建数据,换言之, redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作Aof保存的是appendonly.aof文件。

> 开启aof

![image-20201008204214197](D:\NULL\学习资源\md笔记\images\redis\image-20201008204214197.png)

==默认是不开启的,我们需要手动进行配置!我们只需要将appendoly改为yes就开启了aof !==

> aof文件有错

如果这个aof文件有错位,这时候redis 是启动不起来的吗,我们需要修复这个aof文件
redis给我们提供了一个工具`redis-check-aof --fix`

> 优点和缺点!

```bash
appendonly no
#默认是不开启aof模式的,默认是使用rdb方式持久化的,在大部分所有的情况下,rdb完全够用!
appendfilename "appendonly.aof" # 持久化的文件的名字

# appendfsync always

#每次修改都会sync。消耗性能
appendfsync everysec
#每秒执行一次sync, 可能会丢失这1s的数据!

# appendfsync no

#不执行sync, 这个时候操作系统自己同步数据,速度最快!
```

**优点:**
1、每一次修改都同步,文件的完整会更加好!
2、每秒同步-次,可能会丢失-秒的数据
3、从不同步,效率最高的!

**缺点:**
1、相对于数据文件来说, aof远远大于rdb ,修复的速度也比rdb慢!
2、Aof 运行效率也要比rdb慢,所以我们redis默认的配置就是rdb持久化!

> 扩展

1、RDB持久化方式能够在指定的时间间隔内对你的数据进行快照存储

2、AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据, AOF命令以Redis协
     议追加保存每次写的操作到文件末尾, Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大。

3、只做缓存,如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化

4、同时开启两种持久化方式

- 在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB
  文件保存的数据集要完整。
- RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件,那要不要只使用AOF呢?作者建议不要,因为RDB更适合
  用于备份数据库( AOF在不断变化不好备份) , 快速重启,而且不会有AOF可能潜在的Bug ,留着作为一一个万一 -的手段。

5、性能建议

- 因为RDB文件只用作后备用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份- 次就够了,只保留save 9001这条
  规则。
- 如果Enable AOF ,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了,代价一是带来了持续的I0 ,二是AOF rewrite的最后将rewrite 过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少AOF rewrite的频率, AOF重写的基础大小默认值64M太了.可以设到5G以上,默认超过原大小100%大小重写可以改到适当的数值。
- 如果不Enable AOF ,仅靠Master-Slave Repllcation实现高可用性也可以,能省掉一大笔I0 ,也减少了rewrite时带来的系统
  波动。代价是如果Master/Slave 同时倒掉,会丢失十几分钟的数据,启动脚本也要比较两个Master/Slave中的RDB文件,载
  入较新的那个,微博就是这种架构。

> RDB 和 AOF 对比

| RDB        | AOF    |              |
| ---------- | ------ | ------------ |
| 启动优先级 | 低     | 高           |
| 体积       | 小     | 大           |
| 恢复速度   | 快     | 慢           |
| 数据安全性 | 丢数据 | 根据策略决定 |

> 如何选择使用哪种持久化方式?

一般来说, 如果想达到足以媲美 PostgreSQL 的数据安全性, 你应该同时使用两种持久化功能。

如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。

有很多用户都只使用 AOF 持久化, 但并不推荐这种方式: 因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快。

## 十一、发布和订阅

> 什么是发布和订阅

Redis 发布订阅(pub/sub)是一种==消息通信模式==:发送者(pub)发送消息,订阅者(sub)接收消息。类似于:微信、微博、关注系统!Redis 客户端可以订阅任意数量的频道。
订阅/发布消息图:

第一个:消息发送者, 第二个:频道 第三个:消息订阅者!

![2020092421593358](D:\NULL\学习资源\md笔记\images\redis\2020092421593358.png)

> 下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:

![20200924215943362](D:\NULL\学习资源\md笔记\images\redis\20200924215943362.png)

> 当有新消息通过 PUBLISH 命令发送给频道 channel1 时,这个消息就会被发送给订阅它的三个客户端

![](D:\NULL\学习资源\md笔记\images\redis\20200924215943362.png)

>  命令:
>
> 这些命令被广泛用于构建即时通信应用,比如网络聊天室(chatroom)和实时广播、实时提醒等。

| 命令                                   | 描述                               |
| -------------------------------------- | ---------------------------------- |
| PSUBSCRIBE pattern [pattern…]          | 订阅一个或多个符合给定模式的频道。 |
| PUNSUBSCRIBE pattern [pattern…]        | 退订一个或多个符合给定模式的频道。 |
| PUBSUB subcommand [argument[argument]] | 查看订阅与发布系统状态。           |
| PUBLISH channel message                | 向指定频道发布消息                 |
| SUBSCRIBE channel [channel…]           | 订阅给定的一个或多个频道。         |
| UNSUBSCRIBE channel [channel…]         | 退订一个或多个频道                 |

> SUBSCRIBE 
>
> 订阅段

![image-20201008212002263](D:\NULL\学习资源\md笔记\images\redis\image-20201008212002263.png)

> PUBLISH 
>
> 发送端

![image-20201008212128975](D:\NULL\学习资源\md笔记\images\redis\image-20201008212128975.png)

> 原理

Redis是使用C实现的,通过分析Redis源码里的pubsub.c 文件,了解发布和订阅机制的底层实现,籍此加深对Redis的理解。
Redis通过PUBLISH、SUBSCRIBE 和PSUBSCRIBE等命令实现发布和订阅功能。
通过SUBSCRIBE命令订阅某频道后, redis-server 里维护了一个字典,字典的键就是一个个channel ,而字典的值则是一个链
表,链表中保存了所有订阅这个channel的客户端。SUBSCRIBE 命令的关键,就是将客户端添加到给定channel的订阅链表中。
通过PUBLISH命令向订阅者发送消息, redis-server 会使用给定的频道作为键,在它所维护的channel字典中查找记录了订阅这
个频道的所有客户端的链表,遍历这个链表,将消息发布给所有订阅者.
Pub/Sub从字面上理解就是发布( Publish )与订阅( Subscribe ) , 在Redis中,你可以设定对某-个key值进行消息发布及消息订
阅,当一个key值上进行了消息发布后,所有订阅它的客户端都会收到相应的消息。这-功能最明显的用法就是用作实时消息系
统,比如普通的即时聊天,群聊等功能。

>

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章