mirror of https://github.com/dunwu/db-tutorial.git
update docs
parent
9197969584
commit
463bef34f9
11
README.md
11
README.md
|
@ -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.
|
@ -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"]]
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
> 关键词:`安装`、`命令`、`集群`、`客户端`
|
||||
|
||||
## 📚 资料
|
||||
|
||||
- **官网**
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
|
||||
- [一、应用场景](#一应用场景)
|
||||
- [缓存](#缓存)
|
||||
- [布隆过滤器](#布隆过滤器)
|
||||
- [BitMap 和 BloomFilter](#bitmap-和-bloomfilter)
|
||||
- [分布式锁](#分布式锁)
|
||||
- [二、技巧](#二技巧)
|
||||
- [keys 和 scan](#keys-和-scan)
|
||||
- [参考资料](#参考资料)
|
||||
|
||||
<!-- /TOC -->
|
||||
|
|
|
@ -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 应用
|
||||
|
||||
### 集群限制
|
||||
|
||||
|
|
|
@ -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> 计算一个键的排名 |
|
||||
(1)Redis 支持五种基本数据类型:
|
||||
|
||||
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 内存淘汰策略:
|
||||
(1)Redis 过期策略是:**定期删除+惰性删除**。
|
||||
|
||||
- 消极方法(passive way),在主键被访问时如果发现它已经失效,那么就删除它。
|
||||
- 主动方法(active way),定期从设置了失效时间的主键中选择一部分失效的主键删除。
|
||||
|
||||
(2)Redis 内存淘汰策略:
|
||||
|
||||
- **`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`
|
||||
(4)LRU 算法实现思路:可以继承 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 文件)中。
|
||||
(1)Redis 支持两种持久化方式:RDB 和 AOF。
|
||||
|
||||
AOF(Append Only File) 是以文本日志形式将所有写命令追加到 AOF 文件的末尾,以此来记录数据的变化。
|
||||
(2)RDB 即某一时刻的二进制数据快照。
|
||||
|
||||
更详细的特性及原理说明请参考:[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 的并发竞争问题如何解决?
|
||||
(3)AOF 会将写命令不断追加到 AOF 文本日志末尾。
|
||||
|
||||
---
|
||||
AOF 丢数据比 RDB 少,但文件会比 RDB 文件大很多。
|
||||
|
||||
解答:
|
||||
一般,AOF 设置 `appendfsync` 同步频率为 **`everysec`** 即可。
|
||||
|
||||
Redis 为单进程单线程模式,采用队列模式将并发访问变为串行访问。
|
||||
(4)RDB or AOF
|
||||
|
||||
Redis 单机吞吐量也很高,能达到几万 QPS,但需要格外注意的是:**Redis 是单线程模型**。很多人可能会奇怪,Redis 是单线程模型,如何能处理高并发请求呢?
|
||||
|
||||
原因在于:
|
||||
|
||||
- Redis 读写都是内存操作。
|
||||
- Redis 基于**非阻塞的 IO 多路复用机制**,同时监听多个 socket,将产生事件的 socket 压入内存队列中,事件分派器根据 socket 上的事件类型来选择对应的事件处理器进行处理。
|
||||
- 单线程,避免了线程创建、销毁、上下文切换的开销,并且避免了资源竞争。
|
||||
|
||||
Redis 的高并发通过主从架构来实现。Redis 集群采用主从模型,提供复制和故障转移功能,来保证 Redis 集群的高可用。通常情况,一主多从模式已经可以满足大部分项目的需要。根据实际的并发量,可以通过增加节点来扩展并发吞吐。
|
||||
|
||||
一主多从模式下,主节点负责写操作(单机几万 QPS),从节点负责查询操作(单机十万 QPS)。
|
||||
|
||||
进一步,如果需要缓存大量数据,就需要分区(sharding),Redis 集群通过划分虚拟 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。
|
||||
|
||||
(3)Redis 集群数据一致性
|
||||
|
||||
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**
|
||||
|
||||
(3)Redis 集群主从节点复制的工作流程:
|
||||
|
||||
- 步骤 1. 设置主从服务器
|
||||
- 步骤 2. 主从服务器建立 TCP 连接。
|
||||
- 步骤 3. 发送 PING 检查通信状态。
|
||||
- 步骤 4. 身份验证。
|
||||
- 步骤 5. 发送端口信息。
|
||||
- 步骤 6. 同步。
|
||||
- 步骤 7. 命令传播。
|
||||
|
||||
## Redis 哨兵
|
||||
|
||||
【问题】
|
||||
|
||||
- Redis 如何实现高可用?
|
||||
- Redis 哨兵的功能?
|
||||
- Redis 哨兵的原理?
|
||||
- Redis 哨兵如何选举 Leader?
|
||||
- Redis 如何实现故障转移?
|
||||
|
||||
---
|
||||
|
||||
【解答】
|
||||
|
||||
> **_Redis 哨兵_**
|
||||
>
|
||||
> 详情可以参考:[Redis 哨兵](redis-sentinel.md)
|
||||
|
||||
(1)Redis 的高可用是通过哨兵来实现(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 类型的数据,同时还提供 list,set,zset,hash 等数据结构的存储。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#缓存)
|
||||
|
|
|
@ -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 集群节点的安装与单节点服务相同,差异仅在于部署方式。
|
||||
|
|
|
@ -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/)
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue