update docs

pull/2/head
Zhang Peng 2020-07-13 17:03:42 +08:00
parent 9197969584
commit 463bef34f9
11 changed files with 288 additions and 469 deletions

View File

@ -56,16 +56,17 @@
> [Redis](docs/nosql/redis) 📚
![img](http://dunwu.test.upcdn.net/snap/20200713105627.png)
- [Redis 面试总结](docs/nosql/redis/redis-interview.md) 💯
- [Redis 入门指南](docs/nosql/redis/redis-quickstart.md) ⚡
- [Redis 入门指南](docs/nosql/redis/redis-quickstart.md) ⚡ - 关键词:`内存淘汰`、`事件`、`事务`、`管道`、`发布与订阅`
- [Redis 数据类型和应用](docs/nosql/redis/redis-datatype.md) - 关键词:`STRING`、`HASH`、`LIST`、`SET`、`ZSET`、`BitMap`、`HyperLogLog`、`Geo`
- [Redis 持久化](docs/nosql/redis/redis-persistence.md) - 关键词:`RDB`、`AOF`、`SAVE`、`BGSAVE`、`appendfsync`
- [Redis 复制](docs/nosql/redis/redis-replication.md) - 关键词:`SYNC`、`PSYNC`、`REPLCONF ACK`
- [Redis 复制](docs/nosql/redis/redis-replication.md) - 关键词:`SLAVEOF`、`SYNC`、`PSYNC`、`REPLCONF ACK`
- [Redis 哨兵](docs/nosql/redis/redis-sentinel.md) - 关键词:`Sentinel`、`PING`、`INFO`、`Raft`
- [Redis 集群](docs/nosql/redis/redis-cluster.md) - 关键词:`分片`、`虚拟 Hash 槽`
- [Redis 发布与订阅](docs/nosql/redis/redis-pub-sub.md)
- [Redis 集群](docs/nosql/redis/redis-cluster.md) - 关键词:`CLUSTER MEET`、`Hash slot`、`MOVED`、`ASK`、`SLAVEOF no one`、`redis-trib`
- [Redis 实战](docs/nosql/redis/redis-action.md) - 关键词:`缓存`、`分布式锁`、`布隆过滤器`
- [Redis 运维](docs/nosql/redis/redis-ops.md) 🔨
- [Redis 运维](docs/nosql/redis/redis-ops.md) 🔨 - 关键词:`安装`、`命令`、`集群`、`客户端`
#### Elasticsearch

Binary file not shown.

View File

@ -7,90 +7,43 @@ module.exports = {
base: "/db-tutorial/",
title: "DB-TUTORIAL",
description: "数据库教程",
head: [["link", { rel: "icon", href: `/favicon.ico` }]],
head: [["link", {rel: "icon", href: `/favicon.ico`}]],
markdown: {
externalLinks: {
target: "_blank",
rel: "noopener noreferrer"
target: "_blank", rel: "noopener noreferrer"
}
},
themeConfig: {
logo: "images/dunwu-logo-100.png",
repo: "dunwu/db-tutorial",
repoLabel: "Github",
docsDir: 'docs',
docsBranch: 'master',
docsDir: "docs",
docsBranch: "master",
editLinks: true,
smoothScroll: true,
locales: {
"/": {
label: "简体中文",
selectText: "Languages",
editLinkText: "帮助我们改善此页面!",
lastUpdated: "上次更新",
nav: [
{
text: "sql",
link: "/sql/",
items: [
{
text: "Mysql",
link: "/sql/mysql/"
}
]
},
{
text: "nosql",
link: "/nosql/",
items: [
{
text: "Redis",
link: "/nosql/redis/"
}
]
},
{
text: "🎯 博客",
link: "https://github.com/dunwu/blog",
target: "_blank",
rel: ""
}
],
sidebar: "auto",
sidebarDepth: 2
label: "简体中文", selectText: "Languages", editLinkText: "帮助我们改善此页面!", lastUpdated: "上次更新", nav: [{
text: "SQL", link: "/sql/"
}, {
text: "NOSQL", link: "/nosql/"
}, {
text: "Mysql", link: "/sql/mysql/"
}, {
text: "Redis", link: "/nosql/redis/"
}, {
text: "🎯 博客", link: "https://github.com/dunwu/blog", target: "_blank", rel: ""
}], sidebar: "auto", sidebarDepth: 2
}
}
},
plugins: [
['@vuepress/active-header-links', {
sidebarLinkSelector: '.sidebar-link',
headerAnchorSelector: '.header-anchor'
}],
["@vuepress/back-to-top", true],
[
"@vuepress/pwa",
{
serviceWorker: true,
updatePopup: true
}
],
["@vuepress/medium-zoom", true],
[
"container",
{
type: "vue",
before: '<pre class="vue-container"><code>',
after: "</code></pre>"
}
],
[
"container",
{
type: "upgrade",
before: info => `<UpgradePath title="${info}">`,
after: "</UpgradePath>"
}
],
["flowchart"]
]
plugins: [["@vuepress/active-header-links", {
sidebarLinkSelector: ".sidebar-link", headerAnchorSelector: ".header-anchor"
}], ["@vuepress/back-to-top", true], ["@vuepress/pwa", {
serviceWorker: true, updatePopup: true
}], ["@vuepress/medium-zoom", true], ["container", {
type: "vue", before: '<pre class="vue-container"><code>', after: "</code></pre>"
}], ["container", {
type: "upgrade", before: info => `<UpgradePath title="${info}">`, after: "</UpgradePath>"
}], ["flowchart"]]
};

View File

@ -47,15 +47,17 @@ footer: CC-BY-SA-4.0 Licensed | Copyright © 2018-Now Dunwu
> [Redis](nosql/redis) 📚
![img](http://dunwu.test.upcdn.net/snap/20200713105627.png)
- [Redis 面试总结](nosql/redis/redis-interview.md) 💯
- [Redis 入门指南](nosql/redis/redis-quickstart.md) ⚡
- [Redis 数据类型和应用](nosql/redis/redis-datatype.md)
- [Redis 持久化](nosql/redis/redis-persistence.md)
- [Redis 复制](nosql/redis/redis-replication.md)
- [Redis 哨兵](nosql/redis/redis-sentinel.md)
- [Redis 集群](nosql/redis/redis-cluster.md)
- [Redis 发布与订阅](nosql/redis/redis-pub-sub.md)
- [Redis 运维](nosql/redis/redis-ops.md) 🔨
- [Redis 入门指南](nosql/redis/redis-quickstart.md) ⚡ - 关键词:`内存淘汰`、`事件`、`事务`、`管道`、`发布与订阅`
- [Redis 数据类型和应用](nosql/redis/redis-datatype.md) - 关键词:`STRING`、`HASH`、`LIST`、`SET`、`ZSET`、`BitMap`、`HyperLogLog`、`Geo`
- [Redis 持久化](nosql/redis/redis-persistence.md) - 关键词:`RDB`、`AOF`、`SAVE`、`BGSAVE`、`appendfsync`
- [Redis 复制](nosql/redis/redis-replication.md) - 关键词:`SLAVEOF`、`SYNC`、`PSYNC`、`REPLCONF ACK`
- [Redis 哨兵](nosql/redis/redis-sentinel.md) - 关键词:`Sentinel`、`PING`、`INFO`、`Raft`
- [Redis 集群](nosql/redis/redis-cluster.md) - 关键词:`CLUSTER MEET`、`Hash slot`、`MOVED`、`ASK`、`SLAVEOF no one`、`redis-trib`
- [Redis 实战](nosql/redis/redis-action.md) - 关键词:`缓存`、`分布式锁`、`布隆过滤器`
- [Redis 运维](nosql/redis/redis-ops.md) 🔨 - 关键词:`安装`、`命令`、`集群`、`客户端`
#### Elasticsearch

View File

@ -12,16 +12,26 @@
### [Redis 入门指南 ⚡](redis-quickstart.md)
> 关键词:`内存淘汰`、`事件`、`事务`、`管道`、`发布与订阅`
![img](http://dunwu.test.upcdn.net/snap/20200713105627.png)
### [Redis 数据类型和应用](redis-datatype.md)
> 关键词:`STRING`、`HASH`、`LIST`、`SET`、`ZSET`、`BitMap`、`HyperLogLog`、`Geo`
![Redis 数据类型](http://dunwu.test.upcdn.net/snap/20200226113813.png)
### [Redis 持久化](redis-persistence.md)
> 关键词:`RDB`、`AOF`、`SAVE`、`BGSAVE`、`appendfsync`
![img](http://dunwu.test.upcdn.net/snap/20200224214047.png)
### [Redis 复制](redis-replication.md)
> 关键词:`SLAVEOF`、`SYNC`、`PSYNC`、`REPLCONF ACK`
![img](http://dunwu.test.upcdn.net/snap/20200712182603.png)
### [Redis 哨兵](redis-sentinel.md)
@ -29,15 +39,25 @@
> Redis 哨兵Sentinel是 Redis 的高可用性Hight Availability解决方案。
>
> Redis 哨兵是 Raft 算法 的具体实现。
>
> 关键词:`Sentinel`、`PING`、`INFO`、`Raft`
![img](http://dunwu.test.upcdn.net/snap/20200713072747.png)
### [Redis 集群](redis-cluster.md)
> 关键词:`CLUSTER MEET`、`Hash slot`、`MOVED`、`ASK`、`SLAVEOF no one`、`redis-trib`
![img](http://dunwu.test.upcdn.net/snap/20200713100613.png)
### [Redis 实战](redis-action.md)
> 关键词:`缓存`、`分布式锁`、`布隆过滤器`
### [Redis 运维 🔨](redis-ops.md)
> 关键词:`安装`、`命令`、`集群`、`客户端`
## 📚 资料
- **官网**

View File

@ -4,8 +4,10 @@
- [一、应用场景](#一应用场景)
- [缓存](#缓存)
- [布隆过滤器](#布隆过滤器)
- [BitMap 和 BloomFilter](#bitmap-和-bloomfilter)
- [分布式锁](#分布式锁)
- [二、技巧](#二技巧)
- [keys 和 scan](#keys-和-scan)
- [参考资料](#参考资料)
<!-- /TOC -->

View File

@ -12,18 +12,18 @@
<!-- TOC depthFrom:2 depthTo:3 -->
- [一、分区](#一分区)
- [一、Redis Cluster 分区](#一redis-cluster-分区)
- [集群节点](#集群节点)
- [分配 Hash 槽](#分配-hash-槽)
- [寻址](#寻址)
- [重新分片](#重新分片)
- [ASK 错误](#ask-错误)
- [二、故障转移](#二故障转移)
- [二、Redis Cluster 故障转移](#二redis-cluster-故障转移)
- [复制](#复制)
- [故障检测](#故障检测)
- [故障转移](#故障转移)
- [三、通信](#三通信)
- [四、应用](#四应用)
- [三、Redis Cluster 通信](#三redis-cluster-通信)
- [四、Redis Cluster 应用](#四redis-cluster-应用)
- [集群限制](#集群限制)
- [集群配置](#集群配置)
- [五、其他方案](#五其他方案)
@ -34,7 +34,7 @@
<!-- /TOC -->
## 一、分区
## 一、Redis Cluster 分区
### 集群节点
@ -118,7 +118,7 @@ Redis 集群的重新分片操作由 Redis 集群管理软件 **redis-trib** 负
![img](http://dunwu.test.upcdn.net/cs/database/redis/redis-ask.png)
## 二、故障转移
## 二、Redis Cluster 故障转移
### 复制
@ -147,7 +147,7 @@ Redis 复制机制可以参考:[Redis 复制](redis-replication.md)
Redis 集群选举新的主节点流程基于[共识算法Raft](https://www.jianshu.com/p/8e4bbe7e276c)
## 三、通信
## 三、Redis Cluster 通信
集群中的节点通过发送和接收消息来进行通信。
@ -159,7 +159,7 @@ Redis 集群节点发送的消息主要有以下五种:
- `FAIL` - 当一个主节点 A 判断另一个主节点 B 已经进入 FAIL 状态时,节点 A 会向集群广播一条关于节点 B 的 FAIL 消息,所有收到这条消息的节点都会立即将节点 B 标记为已下线。
- `PUBLISH` - 当节点收到一个 PUBLISH 命令时,节点会执行这个命令,并向集群广播一条 PUBLISH 消息,所有接受到这条消息的节点都会执行相同的 PUBLISH 命令。
## 四、应用
## 四、Redis Cluster 应用
### 集群限制

View File

@ -1,33 +1,50 @@
# Redis 面试总结
<!-- TOC depthFrom:2 depthTo:3 -->
- [Redis 数据类型](#redis-数据类型)
- [Redis 内存淘汰](#redis-内存淘汰)
- [Redis 持久化](#redis-持久化)
- [Redis 事务](#redis-事务)
- [Redis 管道](#redis-管道)
- [Redis 高并发](#redis-高并发)
- [Redis 复制](#redis-复制)
- [Redis 哨兵](#redis-哨兵)
- [Redis vs. Memcached](#redis-vs-memcached)
- [参考资料](#参考资料)
<!-- /TOC -->
## Redis 数据类型
问题:
【问题】
- Redis 数据类型有哪些?
- Redis 各种数据类型适用于什么样的场景?
- Redis 有哪些数据类型?
- Redis 的数据类型分别适用于什么样的场景?
---
解答:
【解答】
Redis 基本数据类型:
> **_Redis 数据类型和应用_**
>
> 数据类型的特性和应用细节点较多,详情可以参考:[Redis 数据类型](https://github.com/dunwu/db-tutorial/blob/master/docs/nosql/redis/redis-datatype.md)
| 数据类型 | 可以存储的值 | 操作 |
| -------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------- |
| STRING | 字符串、整数或者浮点数 | 对整个字符串或者字符串的其中一部分执行操作</br> 对整数和浮点数执行自增或者自减操作 |
| LIST | 列表 | 从两端压入或者弹出元素</br> 读取单个或者多个元素</br> 进行修剪,只保留一个范围内的元素 |
| SET | 无序集合 | 添加、获取、移除单个元素</br> 检查一个元素是否存在于集合中</br> 计算交集、并集、差集</br> 从集合里面随机获取元素 |
| HASH | 包含键值对的无序散列表 | 添加、获取、移除单个键值对</br> 获取所有键值对</br> 检查某个键是否存在 |
| ZSET | 有序集合 | 添加、获取、删除元素</br> 根据分值范围或者成员来获取元素</br> 计算一个键的排名 |
1Redis 支持五种基本数据类型:
Redis 各种数据类型的应用比较繁杂,详情可以参考:[Redis 数据类型](https://github.com/dunwu/db-tutorial/blob/master/docs/nosql/redis/redis-datatype.md)
- String常用于 KV 缓存
- Hash存储结构化数据产品信息、用户信息等。
- List存储列表粉丝列表、文章评论列表等。可以通过 lrange 命令进行分页查询。
- Set存储去重列表粉丝列表等。可以基于 set 玩儿交集、并集、差集的操作。例如:求两个人的共同好友列表。
- Sorted Set存储含评分的去重列表各种排行榜。
2除此以外还有 Bitmaps、HyperLogLogs、GEO、Streams 等高级数据类型。
## Redis 内存淘汰
问题:
【问题】
- Redis 有哪些淘汰策略?
- Redis 有哪些内存淘汰策略?
- 这些淘汰策略分别适用于什么场景?
- Redis 有哪些删除失效 key 的方法?
- 如何设置 Redis 中键的过期时间?
@ -35,9 +52,14 @@ Redis 各种数据类型的应用比较繁杂,详情可以参考:[Redis 数
---
解答:
【解答】
Redis 内存淘汰策略:
1Redis 过期策略是:**定期删除+惰性删除**。
- 消极方法passive way在主键被访问时如果发现它已经失效那么就删除它。
- 主动方法active way定期从设置了失效时间的主键中选择一部分失效的主键删除。
2Redis 内存淘汰策略:
- **`noeviction`** - 当内存使用达到阈值的时候,所有引起申请内存的命令会报错。这是 Redis 默认的策略。
- **`allkeys-lru`** - 在主键空间中,优先移除最近未使用的 key。
@ -46,27 +68,20 @@ Redis 内存淘汰策略:
- **`volatile-random`** - 在设置了过期时间的键空间中,随机移除某个 key。
- **`volatile-ttl`** - 在设置了过期时间的键空间中,具有更早过期时间的 key 优先移除。
如何选择内存淘汰策略:
3如何选择内存淘汰策略:
- 如果数据呈现幂等分布,也就是一部分数据访问频率高,一部分数据访问频率低,则使用 `allkeys-lru`
- 如果数据呈现平等分布,也就是所有的数据访问频率都相同,则使用 `allkeys-random`
- `volatile-lru` 策略和 `volatile-random` 策略适合我们将一个 Redis 实例既应用于缓存和又应用于持久化存储的时候,然而我们也可以通过使用两个 Redis 实例来达到相同的效果。
- 将 key 设置过期时间实际上会消耗更多的内存,因此我们建议使用 `allkeys-lru` 策略从而更有效率的使用内存。
Redis 删除失效主键的方法主要有两种:
- 消极方法passive way在主键被访问时如果发现它已经失效那么就删除它。
- 主动方法active way周期性地从设置了失效时间的主键中选择一部分失效的主键删除。
LRU 算法实现思路:
`HashMap` + `LinkedList`
4LRU 算法实现思路:可以继承 LinkedHashMap并覆写 removeEldestEntry 方法来实现一个最简单的 LRUCache
## Redis 持久化
问题:
【问题】
- Redis 有哪些持久化方式?
- Redis 有几种持久化方式?
- Redis 的不同持久化方式的特性和原理是什么?
- RDB 和 AOF 各有什么优缺点?分别适用于什么样的场景?
- Redis 执行持久化时,可以处理请求吗?
@ -74,122 +89,47 @@ LRU 算法实现思路:
---
解答:
【解答】
Redis 支持两种持久化方式RDB 和 AOF。
> **_Redis 持久化_**
>
> 详情可以参考:[Redis 持久化](redis-persistence.md)
RDB 即快照方式,它将某个时间点的所有 Redis 数据保存到一个经过压缩的二进制文件RDB 文件)中。
1Redis 支持两种持久化方式RDB 和 AOF
AOF(Append Only File) 是以文本日志形式将所有写命令追加到 AOF 文件的末尾,以此来记录数据的变化
2RDB 即某一时刻的二进制数据快照
更详细的特性及原理说明请参考:[Redis 持久化](https://github.com/dunwu/db-tutorial/blob/master/docs/nosql/redis/redis-persistence.md)
Redis 会周期性生成 RDB 文件。
## Redis 高并发
生成 RDB 流程Redis fork 一个子进程,负责生成 RDB生成 RDB 采用 Copy On Write 模式,此时,如果收到写请求,会在原副本上操作,不影响工作。
问题:
RDB 只能恢复生成快照时刻的数据,之后的数据无法恢复。生成 RDB 的资源开销高昂。RDB 适合做冷备。
- Redis 是单线程模型,为何吞吐量还很高?
- Redis 集群如何分片和寻址?
- Redis 集群如何扩展?
- Redis 集群如何保证数据一致?
- Redis 集群如何规划?你们公司的生产环境上如何部署 Redis 集群?
- Redis 的并发竞争问题如何解决?
3AOF 会将写命令不断追加到 AOF 文本日志末尾。
---
AOF 丢数据比 RDB 少,但文件会比 RDB 文件大很多。
解答:
一般AOF 设置 `appendfsync` 同步频率为 **`everysec`** 即可。
Redis 为单进程单线程模式,采用队列模式将并发访问变为串行访问。
4RDB or AOF
Redis 单机吞吐量也很高,能达到几万 QPS但需要格外注意的是**Redis 是单线程模型**。很多人可能会奇怪Redis 是单线程模型,如何能处理高并发请求呢?
原因在于:
- Redis 读写都是内存操作。
- Redis 基于**非阻塞的 IO 多路复用机制**,同时监听多个 socket将产生事件的 socket 压入内存队列中,事件分派器根据 socket 上的事件类型来选择对应的事件处理器进行处理。
- 单线程,避免了线程创建、销毁、上下文切换的开销,并且避免了资源竞争。
Redis 的高并发通过主从架构来实现。Redis 集群采用主从模型,提供复制和故障转移功能,来保证 Redis 集群的高可用。通常情况,一主多从模式已经可以满足大部分项目的需要。根据实际的并发量,可以通过增加节点来扩展并发吞吐。
一主多从模式下,主节点负责写操作(单机几万 QPS从节点负责查询操作单机十万 QPS
进一步如果需要缓存大量数据就需要分区shardingRedis 集群通过划分虚拟 hash 槽来分片,进行数据分享。
根据 CAP 理论Consistency、Availability、Partition tolerance 三者不可兼得,而 Redis 集群的选择是 AP。Redis 集群节点间采用异步通信方式,不保证强一致性,尽力达到最终一致性。
`Redis` 集群一般由 **多个节点** 组成,节点数量至少为 `6` 个,才能保证组成 **完整高可用** 的集群。
![img](https://user-gold-cdn.xitu.io/2019/10/10/16db5250b0d1c392?w=1467&h=803&f=png&s=43428)
更详细的特性及原理说明请参考:[Redis 集群](https://github.com/dunwu/db-tutorial/blob/master/docs/nosql/redis/redis-cluster.md)
## Redis 高可用
问题:
- Redis 如何实现高可用?
- Redis 哨兵的功能?
- Redis 哨兵的原理?
- Redis 哨兵如何选举 Leader
- Redis 如何实现故障转移?
---
解答:
Redis 的高可用是通过哨兵来实现Raft 协议的 Redis 实现。Sentinel哨兵可以监听主服务器并在主服务器进入下线状态时自动从从服务器中选举出新的主服务器。
由一个或多个 Sentinel 实例组成的 Sentinel 系统可以监视任意多个主服务器,以及这些主服务器的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器的某个从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求。
![img](http://dunwu.test.upcdn.net/snap/20200131135847.png)
更详细的特性及原理说明请参考:[Redis 哨兵](https://github.com/dunwu/db-tutorial/blob/master/docs/nosql/redis/redis-sentinel.md)
## Redis 复制
问题:
- Redis 复制的工作原理Redis 旧版复制和新版复制有何不同?
- Redis 主从节点间如何复制数据?
- Redis 的数据一致性是强一致性吗?
---
解答:
旧版复制基于 `SYNC` 命令实现。分为同步sync和命令传播command propagate两个操作。这种方式存在缺陷不能高效处理断线重连后的复制情况。
新版复制基于 `PSYNC` 命令实现。同步操作分为了两块:
- **`完整重同步full resychronization`** 用于初次复制;
- **`部分重同步partial resychronization`** 用于断线后重复制。
- 主从服务器的**复制偏移量replication offset**
- 主服务器的**复制积压缓冲区replication backlog**
- **服务器的运行 ID**
Redis 集群主从节点复制的工作流程:
- 步骤 1. 设置主从服务器
- 步骤 2. 主从服务器建立 TCP 连接。
- 步骤 3. 发送 PING 检查通信状态。
- 步骤 4. 身份验证。
- 步骤 5. 发送端口信息。
- 步骤 6. 同步。
- 步骤 7. 命令传播。
更详细的特性及原理说明请参考:[Redis 复制](https://github.com/dunwu/db-tutorial/blob/master/docs/nosql/redis/redis-replication.md)
建议同时使用 RDB 和 AOF。用 AOF 来保证数据不丢失,作为数据恢复的第一选择; 用 RDB 来做不同程度的冷备,在 AOF 文件都丢失或损坏不可用的时候,还可以使用 RDB 来进行快速的数据恢复。
## Redis 事务
问题:
【问题】
- Redis 的并发竞争问题是什么?如何解决这个问题?
- Redis 支持事务吗?
- Redis 事务是严格意义的事务吗Redis 为什么不支持回滚。
- Redis 事务如何工作?
- 了解 Redis 事务中的 CAS 行为吗?
- 除了事务,还有其他批量执行 Redis 命令的方式吗?
解答:
【解答】
> **_Redis 的事务特性、原理_**
>
> 详情参考:[Redis 入门指南之 事务](redis-quickstart.md#六redis-事务)
**Redis 提供的不是严格的事务Redis 只保证串行执行命令,并且能保证全部执行,但是执行命令失败时并不会回滚,而是会继续执行下去**。
@ -200,15 +140,135 @@ Redis 不支持回滚的理由:
`MULTI``EXEC``DISCARD``WATCH` 是 Redis 事务相关的命令。
- **[`MULTI`](https://redis.io/commands/multi) 命令用于开启一个事务,它总是返回 OK 。**
- **[`EXEC`](https://redis.io/commands/exec) 命令负责触发并执行事务中的所有命令。**
- **当执行 [`DISCARD`](https://redis.io/commands/discard) 命令时, 事务会被放弃, 事务队列会被清空, 并且客户端会从事务状态中退出。**
- **[`WATCH`](https://redis.io/commands/watch) 命令可以为 Redis 事务提供 check-and-set CAS行为。**被 WATCH 的键会被监视,并会发觉这些键是否被改动过了。 如果有至少一个被监视的键在 EXEC 执行之前被修改了, 那么整个事务都会被取消, EXEC 返回 nil-reply 来表示事务已经失败。
Redis 有天然解决这个并发竞争问题的类 CAS 乐观锁方案:每次要**写之前,先判断**一下当前这个 value 的时间戳是否比缓存里的 value 的时间戳要新。如果是的话,那么可以写,否则,就不能用旧的数据覆盖新的数据。
## Redis 管道
【问题】
- 除了事务,还有其他批量执行 Redis 命令的方式吗?
【解答】
Redis 是一种基于 C/S 模型以及请求/响应协议的 TCP 服务。Redis 支持管道技术。管道技术允许请求以异步方式发送即旧请求的应答还未返回的情况下允许发送新请求。这种方式可以大大提高传输效率。使用管道发送命令时Redis Server 会将部分请求放到缓存队列中(占用内存),执行完毕后一次性发送结果。如果需要发送大量的命令,会占用大量的内存,因此应该按照合理数量分批次的处理。
## Redis 高并发
【问题】
- Redis 是单线程模型,为何吞吐量还很高?
- Redis 的 IO 多路复用原理是什么?
- Redis 集群如何分片和寻址?
- Redis 集群如何扩展?
- Redis 集群如何保证数据一致?
- Redis 集群如何规划?你们公司的生产环境上如何部署 Redis 集群?
---
【解答】
> **_Redis 集群_**
>
> 详情可以参考:[Redis 集群](redis-cluster.md)
1单线程
Redis 为单进程单线程模式采用队列模式将并发访问变为串行访问。Redis 单机吞吐量也很高,能达到几万 QPS。
Redis 单线程模型,依然有很高的并发吞吐,原因在于:
- Redis 读写都是内存操作。
- Redis 基于**非阻塞的 IO 多路复用机制**,同时监听多个 socket将产生事件的 socket 压入内存队列中,事件分派器根据 socket 上的事件类型来选择对应的事件处理器进行处理。
- 单线程,避免了线程创建、销毁、上下文切换的开销,并且避免了资源竞争。
2扩展并发吞吐量、存储容量
Redis 的高性能(扩展并发吞吐量、存储容量)通过主从架构来实现。
Redis 集群采用主从模型,提供复制和故障转移功能,来保证 Redis 集群的高可用。通常情况,一主多从模式已经可以满足大部分项目的需要。根据实际的并发量,可以通过增加节点来扩展并发吞吐。
一主多从模式下,主节点负责写操作(单机几万 QPS从节点负责查询操作单机十万 QPS
进一步如果需要缓存大量数据就需要分区sharding。Redis 集群通过划分虚拟 hash 槽来分片,每个主节点负责一定范围的 hash 槽。当需要扩展集群节点时,重新分配 hash 槽即可redis-trib 会自动迁移变更 hash 槽中所属的 key。
3Redis 集群数据一致性
Redis 集群基于复制特性实现节点间的数据一致性。
## Redis 复制
【问题】
- Redis 复制的工作原理Redis 旧版复制和新版复制有何不同?
- Redis 主从节点间如何复制数据?
- Redis 的数据一致性是强一致性吗?
---
【解答】
> **_Redis 复制_**
>
> 详情可以参考:[Redis 复制](redis-replication.md)
1旧版复制基于 `SYNC` 命令实现。分为同步sync和命令传播command propagate两个操作。这种方式存在缺陷不能高效处理断线重连后的复制情况。
2新版复制基于 `PSYNC` 命令实现。同步操作分为了两块:
- **`完整重同步full resychronization`** 用于初次复制;
- **`部分重同步partial resychronization`** 用于断线后重复制。
- 主从服务器的**复制偏移量replication offset**
- 主服务器的**复制积压缓冲区replication backlog**
- **服务器的运行 ID**
3Redis 集群主从节点复制的工作流程:
- 步骤 1. 设置主从服务器
- 步骤 2. 主从服务器建立 TCP 连接。
- 步骤 3. 发送 PING 检查通信状态。
- 步骤 4. 身份验证。
- 步骤 5. 发送端口信息。
- 步骤 6. 同步。
- 步骤 7. 命令传播。
## Redis 哨兵
【问题】
- Redis 如何实现高可用?
- Redis 哨兵的功能?
- Redis 哨兵的原理?
- Redis 哨兵如何选举 Leader
- Redis 如何实现故障转移?
---
【解答】
> **_Redis 哨兵_**
>
> 详情可以参考:[Redis 哨兵](redis-sentinel.md)
1Redis 的高可用是通过哨兵来实现Raft 协议的 Redis 实现。Sentinel哨兵可以监听主服务器并在主服务器进入下线状态时自动从从服务器中选举出新的主服务器。
由一个或多个 Sentinel 实例组成的 Sentinel 系统可以监视任意多个主服务器,以及这些主服务器的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器的某个从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求。
![img](http://dunwu.test.upcdn.net/snap/20200131135847.png)
## Redis vs. Memcached
【问题】
Redis 和 Memcached 有什么区别?
分布式缓存技术选型,选 Redis 还是 Memcached为什么
Redis 和 Memcached 各自的线程模型是怎样的?
为什么单线程的 Redis 性能却不输于多线程的 Memcached
【解答】
Redis 不仅仅支持简单的 k/v 类型的数据,同时还提供 listsetzsethash 等数据结构的存储。memcache 支持简单的数据类型String。
Redis 支持数据的备份,即 master-slave 模式的数据备份。
@ -223,10 +283,9 @@ Memcached 是多线程,非阻塞 IO 复用的网络模型Redis 使用单线
如果想要更详细了解的话,可以查看慕课网上的这篇手记(非常推荐) **:《脚踏两只船的困惑 - Memcached 与 Redis》**[www.imooc.com/article/23549](https://www.imooc.com/article/23549)
### Redis 与 Memcached 的选择
**终极策略:** 使用 Redis 的 String 类型做的事,都可以用 Memcached 替换,以此换取更好的性能提升; 除此以外,优先考虑 Redis
## 参考资料
- [面试中关于 Redis 的问题看这篇就够了](https://juejin.im/post/5ad6e4066fb9a028d82c4b66)
- [advanced-java](https://github.com/doocs/advanced-java#缓存)

View File

@ -276,6 +276,19 @@ Redis 3.0 后支持集群模式。
理想情况当然是所有节点各自在不同的机器上,首先于资源,本人在部署 Redis 集群时,只得到 3 台服务器。所以,我计划每台服务器部署 2 个 Redis 节点。
【示例】最简高可用 Redis 集群规划
机器配置16G 内存 + 8 核 CPU + 1T 磁盘
Redis 进程分配 10 G 内存。一般线上生产环境Redis 的内存尽量不要超过 10g超过 10g 可能会有问题。
集群拓扑:三主三从;三哨兵,每个哨兵监听所有主节点。
估算性能:
- 容量:三主,占用 30 G 内存,所以最大存储容量为 30 G。假设每条数据记录平均 大小为 10 K则最大能存储 300 万条数据。
- 吞吐量:单机一般 TPS/QPS 为 五万到八万左右。假设为五万,那么三主三从架构理论上能达到 TPS 15 万QPS 30 万。
### 部署集群
> Redis 集群节点的安装与单节点服务相同,差异仅在于部署方式。

View File

@ -1,23 +0,0 @@
# Redis 发布与订阅
Redis 提供了 5 个发布与订阅命令:
| 命令 | 描述 |
| -------------- | ------------------------------------------------------------------- |
| `SUBSCRIBE` | `SUBSCRIBE channel [channel ...]`—订阅指定频道。 |
| `UNSUBSCRIBE` | `UNSUBSCRIBE [channel [channel ...]]`—取消订阅指定频道。 |
| `PUBLISH` | `PUBLISH channel message`—发送信息到指定的频道。 |
| `PSUBSCRIBE` | `PSUBSCRIBE pattern [pattern ...]`—订阅符合指定模式的频道。 |
| `PUNSUBSCRIBE` | `PUNSUBSCRIBE [pattern [pattern ...]]`—取消订阅符合指定模式的频道。 |
## 参考资料
- **官网**
- [Redis 官网](https://redis.io/)
- [Redis github](https://github.com/antirez/redis)
- [Redis 官方文档中文版](http://redis.cn/)
- **书籍**
- [《Redis 实战》](https://item.jd.com/11791607.html)
- [《Redis 设计与实现》](https://item.jd.com/11486101.html)
- **教程**
- [Redis 命令参考](http://redisdoc.com/)

View File

@ -113,228 +113,11 @@ Redis 是单线程模型Redis 6.0 已经支持多线程模型),为什么
## 二、Redis 数据类型
| 数据类型 | 可以存储的值 | 操作 |
| -------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------- |
| STRING | 字符串、整数或者浮点数 | 对整个字符串或者字符串的其中一部分执行操作</br> 对整数和浮点数执行自增或者自减操作 |
| LIST | 列表 | 从两端压入或者弹出元素</br> 读取单个或者多个元素</br> 进行修剪,只保留一个范围内的元素 |
| SET | 无序集合 | 添加、获取、移除单个元素</br> 检查一个元素是否存在于集合中</br> 计算交集、并集、差集</br> 从集合里面随机获取元素 |
| HASH | 包含键值对的无序散列表 | 添加、获取、移除单个键值对</br> 获取所有键值对</br> 检查某个键是否存在 |
| ZSET | 有序集合 | 添加、获取、删除元素</br> 根据分值范围或者成员来获取元素</br> 计算一个键的排名 |
Redis 基本数据类型STRING、HASH、LIST、SET、ZSET
> [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/)
Redis 高级数据类型BitMap、HyperLogLog、GEO
### STRING
<div align="center">
<img src="http://dunwu.test.upcdn.net/cs/database/redis/redis-datatype-string.png" width="400"/>
</div>
应用场景:缓存、计数器、共享 Session
命令:
| 命令 | 行为 |
| ----- | ---------------------------------------------------- |
| `GET` | 获取存储在给定键中的值。 |
| `SET` | 设置存储在给定键中的值。 |
| `DEL` | 删除存储在给定键中的值(这个命令可以用于所有类型)。 |
> 更多命令请参考:[Redis String 类型命令](https://redis.io/commands#string)
示例:
```shell
127.0.0.1:6379> set hello world
OK
127.0.0.1:6379> get hello
"jack"
127.0.0.1:6379> del hello
(integer) 1
127.0.0.1:6379> get hello
(nil)
```
### HASH
<div align="center">
<img src="http://dunwu.test.upcdn.net/cs/database/redis/redis-datatype-hash.png" width="400"/>
</div>
场景:适合存储结构化数据,如一个对象:用户信息、产品信息等。
命令:
| 命令 | 行为 |
| --------- | ------------------------------------------ |
| `HSET` | 在散列里面关联起给定的键值对。 |
| `HGET` | 获取指定散列键的值。 |
| `HGETALL` | 获取散列包含的所有键值对。 |
| `HDEL` | 如果给定键存在于散列里面,那么移除这个键。 |
> 更多命令请参考:[Redis Hash 类型命令](https://redis.io/commands#hash)
示例:
```shell
127.0.0.1:6379> hset hash-key sub-key1 value1
(integer) 1
127.0.0.1:6379> hset hash-key sub-key2 value2
(integer) 1
127.0.0.1:6379> hset hash-key sub-key1 value1
(integer) 0
127.0.0.1:6379> hset hash-key sub-key3 value2
(integer) 0
127.0.0.1:6379> hgetall hash-key
1) "sub-key1"
2) "value1"
3) "sub-key2"
4) "value2"
127.0.0.1:6379> hdel hash-key sub-key2
(integer) 1
127.0.0.1:6379> hdel hash-key sub-key2
(integer) 0
127.0.0.1:6379> hget hash-key sub-key1
"value1"
127.0.0.1:6379> hgetall hash-key
1) "sub-key1"
2) "value1"
```
### LIST
<div align="center">
<img src="http://dunwu.test.upcdn.net/cs/database/redis/redis-datatype-list.png" width="400"/>
</div>
适用场景:用于存储列表型数据。如:粉丝列表、商品列表等。
命令:
| 命令 | 行为 |
| -------- | ------------------------------------------ |
| `RPUSH` | 将给定值推入列表的右端。 |
| `LRANGE` | 获取列表在给定范围上的所有值。 |
| `LINDEX` | 获取列表在给定位置上的单个元素。 |
| `LPOP` | 从列表的左端弹出一个值,并返回被弹出的值。 |
> 更多命令请参考:[Redis List 类型命令](https://redis.io/commands#list)
示例:
```shell
127.0.0.1:6379> rpush list-key item
(integer) 1
127.0.0.1:6379> rpush list-key item2
(integer) 2
127.0.0.1:6379> rpush list-key item
(integer) 3
127.0.0.1:6379> lrange list-key 0 -1
1) "item"
2) "item2"
3) "item"
127.0.0.1:6379> lindex list-key 1
"item2"
127.0.0.1:6379> lpop list-key
"item"
127.0.0.1:6379> lrange list-key 0 -1
1) "item2"
2) "item"
```
### SET
<div align="center">
<img src="http://dunwu.test.upcdn.net/cs/database/redis/redis-datatype-set.png" width="400"/>
</div>
适用场景:适用于存储不出现重复的列表数据。
命令:
| 命令 | 行为 |
| ----------- | ---------------------------------------------- |
| `SADD` | 将给定元素添加到集合。 |
| `SMEMBERS` | 返回集合包含的所有元素。 |
| `SISMEMBER` | 检查给定元素是否存在于集合中。 |
| `SREM` | 如果给定的元素存在于集合中,那么移除这个元素。 |
> 更多命令请参考:[Redis Set 类型命令](https://redis.io/commands#set)
示例:
```shell
127.0.0.1:6379> sadd set-key item
(integer) 1
127.0.0.1:6379> sadd set-key item2
(integer) 1
127.0.0.1:6379> sadd set-key item3
(integer) 1
127.0.0.1:6379> sadd set-key item
(integer) 0
127.0.0.1:6379> smembers set-key
1) "item"
2) "item2"
3) "item3"
127.0.0.1:6379> sismember set-key item4
(integer) 0
127.0.0.1:6379> sismember set-key item
(integer) 1
127.0.0.1:6379> srem set-key item2
(integer) 1
127.0.0.1:6379> srem set-key item2
(integer) 0
127.0.0.1:6379> smembers set-key
1) "item"
2) "item3"
```
### ZSET
<div align="center">
<img src="http://dunwu.test.upcdn.net/cs/database/redis/redis-datatype-zset.png" width="400"/>
</div>
场景:由于可以设置 score且不重复。适合存储各种排行数据按评分排序的有序商品集合、按时间排序的有序文章集合。
命令:
| 命令 | 行为 |
| --------------- | ------------------------------------------------------------ |
| `ZADD` | 将一个带有给定分值的成员添加到有序集合里面。 |
| `ZRANGE` | 根据元素在有序排列中所处的位置,从有序集合里面获取多个元素。 |
| `ZRANGEBYSCORE` | 获取有序集合在给定分值范围内的所有元素。 |
| `ZREM` | 如果给定成员存在于有序集合,那么移除这个成员。 |
> 更多命令请参考:[Redis ZSet 类型命令](https://redis.io/commands#sorted_set)
示例:
```shell
127.0.0.1:6379> zadd zset-key 728 member1
(integer) 1
127.0.0.1:6379> zadd zset-key 982 member0
(integer) 1
127.0.0.1:6379> zadd zset-key 982 member0
(integer) 0
127.0.0.1:6379> zrange zset-key 0 -1 withscores
1) "member1"
2) "728"
3) "member0"
4) "982"
127.0.0.1:6379> zrangebyscore zset-key 0 800 withscores
1) "member1"
2) "728"
127.0.0.1:6379> zrem zset-key member1
(integer) 1
127.0.0.1:6379> zrem zset-key member1
(integer) 0
127.0.0.1:6379> zrange zset-key 0 -1 withscores
1) "member0"
2) "982"
```
> :bulb: 更详细的特性及原理说明请参考:[Redis 数据类型和应用](redis-datatype.md)
## 三、Redis 内存淘汰
@ -360,7 +143,7 @@ Redis 可以为每个键设置过期时间,当键过期时,会自动删除
示例:
```py
```shell
redis> SET mykey "Hello"
"OK"
redis> EXPIRE mykey 10
@ -410,7 +193,6 @@ Redis 是内存型数据库,为了保证数据在宕机后不会丢失,需
Redis 支持两种持久化方式RDB 和 AOF。
- RDB - **RDB 即快照方式,它将某个时间点的所有 Redis 数据保存到一个经过压缩的二进制文件RDB 文件)中**
- 创建 RDB 后,用户可以对 RDB 进行**备份**,可以将 RDB **复制**到其他服务器从而创建具有相同数据的服务器副本,还可以在**重启**服务器时使用。一句话来说RDB 适合作为 **冷备**。
- AOF - `AOF(Append Only File)` 是以文本日志形式将所有写命令追加到 AOF 文件的末尾以此来记录数据的变化。当服务器重启的时候会重新载入和执行这些命令来恢复原始的数据。AOF 适合作为 **热备**。
> :bulb: 更详细的特性及原理说明请参考:[Redis 持久化](redis-persistence.md)
@ -639,6 +421,16 @@ pipe.exec();
## 八、Redis 发布与订阅
Redis 提供了 5 个发布与订阅命令:
| 命令 | 描述 |
| -------------- | ------------------------------------------------------------ |
| `SUBSCRIBE` | `SUBSCRIBE channel [channel ...]`—订阅指定频道。 |
| `UNSUBSCRIBE` | `UNSUBSCRIBE [channel [channel ...]]`—取消订阅指定频道。 |
| `PUBLISH` | `PUBLISH channel message`—发送信息到指定的频道。 |
| `PSUBSCRIBE` | `PSUBSCRIBE pattern [pattern ...]`—订阅符合指定模式的频道。 |
| `PUNSUBSCRIBE` | `PUNSUBSCRIBE [pattern [pattern ...]]`—取消订阅符合指定模式的频道。 |
订阅者订阅了频道之后,发布者向频道发送字符串消息会被所有订阅者接收到。
某个客户端使用 SUBSCRIBE 订阅一个频道,其它客户端可以使用 PUBLISH 向这个频道发送消息。
@ -715,7 +507,7 @@ Sentinel哨兵可以监听主服务器并在主服务器进入下线状
- 代理分片:将客户端请求发送到代理上,由代理转发请求到正确的节点上。
- 服务器分片Redis Cluster官方的 Redis 集群解决方案)。
## Redis Client
## 十二、Redis Client
Redis 社区中有多种编程语言的客户端,可以在这里查找合适的客户端:[Redis 官方罗列的客户端清单](https://redis.io/clients)