feat: redis学习

master
old-tom 3 years ago
parent ca8eea2107
commit d333d05b19

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

@ -0,0 +1,102 @@
+ String
+ hash
+ list
+ set
+ zset
# 一、数据结构
## 1. string
字符串由多个字节组成每个字节由8个bit组成可以将一个字符串看成很多bit的组合这就是bitmap数据结构。
redis提供的字符串是动态字符串是可以修改的字符串内部使用数组结构实现采用**预分配**冗余空间的方式来减少内存的频繁分配如图所示预分配的空间capacity要高于实际字符串长度len。
![[Snipaste_2023-02-22_14-56-05.png]]
当字符串长度小于1MB时扩容都是加倍现有空间。如果字符串长度超过1MB扩容时一次只会多扩1MB空间并且字符串最大长度为512MB。
### 1.1常用命令
#### 1.1.1 键值对
![[Snipaste_2023-02-22_14-56-05 1.png]]
#### 1.1.2 批量键值对
对多字符串进行批量读写
![[Snipaste_2023-02-22_14-56-05 2.png]]
#### 1.1.3 过期和set命令扩展
对key设置过期时间到期自动删除
![[Snipaste_2023-02-22_14-56-05 3.png]]
等价命令 setex name 3 zr 等价于set + expire
![[Snipaste_2023-02-22_14-56-05 4.png]]
setnx name zr 如果name不存在则创建
![[Snipaste_2023-02-22_14-56-05 5.png]]
#### 1.1.4 计数
如果value值是一个整数可以对它进行自增操作自增范围在long的最大值和最小值之间
![[Snipaste_2023-02-22_14-56-05 6.png]]
## 2.list
Redis的list相当于Java的LinkedList是链表不是数组。插入和删除很快时间复杂度为O(1)。索引定位慢时间复杂度为O(n)。list的每个元素都使用了双向指针可以支持前向后向遍历因此可以作为队列或栈使用。
![[Snipaste_2023-02-22_14-56-05 7.png]]
### 2.1 常用命令
#### 2.1.1 队列
队列是先进先出的数据结构,用于消息排队和异步逻辑处理。支持左进右出、右进左出,会确保元素的访问顺序性。
![[Snipaste_2023-02-22_14-56-05 8.png]]
使用pop命令后元素会删除
#### 2.1.2栈
栈是后进先出的数据结构
![[Snipaste_2023-02-22_14-56-05 9.png]]
#### 2.1.3慢操作
lindex类似于java的get(int index)方法需要对list进行遍历性能随着参数index增加而变差。
ltrim类似于截取操作由两个参数start_index和end_index定义一个区间保留在区间内的值区间外的删除可以用来实现一个定长的链表。
index可以为负数index=-1表示倒数第一个元素同理index=-2表示倒数第二个元素。
![[Snipaste_2023-02-22_14-56-05 10.png]]
### 2.2底层数据结构quicklist
实际上Redis的list并不是一个简单的linkedlist而是quicklist快速链表
在元素较少情况下会使用一块连续的内存存储这个结构是ziplist压缩列表。将所有的元素彼此紧挨着存储也可以看作是数组结构。当数据量比较多的时间才会变成quicklist因为普通的链表需要的附加指针空间前后指针所以Redis将链表和ziplist结合组成quicklist将多个ziplist使用双向指针连接使用。
![[Snipaste_2023-02-22_16-10-55.png]]
## 3.hash
Redis字典相当于Java的HashMap属于无序字典在数据结构上使用的是数组+链表也就是散列表结构。
![[Snipaste_2023-02-22_16-10-55 4.png]]
### 3.1 常用操作
![[Snipaste_2023-02-22_16-10-55 1.png]]
#### 获取字典中的所有值
![[Snipaste_2023-02-22_16-10-55 2.png]]
#### 获取字典中的所有键值对
![[Snipaste_2023-02-22_16-10-55 3.png]]
### 3.2 底层数据结构
采用于HashMao相同的散列表结构redis字段的值只能是字符串
![[Snipaste_2023-02-22_16-10-55 5.png]]
#### 3.2.1 rehash
Redis为了追求高性能采用了渐进式rehash策略可以不堵塞服务但是需要牺牲空间可以理解为空间换时间。渐进式rehash会在执行同时保留新旧两个hash结构查询时会同时查询两个hash然后再后续的定时任务以及hash操作指令中循序渐进地将旧hash的内容迁移到新hash结构当迁移完成就使用新hash代替。
![[Snipaste_2023-02-22_16-10-55 6.png]]
### 3.3优缺点
hash结构可以结构化存储用户信息相比于json存储可以单独获取或修改某几个字段。如果以整个字符串形式保存的话只能一次性读取比较浪费流量。
缺点是存储消耗要高于单个字符。
## 4.set
相当于Java的HashSet其内部键值对是无序且唯一的内部实现相当于一个特殊的字典字典中所有的value都是NULL
### 4.1 常用操作
![[Snipaste_2023-02-22_16-10-55 7.png]]
#### 查询某个值是否存在
![[Snipaste_2023-02-22_16-10-55 8.png]]
#### 获取长度
![[Snipaste_2023-02-22_16-10-55 9.png]]
#### 弹出一个
![[Snipaste_2023-02-22_16-10-55 10.png]]
## 5.zset
类似于Java的SortedSet和HashMap结合体set保证内部value的唯一性另外可以给每个value赋予一个score代表排序权重内部是使用跳跃列表实现。
![[Snipaste_2023-02-23_10-00-41.png]]
### 5.1 常用操作
![[Snipaste_2023-02-23_10-00-41 1.png]]
#### 逆序输出
![[Snipaste_2023-02-23_10-00-41 2.png]]
#### 统计
![[Snipaste_2023-02-23_10-00-41 3.png]]
#### 获取指定value的score
![[Snipaste_2023-02-23_10-00-41 4.png]]
#### 排名
![[Snipaste_2023-02-23_10-00-41 5.png]]
#### 删除value
![[Snipaste_2023-02-23_10-00-41 6.png]]
#### 根据score区间遍历
0 2 表示分数区间
![[Snipaste_2023-02-23_10-00-41 7.png]]
### 5.2 底层数据结构(跳跃列表)
查看数据结构相关文档

@ -0,0 +1,3 @@
[Redis 哈希(Hash)_redis教程](https://www.redis.net.cn/tutorial/3509.html)
![[Snipaste_2023-02-20_15-21-10 3.png]]
![[Snipaste_2023-02-20_15-21-10 2.png]]

@ -0,0 +1,5 @@
用于不精确的去重统计标准误差为0.81%,可以用于访问量统计或者其他不需要精确统计的场景
# 一、使用方法
提供了pfadd、pfcount第一个用于增加计数第二个是获取计数
![[Snipaste_2023-02-23_17-24-34 11.png]]

@ -0,0 +1,4 @@
![[Snipaste_2023-02-20_14-56-37 4.png]]
![[Snipaste_2023-02-20_15-16-16.png]]

@ -0,0 +1,3 @@
[Redis 列表(List)_redis教程](https://www.redis.net.cn/tutorial/3510.html)
![[Snipaste_2023-02-20_15-21-10 4.png]]
![[Snipaste_2023-02-20_15-21-10 5.png]]

@ -0,0 +1,9 @@
1.本地打开redis
`redis-cli`
2.远程打开redis
`redis-cli -h host -p port -a password`
例:`redis-cli -h 127.0.0.1 -p 6379 -a "mypass"`

@ -0,0 +1,40 @@
Redis支持五种数据类型string字符串hash哈希list列表set集合及zset(sorted set有序集合)。
# 一、String(字符串)
string是redis最基本的类型你可以理解成与Memcached一模一样的类型一个key对应一个value。
string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。
string类型是Redis最基本的数据类型一个键最大能存储512MB。
`1. redis 127.0.0.1:6379> SET name "redis.net.cn"`
`2. OK`
`3. redis 127.0.0.1:6379> GET name`
`4. "redis.net.cn"`
在以上实例中我们使用了 Redis 的 **SET** 和 **GET** 命令。键为 name对应的值为redis.net.cn。
**注意:**一个键最大能存储512MB。
# 二、Hash(哈希)
Redis hash 是一个键值对集合。
Redis hash是一个string类型的field和value的映射表hash特别适合用于存储对象。一对多一个key对应多个value
![[Snipaste_2023-02-20_14-56-37.png]]
以上实例中 hash 数据类型存储了包含用户脚本信息的用户对象。 实例中我们使用了 Redis **HMSET, HEGTALL** 命令,**user:1** 为键值。
每个 hash 可以存储 232 - 1 键值对40多亿
# 三、List(列表)
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边)。
![[Snipaste_2023-02-20_14-56-37 1.png]]
列表最多可存储 232 - 1 元素 (4294967295, 每个列表可存储40多亿)。
# 四、Set(集合)
Redis的Set是string类型的无序集合。集合是通过哈希表实现的所以添加删除查找的复杂度都是O(1)。
### sadd 命令
添加一个string元素到,key对应的set集合中成功返回1,如果元素以及在集合中返回0,key对应的set不存在返回错误。
![[Snipaste_2023-02-20_14-56-37 2.png]]
**注意:**以上实例中 rabitmq 添加了两次,但根据集合内元素的唯一性,第二次插入的元素将被忽略。
集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。
# 五、zset(有序集合)
Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但分数(score)却可以重复。
### zadd 命令
添加元素到集合元素在集合中存在则更新对应score
![[Snipaste_2023-02-20_14-56-37 3.png]]

@ -0,0 +1,15 @@
Redis 是完全开源免费的遵守BSD协议是一个高性能的key-value数据库。
Redis 与其他 key - value 缓存产品有以下三个特点:
- Redis支持数据的持久化可以将内存中的数据保持在磁盘中重启的时候可以再次加载进行使用。
- Redis不仅仅支持简单的key-value类型的数据同时还提供listsetzsethash等数据结构的存储。
- Redis支持数据的备份即master-slave模式的数据备份。
## Redis优势
- 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
- 丰富的数据类型 Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
- 原子 Redis的所有操作都是原子性的同时Redis还支持对几个操作全并后的原子性执行。
- 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。
## Redis与其他key-value存储有什么不同
- Redis有着更为复杂的数据结构并且提供对他们的原子性操作这是一个不同于其他数据库的进化路径。Redis的数据类型都是基于基本数据结构的同时对程序员透明无需进行额外的抽象。
- Redis运行在内存中但是可以持久化到磁盘所以在对不同数据集进行高速读写时需要权衡内存应为数据量不能大于硬件内存。在内存数据库方面的另一个优点是 相比在磁盘上相同的复杂的数据结构在内存中操作起来非常简单这样Redis可以做很多内部复杂性很强的事情。 同时,在磁盘格式方面他们是紧凑的以追加的方式产生的,因为他们并不需要进行随机访问。

@ -0,0 +1,3 @@
[Redis 集合(Set)_redis教程](https://www.redis.net.cn/tutorial/3511.html)
![[Snipaste_2023-02-20_15-21-10 6.png]]
![[Snipaste_2023-02-20_15-21-10 7.png]]

@ -0,0 +1,3 @@
[Redis 字符串(String)_redis教程](https://www.redis.net.cn/tutorial/3508.html)
![[Snipaste_2023-02-20_15-21-10.png]]
![[Snipaste_2023-02-20_15-21-10 1.png]]

@ -0,0 +1,3 @@
[Redis 有序集合(sorted set)_redis教程](https://www.redis.net.cn/tutorial/3512.html)
![[Snipaste_2023-02-20_15-21-10 8.png]]
![[Snipaste_2023-02-20_15-21-10 9.png]]

@ -0,0 +1,13 @@
Redis 事务可以一次执行多个命令, 并且带有以下两个重要的保证:
- 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
- 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
一个事务从开始到执行会经历以下三个阶段:
- 开始事务。
- 命令入队。
- 执行事务。
![[Snipaste_2023-02-21_09-33-02.png]]
![[Snipaste_2023-02-21_09-33-02 1.png]]

@ -0,0 +1,20 @@
# 一、介绍
redis提供了不完整的事务有3个命令
multi 开启事务相当于begin
exec 执行事务相当于commit
discard 回滚相当于rollback
使用方法如下图所示
QUEUED是一个提示字符串和OK相同表示指令已经被服务器缓存到队列里了
![[Snipaste_2023-02-24_14-42-21.png]]
# 二、原子性
事务的原子性是指事务要么全部成功要么全部失败redis的事务不具备原子性因为它在遇到指令执行失败后后面的指令还会继续执行。
redis仅仅是满足了事务隔离性中的串行化当前执行的事务有着不被其他事务打断的权利
# 三、使用
一般事务和管道是一起使用的这样可以将多次IO操作压缩为单次IO操作。
重点多线程事务redis提供了watch机制一种乐观锁用于解决并发修改问题
watch会在事务开始之前盯住一个或多个关键变量当事务执行时服务器收到exec指令要顺序执行缓存的事务队列时Redis会检查关键变量自watch之后是否被修改包括当前事务所在的客户端。如果关键变量被修改exec指令就会返回NULL回复客户端事务执行失败这个时候客户端可以选择重试。
**禁止在multi和exec之间执行watch指令必须在multi之前盯住关键变量**

@ -0,0 +1,54 @@
# 一、介绍
举个例子用户一年的签到记录签了是1没签是0要记录365天。如果使用kv存储那么需要365条。当用户数量过亿的时候需要的存储空间就太大了。
为了解决这个问题redis提供了bitmap数据结构这样每天的签到记录只占用1位365天就是365位一共46个字节。位图的最小单位是比特(bit)每个bit的取值只能是0或1
![[Snipaste_2023-02-23_10-00-41 21.png]]
位图的内容就是普通字符串byte数组1byte=8bit。redis的位数组是自动扩展如果设置了某个偏移位置超出了现有的范围就会自动补零
# 二、基本用法
**零存** 使用setbit对位值进行逐个设置
**整存**:使用字符串一次性填充所有位数组
**零取**使用getbit获取位数组的值
## 2.1 零存整取
使用位操作符将字符串设置为hello先得到hello的ASCII码
![[Snipaste_2023-02-23_17-24-34.png]]
转换为8为ASCII码为
h:01101000
e:01100101
l:01101100
l:01101100
o:01101111
以h字符为例只需要设置为1的位置h字符有1/2/4位需要设置
![[Snipaste_2023-02-23_17-24-34 1.png]]
命令如下
![[Snipaste_2023-02-23_17-24-34 2.png]]
![[Snipaste_2023-02-23_17-24-34 3.png]]
## 2.2零存零取
![[Snipaste_2023-02-23_17-24-34 4.png]]
## 2.3整存零取
![[Snipaste_2023-02-23_17-24-34 5.png]]
## 2.4 统计和查找
位图统计指令bitcount用来统计指定位置范围内1的个数
位图查找指令bitpos用来查找指定范围内出现的第一个0或1
可以通过bitcount统计用户一共签到了多少天通过bitpos指令查找用户从哪一天开始第一次签到。如果指定了范围参数[startend],就可以统计在某个时间范围内用户签到了多少天,用户自某天以后的哪天开始签到。**注意start和end参数是字节索引也就是指定的位范围必须是8的倍数而不能任意指定。**
因为这个设计导致无法直接计算某个月内用户签到了多少天,而必须将这个月所覆盖的字节内容全部取出来在内存中统计
### bitcount
例: bitcount w 0 0 统计第一个字符中1的位数
![[Snipaste_2023-02-23_17-24-34 6.png]]
### bitpos
bitpos w 0 第一个0位
![[Snipaste_2023-02-23_17-24-34 7.png]]
bitpos w 1 0 1 从第一个字符算起第一个1位
![[Snipaste_2023-02-23_17-24-34 8.png]]
### bitfield
bitfield w get u4 0 从第一位开始取4个位结果为6对应4位二进制为0110
![[Snipaste_2023-02-23_17-24-34 9.png]]
bitfield w get u3 2 从第三位开始取3个位结果为5对应3位编码为101前面补零为0101=5
![[Snipaste_2023-02-23_17-24-34 10.png]]
# 三、使用场景
+ 用户签到统计

@ -0,0 +1,34 @@
分区是分割数据到多个Redis实例的处理过程因此每个实例只保存key的一个子集。
### 分区的优势
- 通过利用多台计算机内存的和值,允许我们构造更大的数据库。
- 通过多核和多台计算机,允许我们扩展计算能力;通过多台计算机和网络适配器,允许我们扩展网络带宽。
### 分区的不足
redis的一些特性在分区方面表现的不是很好
- 涉及多个key的操作通常是不被支持的。举例来说当两个set映射到不同的redis实例上时你就不能对这两个set执行交集操作。
- 涉及多个key的redis事务不能使用。
- 当使用分区时数据处理较为复杂比如你需要处理多个rdb/aof文件并且从多个实例和主机备份持久化文件。
- 增加或删除容量也比较复杂。redis集群大多数支持在运行时增加、删除节点的透明数据平衡的能力但是类似于客户端分区、代理等其他系统则不支持这项特性。然而一种叫做presharding的技术对此是有帮助的。
## 分区类型
Redis 有两种类型分区。 假设有4个Redis实例 R0R1R2R3和类似user:1user:2这样的表示用户的多个key对既定的key有多种不同方式来选择这个key存放在哪个实例中。也就是说有不同的系统来映射某个key到某个Redis服务。
### 范围分区
最简单的分区方式是按范围分区就是映射一定范围的对象到特定的Redis实例。
比如ID从0到10000的用户会保存到实例R0ID从10001到 20000的用户会保存到R1以此类推。
这种方式是可行的,并且在实际中使用,不足就是要有一个区间范围到实例的映射表。这个表要被管理,同时还需要各 种对象的映射表通常对Redis来说并非是好的方法。
### 哈希分区
另外一种分区方法是hash分区。这对任何key都适用也无需是object_name:这种形式,像下面描述的一样简单:
- 用一个hash函数将key转换为一个数字比如使用crc32 hash函数。对key foobar执行crc32(foobar)会输出类似93024922的整数。
- 对这个整数取模将其转化为0-3之间的数字就可以将这个整数映射到4个Redis实例中的一个了。93024922 % 4 = 2就是说key foobar应该被存到R2实例中。注意取模操作是取除的余数通常在多种编程语言中用%操作符实现。

@ -0,0 +1,8 @@
Redis的ziplist是一个紧凑的字节数组结构每个元素之间都是紧挨着。
![[Snipaste_2023-02-24_14-42-21 1.png]]
+ 如果存储的是hash结构那么key和value会作为两个entry被相邻存储
+ 如果是zsetvalue和score会作为两个entry被相邻存储
+ 如果set里存储的是字符串那么sadd会升级为hashtable结构HashSet
# 存储界限

@ -0,0 +1,37 @@
# 一、介绍
可以把布隆过滤器理解为一个不怎么精确的set结构。当布隆过滤器判定某个值存在时这个值可能不存在当判定某个值不存在时那肯定不存在。误判率大约为1%左右。
# 二、使用方法及注意事项
| 命令 | 用途 |
| ---------- | ------------------------ |
| bf.add | 添加元素 |
| bf.exists | 判断元素是否存在 |
| bf.madd | 批量添加元素 |
| bf.mexists | 一次查询多个元素是否存在 |
![[Snipaste_2023-02-23_17-24-34 12.png]]
## 显示创建布隆过滤器
先说为什么需要显示创建redis提供的默认设置错误率为0.01、预计放入的元素量为100实际使用中我们的元素肯定不止100个所以需要自定义创建并且对于错误率的容忍度也不一样。
redis提供了bf.reserver命令格式如下 bf.reserver key error_rate initial_size
error_rate错误率错误率越低需要的空间越大
initial_size预计放入的元素数量当实际数量超出这个数值时误判率会上升所以需要提前设置一个较大的数值避免超出导致误判率升高
![[Snipaste_2023-02-23_17-24-34 13.png]]
# 三、原理
布隆过滤器对应到Redis的数据结构里面就是一个大型的位数组和几个不一样的无偏hash函数。所谓无偏就是能够把元素的hash值算的比较均匀让元素被hash映射到位数组中的位置比较随机。
![[Snipaste_2023-02-24_09-52-40.png]]
## 3.1 添加Key
会使用多个hash函数对Key进行Hash算得一个整数索引值然后对位数组长度进行取模得到一个下标每个hash函数都会算的一个不同的下标。再把位数组的对应下标置为1就完成了添加操作。
## 3.2 判断Key是否存在
和添加操作一样先根据Hash计算下标然后与位数组中这几个位置对比是否为1只要有一个为0那么说明Key不存在。如果都是1只能说明key可能存在因为这些位置被置为1可能是因为其他key存在导致的。
自定义布隆的initial_size参数与位数组长度有关如果位数组比较稀疏判断正确的概率就会很大如果位数组比较拥挤判断正确的概率就会降低。
## 3.3 空间占用率估计
布隆有两个参数预计元素的数量m错误率f。公式根据这两个输入得到两个输出第一个输出是位数组长度l第二个是hash函数的最佳数量k
k=0.7*(l/n)
f=0.6185^(l/n) ^表示次方计算就是math.pow
# 四、FAQ
1. 为什么使用布隆过滤器而不是直接使用set
因为set中会存储每个元素的内容而布隆过滤器仅仅存储元素的指纹
2. 如果redis不支持布隆过滤器怎么办
python 版本 pyreBloomjava版本 orestes-bloomfilter或者hutool中提供的bloomfilter

@ -0,0 +1,15 @@
# 一、介绍
redis的持久化机制有2种第一种是快照第二种是AOF日志。快照是一次全量备份AOF日志是增量备份。
快照是内存数据的二进制序列化形式在存储上非常紧凑AOF日志记录的是内存数据修改的指令记录文本。AOF日志在长期的运行种会变得很大如果重启时需要加载AOF日志重放耗时很长所以需要定期进行AOF重写给日志瘦身。
# 二、实现原理
## 2.1 快照原理
由于redis是单线程程序为了持久化时不阻塞服务使用了多进程COWcopy on write机制实现快照功能。
在持久化时会调用glibc的函数forkfork/join机制产生一个子进程快照持久化完全由子进程处理父进程继续处理客户端请求。
子进程刚刚产生时,它和父进程共享内存里面的代码和数据段。子进程做数据持久化,不会修改现有的内存数据结构,它只是对数据结构进行遍历读取,然后序列化写入磁盘,此时的父进程还在处理客户端请求,也就是说**同一时间,父子进程的数据是有差异的**。
COW机制进行数据段页面分离当父进程对其中一个页面page的数据进行修改时会将被共享的页面**复制**一份,然后父进程对这个复制的页修改。子进程相应的页是没有变化的,还是进程产生那一瞬间的数据。
## 2.2 AOF原理
AOF存储的是Redis服务器的顺序指令序列AOF日志只记录对内存进行修改的指令记录
当收到客户端修改指令后进行参数校验、逻辑处理如果没问题就将该指令写入AOF日志先执行指令再存盘
# 三、如何使用
一般情况下不会单独使用上述两种方案都是结合起来使用称之为混合持久化。当重启时先加载快照内容然后再重放增量AOF日志。
混合持久化中将快照(rdb)文件的内容和增量AOF日志文件存在一起这里的AOF日志不再是全量的日志而是自持久化开始到结束这段时间内发生的增量操作日志所以这部分AOF日志很小。

@ -0,0 +1,26 @@
# 一、介绍
管道是由客户端提供的一种加快存取效率的技术。
如图所示客户端将请求发给服务器需要进过2个操作写->读,如果是多个操作就变成写->读->写->读
![[Snipaste_2023-02-24_09-52-40 1.png]]
此时如果调整读写顺序,变成写->写->读->读,两个连续的写操作和两个连续的读操作总共只会花费一次网络来回。
管道的本质就是改变读写操作顺序来节省IO时间。管道中指令越多效果越好。
# 二、管道原理
![[Snipaste_2023-02-24_09-52-40 2.png]]
1. 客户段进程调用write将消息写到socket的send buffer中
2. 客户端操作系统将发送缓冲的内容发送到网卡,网卡将数据通过路由送到服务器网卡
3. 服务器操作系统将网卡内容放到socket的recv buffer中
4. 服务器进程调用read从接收缓冲中读取消息进行处理
5. 服务器进程调用write将响应消息写入到socket的send buffer中
6. 服务器操作系统将发送缓冲的内容发送到网卡,网卡将数据通过路由送到客户端网卡
7. 客户端器操作系统将网卡内容放到socket的recv buffer中
8. 客户端进程调用read从接收缓冲中读取消息进行处理
9. 结束
5~8和1~4步骤一样方向不同。一个是请求一个是响应。
重点write操作只负责将数据写到send buffer就返回了剩下的事情由操作系统处理。对于redis.get(key)来说write操作几乎没有耗时直接写到发送缓冲就返回而read需要走完上述的流程。
对于管道来说连续的write操作根本没有耗时之后的第一个read操作会等待一个网络的来回开销然后所有的响应消息就已经回到了recv buffer后续的read操作就直接从recv buffer拿结果即可。
如果send buffer满了那么就需要等待缓冲空出空间来这就是写操作IO的真正耗时。

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save