auto commit
This commit is contained in:
165
notes/Redis.md
165
notes/Redis.md
@ -1,51 +1,25 @@
|
||||
# Redis
|
||||
<!-- GFM-TOC -->
|
||||
* [一、概述](#一概述)
|
||||
* [二、数据类型](#二数据类型)
|
||||
* [STRING](#string)
|
||||
* [LIST](#list)
|
||||
* [SET](#set)
|
||||
* [HASH](#hash)
|
||||
* [ZSET](#zset)
|
||||
* [三、数据结构](#三数据结构)
|
||||
* [字典](#字典)
|
||||
* [跳跃表](#跳跃表)
|
||||
* [四、使用场景](#四使用场景)
|
||||
* [计数器](#计数器)
|
||||
* [缓存](#缓存)
|
||||
* [查找表](#查找表)
|
||||
* [消息队列](#消息队列)
|
||||
* [会话缓存](#会话缓存)
|
||||
* [分布式锁实现](#分布式锁实现)
|
||||
* [其它](#其它)
|
||||
* [五、Redis 与 Memcached](#五redis-与-memcached)
|
||||
* [数据类型](#数据类型)
|
||||
* [数据持久化](#数据持久化)
|
||||
* [分布式](#分布式)
|
||||
* [内存管理机制](#内存管理机制)
|
||||
* [六、键的过期时间](#六键的过期时间)
|
||||
* [七、数据淘汰策略](#七数据淘汰策略)
|
||||
* [八、持久化](#八持久化)
|
||||
* [RDB 持久化](#rdb-持久化)
|
||||
* [AOF 持久化](#aof-持久化)
|
||||
* [九、事务](#九事务)
|
||||
* [十、事件](#十事件)
|
||||
* [文件事件](#文件事件)
|
||||
* [时间事件](#时间事件)
|
||||
* [事件的调度与执行](#事件的调度与执行)
|
||||
* [十一、复制](#十一复制)
|
||||
* [连接过程](#连接过程)
|
||||
* [主从链](#主从链)
|
||||
* [十二、Sentinel](#十二sentinel)
|
||||
* [十三、分片](#十三分片)
|
||||
* [十四、一个简单的论坛系统分析](#十四一个简单的论坛系统分析)
|
||||
* [文章信息](#文章信息)
|
||||
* [点赞功能](#点赞功能)
|
||||
* [对文章进行排序](#对文章进行排序)
|
||||
* [参考资料](#参考资料)
|
||||
* [Redis](#redis)
|
||||
* [一、概述](#一概述)
|
||||
* [二、数据类型](#二数据类型)
|
||||
* [三、数据结构](#三数据结构)
|
||||
* [四、使用场景](#四使用场景)
|
||||
* [五、Redis 与 Memcached](#五redis-与-memcached)
|
||||
* [六、键的过期时间](#六键的过期时间)
|
||||
* [七、数据淘汰策略](#七数据淘汰策略)
|
||||
* [八、持久化](#八持久化)
|
||||
* [九、事务](#九事务)
|
||||
* [十、事件](#十事件)
|
||||
* [十一、复制](#十一复制)
|
||||
* [十二、Sentinel](#十二sentinel)
|
||||
* [十三、分片](#十三分片)
|
||||
* [十四、一个简单的论坛系统分析](#十四一个简单的论坛系统分析)
|
||||
* [参考资料](#参考资料)
|
||||
<!-- GFM-TOC -->
|
||||
|
||||
|
||||
# 一、概述
|
||||
## 一、概述
|
||||
|
||||
Redis 是速度非常快的非关系型(NoSQL)内存键值数据库,可以存储键和五种不同类型的值之间的映射。
|
||||
|
||||
@ -53,19 +27,19 @@ Redis 是速度非常快的非关系型(NoSQL)内存键值数据库,可以
|
||||
|
||||
Redis 支持很多特性,例如将内存中的数据持久化到硬盘中,使用复制来扩展读性能,使用分片来扩展写性能。
|
||||
|
||||
# 二、数据类型
|
||||
## 二、数据类型
|
||||
|
||||
| 数据类型 | 可以存储的值 | 操作 |
|
||||
| :--: | :--: | :--: |
|
||||
| STRING | 字符串、整数或者浮点数 | 对整个字符串或者字符串的其中一部分执行操作</br> 对整数和浮点数执行自增或者自减操作 |
|
||||
| LIST | 列表 | 从两端压入或者弹出元素 </br> 对单个或者多个元素进行修剪,</br> 只保留一个范围内的元素 |
|
||||
| SET | 无序集合 | 添加、获取、移除单个元素</br> 检查一个元素是否存在于集合中</br> 计算交集、并集、差集</br> 从集合里面随机获取元素 |
|
||||
| HASH | 包含键值对的无序散列表 | 添加、获取、移除单个键值对</br> 获取所有键值对</br> 检查某个键是否存在|
|
||||
| ZSET | 有序集合 | 添加、获取、删除元素</br> 根据分值范围或者成员来获取元素</br> 计算一个键的排名 |
|
||||
| STRING | 字符串、整数或者浮点数 | 对整个字符串或者字符串的其中一部分执行操作\</br\> 对整数和浮点数执行自增或者自减操作 |
|
||||
| LIST | 列表 | 从两端压入或者弹出元素 \</br\> 对单个或者多个元素进行修剪,\</br\> 只保留一个范围内的元素 |
|
||||
| SET | 无序集合 | 添加、获取、移除单个元素\</br\> 检查一个元素是否存在于集合中\</br\> 计算交集、并集、差集\</br\> 从集合里面随机获取元素 |
|
||||
| HASH | 包含键值对的无序散列表 | 添加、获取、移除单个键值对\</br\> 获取所有键值对\</br\> 检查某个键是否存在|
|
||||
| ZSET | 有序集合 | 添加、获取、删除元素\</br\> 根据分值范围或者成员来获取元素\</br\> 计算一个键的排名 |
|
||||
|
||||
> [What Redis data structures look like](https://redislabs.com/ebook/part-1-getting-started/chapter-1-getting-to-know-redis/1-2-what-redis-data-structures-look-like/)
|
||||
\> [What Redis data structures look like](https://redislabs.com/ebook/part-1-getting-started/chapter-1-getting-to-know-redis/1-2-what-redis-data-structures-look-like/)
|
||||
|
||||
## STRING
|
||||
### STRING
|
||||
|
||||
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/6019b2db-bc3e-4408-b6d8-96025f4481d6.png" width="400"/> </div><br>
|
||||
|
||||
@ -80,7 +54,7 @@ OK
|
||||
(nil)
|
||||
```
|
||||
|
||||
## LIST
|
||||
### LIST
|
||||
|
||||
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/fb327611-7e2b-4f2f-9f5b-38592d408f07.png" width="400"/> </div><br>
|
||||
|
||||
@ -108,7 +82,7 @@ OK
|
||||
2) "item"
|
||||
```
|
||||
|
||||
## SET
|
||||
### SET
|
||||
|
||||
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/cd5fbcff-3f35-43a6-8ffa-082a93ce0f0e.png" width="400"/> </div><br>
|
||||
|
||||
@ -142,7 +116,7 @@ OK
|
||||
2) "item3"
|
||||
```
|
||||
|
||||
## HASH
|
||||
### HASH
|
||||
|
||||
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/7bd202a7-93d4-4f3a-a878-af68ae25539a.png" width="400"/> </div><br>
|
||||
|
||||
@ -173,7 +147,7 @@ OK
|
||||
2) "value1"
|
||||
```
|
||||
|
||||
## ZSET
|
||||
### ZSET
|
||||
|
||||
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1202b2d6-9469-4251-bd47-ca6034fb6116.png" width="400"/> </div><br>
|
||||
|
||||
@ -205,9 +179,9 @@ OK
|
||||
2) "982"
|
||||
```
|
||||
|
||||
# 三、数据结构
|
||||
## 三、数据结构
|
||||
|
||||
## 字典
|
||||
### 字典
|
||||
|
||||
dictht 是一个散列表结构,使用拉链法解决哈希冲突。
|
||||
|
||||
@ -311,7 +285,7 @@ int dictRehash(dict *d, int n) {
|
||||
}
|
||||
```
|
||||
|
||||
## 跳跃表
|
||||
### 跳跃表
|
||||
|
||||
是有序集合的底层实现之一。
|
||||
|
||||
@ -329,79 +303,79 @@ int dictRehash(dict *d, int n) {
|
||||
- 更容易实现;
|
||||
- 支持无锁操作。
|
||||
|
||||
# 四、使用场景
|
||||
## 四、使用场景
|
||||
|
||||
## 计数器
|
||||
### 计数器
|
||||
|
||||
可以对 String 进行自增自减运算,从而实现计数器功能。
|
||||
|
||||
Redis 这种内存型数据库的读写性能非常高,很适合存储频繁读写的计数量。
|
||||
|
||||
## 缓存
|
||||
### 缓存
|
||||
|
||||
将热点数据放到内存中,设置内存的最大使用量以及淘汰策略来保证缓存的命中率。
|
||||
|
||||
## 查找表
|
||||
### 查找表
|
||||
|
||||
例如 DNS 记录就很适合使用 Redis 进行存储。
|
||||
|
||||
查找表和缓存类似,也是利用了 Redis 快速的查找特性。但是查找表的内容不能失效,而缓存的内容可以失效,因为缓存不作为可靠的数据来源。
|
||||
|
||||
## 消息队列
|
||||
### 消息队列
|
||||
|
||||
List 是一个双向链表,可以通过 lpush 和 rpop 写入和读取消息
|
||||
|
||||
不过最好使用 Kafka、RabbitMQ 等消息中间件。
|
||||
|
||||
## 会话缓存
|
||||
### 会话缓存
|
||||
|
||||
可以使用 Redis 来统一存储多台应用服务器的会话信息。
|
||||
|
||||
当应用服务器不再存储用户的会话信息,也就不再具有状态,一个用户可以请求任意一个应用服务器,从而更容易实现高可用性以及可伸缩性。
|
||||
|
||||
## 分布式锁实现
|
||||
### 分布式锁实现
|
||||
|
||||
在分布式场景下,无法使用单机环境下的锁来对多个节点上的进程进行同步。
|
||||
|
||||
可以使用 Redis 自带的 SETNX 命令实现分布式锁,除此之外,还可以使用官方提供的 RedLock 分布式锁实现。
|
||||
|
||||
## 其它
|
||||
### 其它
|
||||
|
||||
Set 可以实现交集、并集等操作,从而实现共同好友等功能。
|
||||
|
||||
ZSet 可以实现有序性操作,从而实现排行榜等功能。
|
||||
|
||||
# 五、Redis 与 Memcached
|
||||
## 五、Redis 与 Memcached
|
||||
|
||||
两者都是非关系型内存键值数据库,主要有以下不同:
|
||||
|
||||
## 数据类型
|
||||
### 数据类型
|
||||
|
||||
Memcached 仅支持字符串类型,而 Redis 支持五种不同的数据类型,可以更灵活地解决问题。
|
||||
|
||||
## 数据持久化
|
||||
### 数据持久化
|
||||
|
||||
Redis 支持两种持久化策略:RDB 快照和 AOF 日志,而 Memcached 不支持持久化。
|
||||
|
||||
## 分布式
|
||||
### 分布式
|
||||
|
||||
Memcached 不支持分布式,只能通过在客户端使用一致性哈希来实现分布式存储,这种方式在存储和查询时都需要先在客户端计算一次数据所在的节点。
|
||||
|
||||
Redis Cluster 实现了分布式的支持。
|
||||
|
||||
## 内存管理机制
|
||||
### 内存管理机制
|
||||
|
||||
- 在 Redis 中,并不是所有数据都一直存储在内存中,可以将一些很久没用的 value 交换到磁盘,而 Memcached 的数据则会一直在内存中。
|
||||
|
||||
- Memcached 将内存分割成特定长度的块来存储数据,以完全解决内存碎片的问题。但是这种方式会使得内存的利用率不高,例如块的大小为 128 bytes,只存储 100 bytes 的数据,那么剩下的 28 bytes 就浪费掉了。
|
||||
|
||||
# 六、键的过期时间
|
||||
## 六、键的过期时间
|
||||
|
||||
Redis 可以为每个键设置过期时间,当键过期时,会自动删除该键。
|
||||
|
||||
对于散列表这种容器,只能为整个键设置过期时间(整个散列表),而不能为键里面的单个元素设置过期时间。
|
||||
|
||||
# 七、数据淘汰策略
|
||||
## 七、数据淘汰策略
|
||||
|
||||
可以设置内存最大使用量,当内存使用量超出时,会施行数据淘汰策略。
|
||||
|
||||
@ -422,11 +396,11 @@ Redis 具体有 6 种淘汰策略:
|
||||
|
||||
Redis 4.0 引入了 volatile-lfu 和 allkeys-lfu 淘汰策略,LFU 策略通过统计访问频率,将访问频率最少的键值对淘汰。
|
||||
|
||||
# 八、持久化
|
||||
## 八、持久化
|
||||
|
||||
Redis 是内存型数据库,为了保证数据在断电后不会丢失,需要将内存中的数据持久化到硬盘上。
|
||||
|
||||
## RDB 持久化
|
||||
### RDB 持久化
|
||||
|
||||
将某个时间点的所有数据都存放到硬盘上。
|
||||
|
||||
@ -436,7 +410,7 @@ Redis 是内存型数据库,为了保证数据在断电后不会丢失,需
|
||||
|
||||
如果数据量很大,保存快照的时间会很长。
|
||||
|
||||
## AOF 持久化
|
||||
### AOF 持久化
|
||||
|
||||
将写命令添加到 AOF 文件(Append Only File)的末尾。
|
||||
|
||||
@ -454,7 +428,7 @@ Redis 是内存型数据库,为了保证数据在断电后不会丢失,需
|
||||
|
||||
随着服务器写请求的增多,AOF 文件会越来越大。Redis 提供了一种将 AOF 重写的特性,能够去除 AOF 文件中的冗余写命令。
|
||||
|
||||
# 九、事务
|
||||
## 九、事务
|
||||
|
||||
一个事务包含了多个命令,服务器在执行事务期间,不会改去执行其它客户端的命令请求。
|
||||
|
||||
@ -462,11 +436,11 @@ Redis 是内存型数据库,为了保证数据在断电后不会丢失,需
|
||||
|
||||
Redis 最简单的事务实现方式是使用 MULTI 和 EXEC 命令将事务操作包围起来。
|
||||
|
||||
# 十、事件
|
||||
## 十、事件
|
||||
|
||||
Redis 服务器是一个事件驱动程序。
|
||||
|
||||
## 文件事件
|
||||
### 文件事件
|
||||
|
||||
服务器通过套接字与客户端或者其它服务器进行通信,文件事件就是对套接字操作的抽象。
|
||||
|
||||
@ -474,7 +448,7 @@ Redis 基于 Reactor 模式开发了自己的网络事件处理器,使用 I/O
|
||||
|
||||
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/9ea86eb5-000a-4281-b948-7b567bd6f1d8.png" width=""/> </div><br>
|
||||
|
||||
## 时间事件
|
||||
### 时间事件
|
||||
|
||||
服务器有一些操作需要在给定的时间点执行,时间事件是对这类定时操作的抽象。
|
||||
|
||||
@ -485,7 +459,7 @@ Redis 基于 Reactor 模式开发了自己的网络事件处理器,使用 I/O
|
||||
|
||||
Redis 将所有时间事件都放在一个无序链表中,通过遍历整个链表查找出已到达的时间事件,并调用相应的事件处理器。
|
||||
|
||||
## 事件的调度与执行
|
||||
### 事件的调度与执行
|
||||
|
||||
服务器需要不断监听文件事件的套接字才能得到待处理的文件事件,但是不能一直监听,否则时间事件无法在规定的时间内执行,因此监听时间应该根据距离现在最近的时间事件来决定。
|
||||
|
||||
@ -527,13 +501,13 @@ def main():
|
||||
|
||||
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/c0a9fa91-da2e-4892-8c9f-80206a6f7047.png" width="350"/> </div><br>
|
||||
|
||||
# 十一、复制
|
||||
## 十一、复制
|
||||
|
||||
通过使用 slaveof host port 命令来让一个服务器成为另一个服务器的从服务器。
|
||||
|
||||
一个从服务器只能有一个主服务器,并且不支持主主复制。
|
||||
|
||||
## 连接过程
|
||||
### 连接过程
|
||||
|
||||
1. 主服务器创建快照文件,发送给从服务器,并在发送期间使用缓冲区记录执行的写命令。快照文件发送完毕之后,开始向从服务器发送存储在缓冲区中的写命令;
|
||||
|
||||
@ -541,17 +515,17 @@ def main():
|
||||
|
||||
3. 主服务器每执行一次写命令,就向从服务器发送相同的写命令。
|
||||
|
||||
## 主从链
|
||||
### 主从链
|
||||
|
||||
随着负载不断上升,主服务器可能无法很快地更新所有从服务器,或者重新连接和重新同步从服务器将导致系统超载。为了解决这个问题,可以创建一个中间层来分担主服务器的复制工作。中间层的服务器是最上层服务器的从服务器,又是最下层服务器的主服务器。
|
||||
|
||||
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/395a9e83-b1a1-4a1d-b170-d081e7bb5bab.png" width="600"/> </div><br>
|
||||
|
||||
# 十二、Sentinel
|
||||
## 十二、Sentinel
|
||||
|
||||
Sentinel(哨兵)可以监听集群中的服务器,并在主服务器进入下线状态时,自动从从服务器中选举出新的主服务器。
|
||||
|
||||
# 十三、分片
|
||||
## 十三、分片
|
||||
|
||||
分片是将数据划分为多个部分的方法,可以将数据存储到多台机器里面,这种方法在解决某些问题时可以获得线性级别的性能提升。
|
||||
|
||||
@ -566,7 +540,7 @@ Sentinel(哨兵)可以监听集群中的服务器,并在主服务器进入
|
||||
- 代理分片:将客户端请求发送到代理上,由代理转发请求到正确的节点上。
|
||||
- 服务器分片:Redis Cluster。
|
||||
|
||||
# 十四、一个简单的论坛系统分析
|
||||
## 十四、一个简单的论坛系统分析
|
||||
|
||||
该论坛系统功能如下:
|
||||
|
||||
@ -574,7 +548,7 @@ Sentinel(哨兵)可以监听集群中的服务器,并在主服务器进入
|
||||
- 可以对文章进行点赞;
|
||||
- 在首页可以按文章的发布时间或者文章的点赞数进行排序显示。
|
||||
|
||||
## 文章信息
|
||||
### 文章信息
|
||||
|
||||
文章包括标题、作者、赞数等信息,在关系型数据库中很容易构建一张表来存储这些信息,在 Redis 中可以使用 HASH 来存储每种信息以及其对应的值的映射。
|
||||
|
||||
@ -582,7 +556,7 @@ Redis 没有关系型数据库中的表这一概念来将同种类型的数据
|
||||
|
||||
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/7c54de21-e2ff-402e-bc42-4037de1c1592.png" width="400"/> </div><br>
|
||||
|
||||
## 点赞功能
|
||||
### 点赞功能
|
||||
|
||||
当有用户为一篇文章点赞时,除了要对该文章的 votes 字段进行加 1 操作,还必须记录该用户已经对该文章进行了点赞,防止用户点赞次数超过 1。可以建立文章的已投票用户集合来进行记录。
|
||||
|
||||
@ -590,13 +564,13 @@ Redis 没有关系型数据库中的表这一概念来将同种类型的数据
|
||||
|
||||
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/485fdf34-ccf8-4185-97c6-17374ee719a0.png" width="400"/> </div><br>
|
||||
|
||||
## 对文章进行排序
|
||||
### 对文章进行排序
|
||||
|
||||
为了按发布时间和点赞数进行排序,可以建立一个文章发布时间的有序集合和一个文章点赞数的有序集合。(下图中的 score 就是这里所说的点赞数;下面所示的有序集合分值并不直接是时间和点赞数,而是根据时间和点赞数间接计算出来的)
|
||||
|
||||
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/f7d170a3-e446-4a64-ac2d-cb95028f81a8.png" width="800"/> </div><br>
|
||||
|
||||
# 参考资料
|
||||
## 参考资料
|
||||
|
||||
- Carlson J L. Redis in Action[J]. Media.johnwiley.com.au, 2013.
|
||||
- [黄健宏. Redis 设计与实现 [M]. 机械工业出版社, 2014.](http://redisbook.com/index.html)
|
||||
@ -606,10 +580,3 @@ Redis 没有关系型数据库中的表这一概念来将同种类型的数据
|
||||
- [Redis 3.0 中文版- 分片](http://wiki.jikexueyuan.com/project/redis-guide)
|
||||
- [Redis 应用场景](http://www.scienjus.com/redis-use-case/)
|
||||
- [Using Redis as an LRU cache](https://redis.io/topics/lru-cache)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-2.png"></img></div>
|
||||
|
Reference in New Issue
Block a user