redis集群模式

This commit is contained in:
heibaiying 2019-07-18 17:55:02 +08:00
parent b286f8ac8f
commit 051619f5a2
19 changed files with 739 additions and 1004 deletions

View File

@ -46,11 +46,11 @@ TODO
+ redis 简介及基本数据结构
+ redis 管道模式详解
+ redis AOF 和 RDB 持久化策略原理
+ redis 哨兵模式
+ reids 集群模式
+ [Redis AOF 和 RDB 持久化策略原理](https://github.com/heibaiying/Full-Stack-Notes/blob/master/notes/Redis_持久化.md)
+ [Redis 哨兵模式](https://github.com/heibaiying/Full-Stack-Notes/blob/master/notes/Redis_哨兵模式.md)
+ [Reids 集群模式](https://github.com/heibaiying/Full-Stack-Notes/blob/master/notes/Redis_集群模式.md)
+ 缓存击穿、缓存雪崩的解决方案
+ redis 管理客户端cachecloud
+ redis 管理客户端 cachecloud
#### 4.MongoDB
@ -63,7 +63,7 @@ TODO
## 📟 操作系统
linux 核心概念、常用命令
[Linux 常用 Shell 命令](https://github.com/heibaiying/Full-Stack-Notes/blob/master/notes/Linux常用Shell命令.md)
@ -86,7 +86,7 @@ linux 核心概念、常用命令
#### 2.spring Boot
+ spring 自动装配原理
+ 理解SpringApplication
+ 理解 SpringApplication
+ Web MVC REST
+ WebFlux 核心
+ ......

View File

@ -1,17 +1,32 @@
# Redis Sentinel
<nav>
<a href="#一复制">一、复制</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#11-建立复制关系">1.1 建立复制关系</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#12-断开复制关系">1.2 断开复制关系</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#13-复制机制缺陷">1.3 复制机制缺陷</a><br/>
<a href="#二哨兵模式原理">二、哨兵模式原理</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#21-架构说明">2.1 架构说明</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#22-故障转移原理">2.2 故障转移原理</a><br/>
<a href="#三哨兵模式搭建">三、哨兵模式搭建</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#31-配置复制集">3.1 配置复制集</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#32-配置Sentinel">3.2 配置Sentinel</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#33-启动集群">3.3 启动集群</a><br/>
</nav>
## 一、复制
为了解决单点问题保证数据的安全性Redis 提供了复制机制用于满足故障恢复和负载均衡等需求。通过复制机制Redis 可以通过多个副本保证数据的安全性从而提供高可用的基础Redis 的哨兵模式和集群模式都是在复制机制的基础上实现高可用的。
为了解决单点问题保证数据的安全性Redis 提供了复制机制用于满足故障恢复和负载均衡等需求。通过复制机制Redis 可以通过多个副本保证数据的安全性从而提供高可用的基础Redis 的哨兵和集群模式都是在复制基础上实现高可用的。
### 1.1 建立复制关系
想要对两个 Redis 节点建立主从复制关系,可以通过以下三种方式来实现:
- 在从节点的配置文件中配置 `slaveof{masterHost}{masterPort}` 选项;
- 在从节点启动时候加入 `--slaveof{masterHost}{masterPort }`参数;
- 直接在从节点的交互式命令行中执行 `slaveof{masterHost}{masterPort}` 命令。
- 在从节点的配置文件中配置 `slaveof {masterHost} {masterPort}` 选项;
- 在从节点启动时候加入 `--slaveof {masterHost} {masterPort}` 参数;
- 直接在从节点上执行 `slaveof {masterHost} {masterPort}` 命令。
<div align="center"> <img src="https://github.com/heibaiying/Full-Stack-Notes/blob/master/pictures/redis主从复制.png"/> </div>
主从节点复制关系建立后,可以使用 `info replication` 命令查看相关的复制状态。需要注意的是每个从节点只能有一个主节点,但主节点可以同时拥有多个从节点,复制行为是单向的,只能由主节点复制到从节点,因此从节点默认都是只读模式,即 `slave-read-only` 的值默认为`yes`
### 1.2 断开复制关系
@ -26,11 +41,7 @@ slaveof{newMasterIp} {newMasterPort}
需要注意的是,当你从一个主节点切换到另外一个主节点时,该从节点上的原有的数据会被完全清除,然后再执行复制操作,从而保证该从节点上的数据和新主节点上的数据相同。
### 1.3 复制机制原理
### 1.4 复制机制缺陷
### 1.3 复制机制缺陷
复制机制最主要的缺陷在于,一旦主节点出现故障,从节点无法自动晋升为主节点,需要通过手动切换来实现,这样无法达到故障的快速转移,因此也不能实现高可用。基于这个原因,就产生了哨兵模式。
@ -40,17 +51,16 @@ slaveof{newMasterIp} {newMasterPort}
哨兵模式的主要作用在于它能够自动完成故障发现和故障转移,并通知客户端,从而实现高可用。哨兵模式通常由一组 Sentinel 节点和一组(或多组)主从复制节点组成,架构如下:
![下载](C:\Users\ciic\Desktop\下载.png)
<div align="center"> <img src="https://github.com/heibaiying/Full-Stack-Notes/blob/master/pictures/redis哨兵模式.png"/> </div>
### 2.1 架构说明
#### 1. Sentinel 与 Redis Node
Redis Sentinel 是一个特殊的 Redis 节点。在哨兵模式创建时,需要通过配置指定 Sentinel 与 Redis Master Node 之间的关系,然后 Sentinel 会从主节点上获取所有从节点的信息,之后 Sentinel 会定时向主节点和从节点发送`info`命令获取其拓扑结构和状态信息。
Redis Sentinel 是一个特殊的 Redis 节点。在哨兵模式创建时,需要通过配置指定 Sentinel 与 Redis Master Node 之间的关系,然后 Sentinel 会从主节点上获取所有从节点的信息,之后 Sentinel 会定时向主节点和从节点发送`info`命令获取其拓扑结构和状态信息。
#### 2. Sentinel 与 Sentinel
基于 Redis 的发布订阅功能, 每个 Sentinel 节点会向主节点的 `__sentinel__ hello` 频道上发送该 Sentinel 节点对于主节点的判断以及当前 Sentinel 节点的信息 ,同时每个 Sentinel 节点也会订阅该频道, 来获取其他 Sentinel 节点的信息以及它们对主节点的判断。
基于 Redis 的发布订阅功能, 每个 Sentinel 节点会向主节点的 `__sentinel__hello` 频道上发送该 Sentinel 节点对于主节点的判断以及当前 Sentinel 节点的信息 ,同时每个 Sentinel 节点也会订阅该频道, 来获取其他 Sentinel 节点的信息以及它们对主节点的判断。
#### 3. 心跳机制
@ -58,13 +68,11 @@ Redis Sentinel 就是一个特殊的 Redis 节点。在哨兵模式创建时,
### 2.2 故障转移原理
每个 Sentinel 都会定时进行心跳检查,当发现某个主节点出现心跳检测超时的情况时,此时认为该主节点已经不可用,这种判定称为主观下线。
每个 Sentinel 都会定时进行心跳检查,当发现某个主节点出现心跳检测超时的情况时,此时认为该主节点已经不可用,这种判定称为主观下线。之后该 Sentinel 节点会通过 `sentinel ismaster-down-by-addr` 命令向其他 Sentinel 节点询问对主节点的判断, 当 quorum 个 Sentinel 节点都认为该节点故障时,则执行客观下线,即认为该节点已经不可用。这也同时解释了为什么必须需要一组 Sentinel 节点,因为单个 Sentinel 节点很容易对故障状态做出误判。
之后该 Sentinel 节点会通过 `sentinel ismaster-down-by-addr` 命令向其他 Sentinel 节点询问对主节点的判断, 当 quorum 个 Sentinel 节点都认为该节点故障时,则执行客观下线,即认为该节点已经不可用。这也同时解释了为什么必须需要一组 Sentinel 节点,因为单个 Sentinel 节点很容易对故障状态做出误判。这里 quorum 的值是我们在哨兵模式搭建时指定的,后文会有说明,通常为 `Sentinel节点总数/2+1`,即半数以上节点做出主观下线判断就可以执行客观下线。
> 这里 quorum 的值是我们在哨兵模式搭建时指定的,后文会有说明,通常为 `Sentinel节点总数/2+1`,即半数以上节点做出主观下线判断就可以执行客观下线。
因为故障转移的工作只需要一个 Sentinel 节点来完成,所以 Sentinel 节点之间会再做一次选举工作, 基于 Raft 算法选出一个 Sentinel 领导者来进行故障转移的工作。
被选举出的 Sentinel 领导者就开始进行故障转移, 具体步骤如下:
因为故障转移的工作只需要一个 Sentinel 节点来完成,所以 Sentinel 节点之间会再做一次选举工作, 基于 Raft 算法选出一个 Sentinel 领导者来进行故障转移的工作。 被选举出的 Sentinel 领导者进行故障转移的具体步骤如下:
1. 在从节点列表中选出一个节点作为新的主节点,选择方法如下:
@ -80,7 +88,107 @@ Redis Sentinel 就是一个特殊的 Redis 节点。在哨兵模式创建时,
## 三、哨兵模式搭建
## 四、客户端连接
下面演示在单机上搭建哨兵模式多机搭建步骤亦同。需要注意的是在实际生产环境中为了保证高可用Sentinel 节点需要尽量部署在不同主机上,同时为了保证正常选举,至少需要 3个 Sentinel 节点。
### 3.1 配置复制集
拷贝三份 `redis.conf`,分别命名为 redis-6379.conf redis-6380.conf redis-6381.conf ,需要修改的配置项如下:
```shell
# redis-6379.conf
port 6379
daemonize yes #以守护进程的方式启动
pidfile /var/run/redis_6379.pid #当Redis以守护进程方式运行时Redis会把pid写入该文件
logfile 6379.log
dbfilename dump-6379.rdb
dir /home/redis/data/
# redis-6380.conf
port 6380
daemonize yes
pidfile /var/run/redis_6380.pid
logfile 6380.log
dbfilename dump-6380.rdb
dir /home/redis/data/
slaveof 127.0.0.1 6379
# redis-6381.conf
port 6381
daemonize yes
pidfile /var/run/redis_6381.pid
logfile 6381.log
dbfilename dump-6381.rdb
dir /home/redis/data/
slaveof 127.0.0.1 6379
```
### 3.2 配置Sentinel
拷贝三份 `sentinel.conf` ,分别命名为 sentinel-26379.conf sentinel-26380.conf sentinel-26381.conf ,配置如下:
```shell
# sentinel-26379.conf
port 26379
daemonize yes
logfile 26379.log
dir /home/redis/data/
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
# sentinel-26380.conf
port 26380
daemonize yes
logfile 26380.log
dir /home/redis/data/
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
# sentinel-26381.conf
port 26381
daemonize yes
logfile 26381.log
dir /home/redis/data/
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
```
### 3.3 启动集群
分别启动三个 Redis 节点,命令如下:
```shell
redis-server redis-6379.conf
redis-server redis-6380.conf
redis-server redis-6381.conf
```
分别启动三个Sentinel节点命令如下
```shell
redis-sentinel sentinel-26379.conf
redis-sentinel sentinel-26380.conf
redis-sentinel sentinel-26381.conf
```
使用 `ps -ef | grep redis` 命令查看进程,此时输出应该如下:
<div align="center"> <img src="https://github.com/heibaiying/Full-Stack-Notes/blob/master/pictures/redis-sentinel-ps-ef.png"/> </div>
可以使用 `info replication` 命令查看 Redis 复制集的状态,此时输出如下。可以看到 6379 节点为 master 节点,并且有两个从节点,分别为 slave0 和 slave1对应的端口为 6380 和 6381。
<div align="center"> <img src="https://github.com/heibaiying/Full-Stack-Notes/blob/master/pictures/redis-info-replication.png"/> </div>
可以使用 `info Sentinel` 命令查看任意 Sentinel 节点的状态,从最后一句输出可以看到 Sentinel 节点已经感知到 6379 的 master 节点,并且也知道它有两个 slaves 节点;同时 Sentinel 节点彼此之间也感知到,共有 3 个 Sentinel 节点。
<div align="center"> <img src="https://github.com/heibaiying/Full-Stack-Notes/blob/master/pictures/redis-sentinel-infomation.png"/> </div>
## 参考资料
1. 付磊,张益军 . 《Redis 开发与运维》. 机械工业出版社 . 2017-3-1
2. 官方文档:[Redis Sentinel Documentation](https://redis.io/topics/sentinel)

View File

@ -0,0 +1,161 @@
# Redis 基础
## 一、数据类型
Redis 5 支持以下多种数据类型:
- 二进制安全字符串。
- Lists (列表):根据插入顺序排序的字符串元素的集合。
- Sets (集):未排序的不重复的字符串元素的集合。
- Sorted Sets (排序集):类似于集,但每个字符串元素与被称为分数的值相关,元素总是按其分数排序。
- Hashes (散列) :由字段 (Field) 和值都是字符串组成的映射的集合。
- Bit Arrays (也称 bitmaps 位图) Bitmaps 本身不是一种数据结构, 实际上它就是字符串,但是它可以对字符串的位进行操作,所以在 Redis 官方的分类当中将其单独归为一类;
- HyperLogLogs实际类型为字符串类型 ,它是一种基数算法, 通过 HyperLogLog 可以利用极小的内存空间完成独立总数的统计。
- Streams (流) Stream是 Redis 5.0 引入的一种新数据类型,用于在生产者和消费者之间建立数据通道。
## 二、常用命令
### 2.1 字符串
| 作用 | 命令格式 | 参数或示例 |
| -------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| 设置值 | set key value \[ex seconds]\[px milliseconds][nx\|xx] setnx setex | ex seconds为键设置秒级过期时间 <br/>px milliseconds为键设置毫秒级过期时间<br/>nx 键不存在时才可以添加成功;<br/>xx 键存在时才可以修改成功。 |
| 获取值 | get key | 如果获取的键不存在 ,则返回 nil |
| 批量设置 | mset key value [key value ...] | mset a 1 b 2 c 3 d 4 |
| 批量获取值 | mget key [key ...] | mget a b c d |
| 计数 | incr key <br/>decr key<br/>incrby key increment指定数值自增<br/>decrby key decrement指定数值自减<br/>incrbyfloat key increment (浮点数自增) | 值是整数时返回自增或自减后的结果;<br/>值不是整数时返回错误;<br/>键不存在时自动创建,并按照初始值为 0 进行自增或自减。 |
| 追加值 | append key value | 向字符串尾部追加值。 |
| 字符串长度 | strlen key | 获取字符串长度,中文占用三个字节 |
| 设置并返回原值 | getset key value | |
| 设置指定位置的字符串 | setrange key offeset value | |
| 获取部分字符串 | getrange key start end | |
### 2.3 哈希
| 作用 | 格式 | 参数或示例 |
| ---------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| 设置值 | hset key field value | hset user:1 name tom<br/>hset user:1 age 12 |
| 获取值 | hget key field | hget user:1 name |
| 删除 field | hdel key field [field ...] | |
| 计算 field 个数 | hlen key | |
| 批量设置或获取 | hmget key field [field]<br/>hmset key field value [field value...] | hmset user:1 name mike age 12 city tianjin<br/>hmget user:1 name city |
| 判断 field 是否存在 | hexists key field | |
| 获取所有 field | hkeys key | |
| 获取所有 value | hvals key | |
| 获取所有的 filed-value | hgetall key | 如果哈希元素个数比较多可能会阻塞Redis此时可以使用 hscan 渐进式遍历 |
| 计数 | hincrby key field<br/>hincrbyfloat key field | |
### 2.4 列表
| 作用 | 格式 | 参数或示例 |
| -------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| 增 | 左侧插入lpush key value [value ...] <br/>右侧插入rpush key value [value ...] <br/>某个指定元素前后插入linsert key before\|after pivot value | |
| 查 | 获取指定范围内的元素列表lrange key start end <br/>获取列表指定索引下标的元素lindex key index <br/>获取列表指定长度llen key | lrange listkey 0 -1 |
| 删 | 从列表左侧弹出元素lpop key <br/>从列表右侧弹出元素rpop key <br/>删除指定元素lrem key count value <br/>截取列表ltrim key start end | count>0从左到右 删除最多 count 个元素。<br/>count<0从右到左 删除最多 -count 个元素<br/>count=0 删除所有 |
| 改 | 修改指定下标的元素lset key index newValue | |
| 阻塞操作 | blpop key [key ...] timeout <br/>brpop key [key ...] timeout | key[key...] 多个列表的键。 timeout 阻塞时间\|等待时间(单位秒) |
### 2.5 集合
集合set 类型也是用来保存多个的字符串元素, 但和列表类型不一样的是, 集合中的元素是无序的, 不允许有重复元素,不能通过下标获取元素。
| 作用 | 格式 | 参数或示例 |
| -------------------- | ------------------------------ | ----------------------------------------- |
| 添加元素 | sadd key element [element ...] | 返回结果为添加成功的元素个数 |
| 删除元素 | srem key element [element ...] | 返回结果为成功删除的元素个数 |
| 计算元素个数 | scard key | |
| 判断元素是否在集合中 | sismember key element | |
| 随机返回 | srandmember key [count] | 随机从集合返回指定个数元素count 默认为1 |
| 从集合随机弹出元素 | spop key | srandmember 不会从集合中删除元素spop 会 |
| 获取集合中所有元素 | smembers key | 可用 sscan 代替 |
**集合间操作**
| 作用 | 格式 |
| ---------------------------- | ------------------------------------------------------------ |
| 求多个集合的交集 | sinter key [key ...] |
| 求多个集合的并集 | suinon key [key ...] |
| 求多个集合的差集 | sdiff key [key ...] |
| 将交集、并集、差集的结果保存 | sinterstore destination key [key ...] <br/>suionstore destination key [key ...]<br/>sdiffstore destination key [key ...] |
### 2.6 有序集合
有序集合中的元素可以排序。它给每个元素设置一个分数score 作为排序的依据。
| 作用 | 格式 | 参数或示例 |
| ------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
| 添加成员 | zadd key score member [score member ...] | nx member 不存在时才可设置成功, 用于添加;<br>xx member 存在时可以设置成功, 用于更新;<br/>ch 返回此次操作后, 有序集合内元素和分数发生变化的个数;<br/>incr对 score 做增加, 相当于下面的 zincrby。 |
| 计算成员个数 | zcard key | |
| 计算某个成员的分数 | zscore key member | |
| 计算某个成员的排名 | zrank key member zrevrank key member | zrank是从分数从低到高返回排名 zrevrank 反之。 |
| 删除成员 | zrem key member [member ...] | |
| 增加成员分数 | zincrby key increment member | zincrby user:ranking 9 tom |
| 返回指定排名范围的成员 | zrange key start end [withscores] <br/>zrevrange key start end [withscores] | zrange是从低到高返回 zrevrange 反之。 |
| 返回指定分数范围内的成员 | zrangebyscore key min max \[withscores][limit offset count] <br/>zrevrangebyscore key max min \[withscores][limit offset count] | 其中 zrangebyscore 按照分数从低到高返回, zrevrangebyscore 反之;<br/> [limit offset count] 选项用于限制输出的起始位置和个数; <br/>min 和 max 代表最小和最大值,支持开闭区间, 也可以使用 -inf 和+inf 代表无限小和无限大。 |
| 删除指定排名内的升序元素 | zremrangerank key start end | |
| 删除指定分数范围的成员 | zremrangebyscore key min max | |
**集合间操作**
| 作用 | 格式 |
| ---- | ------------------------------------------------------------ |
| 交集 | zinterstore destination numkeys key \[key ...] [weights weight [weight ...]] \[aggregate sum\|min\|max] |
| 并集 | zunionstore destination numkeys key \[key ...] [weights weight [weight ...]] \[aggregate sum\|min\|max] |
- destination 交集计算的结果保存到这个键。
- numkeys 需要做交集计算键的个数。
- key[key...] 需要做交集计算的键。
- weights weight[weight...] 每个键的权重, 在做交集计算时, 每个键中的每个 member 会将自己分数乘以这个权重, 每个键的权重默认是1。
- aggregate sum|min|max 计算成员交集后, 分值可以按照sum 、min最小值 、 max最大值 做汇总, 默认值是 sum。
### 2.7 全局命令
1. 查看所有键: keys \*
2. 查看键总数dbsize
3. 检查键是否存在exists key
4. 删除键del key [key ...]
5. 键过期expire key seconds ,使用 ttl 命令可以查看键剩余的过期时间, 它有以下三种返回值:
- 大于等于0的整数 键剩余的过期时间。
- -1 键未设置过期时间。
- -2 键不存在
6. 查看键的数据类型type key
### 2.8 键过期
可以使用以下命令完成设置键的过期时间:
- expire key seconds 键在 seconds 秒后过期;
- expireat key timestamp 键在秒级时间戳 timestamp 后过期;
- pexpire key milliseconds 键在 milliseconds 毫秒后过期;
- pexpireat key milliseconds-timestamp键在毫秒级时间戳 timestamp 后过期。
注意事项:
- 如果 expire key 的键不存在, 返回结果为 0
- 如果设置过期时间为负值, 键会立即被删除, 此时等价于 del 命令;
- persist key 命令可以将键的过期时间清除,使键变成永久的;
- 需要特别注意对于字符串类型键, 执行 set 命令会清除掉已有的过期时间;
- Redis 不支持对二级数据结构的内部元素设置过期时间, 例如不能对列表内的某个元素设置过期时间;
- setex 命令是 set+expire 的组合, 它是一个原子操作。
### 2.9 渐进式键遍历
使用 keys 命令遍历键可能会带来阻塞的风险,因为 Redis 提供了渐进式键遍历命令 scan ,使用格式如下:
```shell
scan cursor [match pattern] [count number]
```
- cursor游标第一次遍历从 0 开始, 每次遍历完都会返回当前游标的值, 直到游标值为 0 表示遍历结束。
- match patternr可选参数 它的作用的是匹配特定模式的键;
- count numberr可选参数 它的作用是表明每次要遍历的键个数, 默认值是 10。
### 2.10 数据库管理
1.切换数据库select dbIndex
2.清除数据库flushdb/flushallflushdb只清除当前数据库 flushall会清除所有数据库。

View File

@ -1,5 +1,22 @@
# Redis Cluster
<nav>
<a href="#一集群模式介绍">一、集群模式介绍</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#11-数据分区">1.1 数据分区</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#12-节点通讯">1.2 节点通讯</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#13-请求路由">1.3 请求路由</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#14-故障发现">1.4 故障发现</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#15-故障恢复">1.5 故障恢复</a><br/>
<a href="#二集群模式搭建">二、集群模式搭建</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#21-节点配置">2.1 节点配置</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#22-启动集群">2.2 启动集群</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#23-集群完整性校验">2.3 集群完整性校验</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#24-关于版本差异的说明">2.4 关于版本差异的说明</a><br/>
<a href="#三集群伸缩">三、集群伸缩</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#31-集群扩容">3.1 集群扩容</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#32-集群缩容">3.2 集群缩容</a><br/>
</nav>
## 一、集群模式介绍
Redis Cluster 是 Redis 官方提供的分布式实现,在 Redis 3.0 版本正式推出通过集群模式可以扩展单机的性能瓶颈同时也可以通过横向扩展来实现扩容。此外Redis 集群模式还提供了副本迁移机制,用于保证数据的安全和提高集群的容错能力,从而实现高可用。
@ -12,15 +29,19 @@ Redis Cluster 采用虚拟槽进行分区,槽是集群内数据管理和迁移
HASH_SLOT = CRC16(key) mod 16384
```
假设现在有一个 6 个节点的集群,分别有 3 个 Master 点和 3 个 Slave 节点,槽会尽量均匀的分布在所有 Master 节点上。数据经过散列后存储在指定的 Master 节点上,之后 Slave 节点会进行对应的复制操作。这里再次说明一下槽只是一个虚拟的概念,并不是数据存放的实际载体。
<div align="center"> <img src="https://github.com/heibaiying/Full-Stack-Notes/blob/master/pictures/redis-集群架构.png"/> </div>
### 1.2 节点通讯
在 Redis 分布式架构中,每个节点都存储有整个集群所有节点的元数据信息,这是通过 P2P 的 Gossip 协议来实现的。集群中的每个节点都会单独开辟一个 TCP 通道,用于节点之间彼此通信,通信端口号在基础端口上加 10000每个节点定期通过特定的规则选择部分节点发送 ping 消息,接收到 ping 信息的节点用 pong 消息作为响应,通过一段时间的彼此通信,最终所有节点都会达到一致的状态,每个节点都会知道整个集群全部节点的状态信息,从而到达集群状态同步的目的。
<div align="center"> <img src="https://github.com/heibaiying/Full-Stack-Notes/blob/master/pictures/redis节点通讯.png"/> </div>
### 1.3 请求路由
#### 1. 请求重定向
在集群模式下Redis接收到命令时会先计算键对应的槽然后根据槽找出对应的目标节点如果目标节点就是此时所在的节点则直接处理命令,否则返回 MOVED 重定向消息给客户端,通知客户端去正确的节点上执行操作。
在集群模式下Redis接收到命令时会先计算键对应的槽然后根据槽找出对应的目标节点如果目标节点就是此时所在的节点则直接进行处理,否则返回 MOVED 重定向消息给客户端,通知客户端去正确的节点上执行操作。
#### 2. Smart 客户端
@ -32,10 +53,157 @@ Redis 的大多数客户端都采用 Smart 客户端支持集群协议, Smart
ASK 重定向与 MOVED 重定向的区别在于:收到 ASK 重定向时说明集群正在进行数据迁移, 客户端无法知道什么时候迁移完成,因此只是临时性的重定向, 客户端不会更新映射缓存。 但是 MOVED 重定向说明键对应的槽已经明确迁移到新的节点, 因此需要更新映射缓存。
### 1.4 故障转移
### 1.4 故障发现
由于 Redis 集群的节点间都保持着定时通讯,某个节点向另外一个节点发送 ping 消息,如果正常接受到 pong 消息,此时会更新与该节点最后一次的通讯时间记录,如果之后无法正常接受到 pong 消息,并且判断当前时间与最后一次通讯的时间超过 `cluster-node-timeout` ,此时会对该节点做出主观下线的判断。
当做出主观下线判断后,节点会把这个判断在集群内传播,通过 Gossip 消息传播, 集群内节点不断收集到故障节点的下线报告。 当半数以上持有槽的主节点都标记某个节点是主观下线时, 触发客观下线流程。 这里需要注意的是只有持有槽主节点才有权利做出主观下线的判断,因为集群模式下只有处理槽的主节点才负责读写请求和维护槽等关键信息, 而从节点只进行主节点数据和状态信息的复制。
### 1.5 故障恢复
#### 1. 资格检查
每个从节点都要检查最后与主节点断线时间, 判断是否有资格替换故障的主节点。 如果从节点与主节点断线时间超过 `cluster-node-time*cluster-slave-validity-factor`,则当前从节点不具备故障转移资格。 这两个参数可以在 `redis.conf` 中进行修改,默认值分别为 15000 和 10。
#### 2. 准备选举
当从节点符合故障转移资格后, 更新触发故障选举的时间, 只有到达该时间后才能执行后续流程。在这一过程中Redis 会比较每个符合资格的从节点的复制偏移量,然后让复制偏移量大(即数据更加完整)的节点优先发起选举。
#### 3. 选举投票
从节点每次发起投票时都会自增集群的全局配置纪元,全局配置纪元是一个只增不减的整数。之后会在集群内广播选举消息,只有持有槽的主节点才会处理故障选举消息,并且每个持有槽的主节点在一个配置纪元内只有唯一的一张选票。假设集群内有 N 个持有槽的主节点,当某个从节点获得 N/2+1 张选票则代表选举成功。如果在开始投票之后的 `cluster-node-timeout*2` 时间内没有从节点获取足够数量的投票, 则本次选举作废,从节点会对配置纪元自增并发起下一轮投票, 直到选举成功为止。
#### 4. 替换主节点
当从节点收集到足够的选票之后,就会触发替换主节点操作:
+ 当前从节点取消复制变为主节点。
+ 执行 clusterDelSlot 操作撤销原主节点负责的槽, 并执行 clusterAddSlot 把这些槽委派给自己。
+ 向集群广播自己的 pong 消息,通知集群内的其他节点自己已经成为新的主节点。
## 二、集群模式搭建
## 三、客户端连接
### 2.1 节点配置
拷贝6份 `redis.conf`,分别命名为 `redis-6479.conf` ~ `redis-6484.conf`,需要修改的配置项如下:
```shell
# redis-6479.conf
port 6479
# 以守护进程的方式启动
daemonize yes
# 当Redis以守护进程方式运行时Redis会把pid写入该文件
pidfile /var/run/redis_6479.pid
logfile 6479.log
dbfilename dump-6479.rdb
dir /home/redis/data/
# 开启集群模式
cluster-enabled yes
# 节点超时时间,单位毫秒
cluster-node-timeout 15000
# 集群内部配置文件
cluster-config-file nodes-6479.conf
# redis-6480.conf
port 6480
daemonize yes
pidfile /var/run/redis_6480.pid
logfile 6480.log
dbfilename dump-6480.rdb
dir /home/redis/data/
cluster-enabled yes
cluster-node-timeout 15000
cluster-config-file nodes-6480.conf
..... 其他配置类似,修改所有用到端口号的地方
```
### 2.2 启动集群
启动所有 Redis 节点,启动后使用 `ps -ef | grep redis` 查看进程,输出应如下:
<div align="center"> <img src="https://github.com/heibaiying/Full-Stack-Notes/blob/master/pictures/redis-cluster-ps-ef.png"/> </div>
接着需要使用以下命令创建集群,集群节点之间会开始进行通讯,并完成槽的分配:
```shell
redis-cli --cluster create 127.0.0.1:6479 127.0.0.1:6480 127.0.0.1:6481 \
127.0.0.1:6482 127.0.0.1:6483 127.0.0.1:6484 --cluster-replicas 1
```
执行后输出如下M 开头的表示持有槽的主节点S 开头的表示从节点,每个节点都有一个唯一的 ID。最后一句输出表示所有的槽都已经分配到主节点上此时代表集群搭建成功。
<div align="center"> <img src="https://github.com/heibaiying/Full-Stack-Notes/blob/master/pictures/redis-cluster-create.png"/> </div>
### 2.3 集群完整性校验
集群完整性指所有的槽都分配到存活的主节点上, 只要16384个槽中有一个没有分配给节点则表示集群不完整。 可以使用以下命令进行检测, check 命令只需要给出集群中任意一个节点的地址就可以完成整个集群的检查工作。
```shell
redis-cli --cluster check 127.0.0.1:6479
```
### 2.4 关于版本差异的说明
如果你使用的是 Redis 5可以和上面的示例一样直接使用嵌入到 redis-cli 中的 Redis Cluster 命令来创建和管理集群。
如果你使用的是 Redis 3 或 4则需要使用 redis-trib.rb 工具,此时需要预先准备 Ruby 环境和安装 redis gem。
## 三、集群伸缩
Redis 集群提供了灵活的节点扩容和缩容方案,可以在不影响集群对外服务的情况下,进行动态伸缩。
### 3.1 集群扩容
这里准备两个新的节点 6485 和 6486配置和其他节点一致配置完成后进行启动。集群扩容的命令为 `add-node`,第一个参数为需要加入的新节点,第二个参数为集群中任意节点,用于发现集群。
```shell
redis-cli --cluster add-node 127.0.0.1:6485 127.0.0.1:6479
```
成功加入集群后,可以使用 `cluster nodes` 命令查看集群情况。不做任何特殊指定,默认加入集群的节点都是主节点,但是集群并不会为分配任何槽。如下图所示,其他 master 节点后面都有对应的槽的位置信息,但新加入的 6485 节点则没有,由于没有负责的槽,所以该节点此时不能进行任何读写操作。
```shell
redis-cli -h 127.0.0.1 -p 6479 cluster nodes
```
<div align="center"> <img src="https://github.com/heibaiying/Full-Stack-Notes/blob/master/pictures/redis-cluster-nodes.png"/> </div>
想要让新加入的节点能够进行读写操作,可以使用 `reshard` 命令为其分配槽,这里我们将其他三个主节点上的槽迁移一部分到 6485 节点上,这里一共迁移 4096 个槽,即 16384 除以 4 。 `cluster-from ` 用于指明槽的源节点,可以为多个,`cluster-to` 为槽的目标节点,`cluster-slots` 为需要迁移的槽的总数。
```shell
redis-cli --cluster reshard 127.0.0.1:6479 \
--cluster-from fd35b17ace0f15314ed3b3d4f8ff4da08e11b89d,ebd0425db25b8bcf843fee9826755848e23a895a,98a175734db4a106ae676dc403f39b2783640789 \
--cluster-to 819f867afd1da1acfb1a528d3efa91cffb02ba97 \
--cluster-slots 4096 --cluster-yes
```
迁移后,再次使用 `cluster nodes` 命令可以查看到此时 6485 上已经有其他三个主节点上迁移过来的槽。
<div align="center"> <img src="https://github.com/heibaiying/Full-Stack-Notes/blob/master/pictures/redis-cluster-nodes2.png"/> </div>
为保证高可用,可以为新加入的主节点添加从节点,命令如下。`add-node` 接收两个参数,第一个为需要添加的从节点,第二个参数为集群内任意节点,用于发现集群。`cluster-master-id` 参数用于指明作为哪个主节点的从节点,如果不加这个参数,则自动分配给从节点较少的主节点。
```shell
redis-cli --cluster add-node 127.0.0.1:6486 127.0.0.1:6479 --cluster-slave \
--cluster-master-id 819f867afd1da1acfb1a528d3efa91cffb02ba97
```
### 3.2 集群缩容
集群缩容的命令如下:第一个参数为集群内任意节点,用于发现集群;第二个参数为需要删除的节点。
```
redis-cli --cluster del-node 127.0.0.1:6479 `<node-id>`
```
需要注意的是待删除的主节点上必须为空,如果不为空则需要将它上面的槽和数据迁移到其他节点上,和扩容时一样,可以使用`reshard`命令来完成数据迁移。
## 参考资料
1. 付磊,张益军 . 《Redis 开发与运维》. 机械工业出版社 . 2017-3-1
2. 官方文档:[Redis cluster tutorial](https://redis.io/topics/cluster-tutorial)

View File

@ -1,84 +1,91 @@
# MongoDB 单机版本环境搭建
## 一、下载并解压
下载地址为: https://www.mongodb.com/download-center/community ,选择所需版本的 MongoDB 后进行下载:
![mongodb-version-select](D:\Full-Stack-Notes\pictures\mongodb-version-select.png)
这里我下载的版本为 `4.0.10` , 安装环境为 `RHEL 7.0`,下载后进行解压:
```shell
tar -zxvf mongodb-linux-x86_64-rhel70-4.0.10.tgz -C /usr/app
```
## 二、配置环境变量
配置环境变量:
```shell
vi /etc/profile
```
```shell
export MONGODB_HOME=/usr/app/mongodb-linux-x86_64-rhel70-4.0.10/
export PATH=${MONGODB_HOME}/bin:$PATH
```
使得配置的环境变量立即生效:
```shell
source /etc/profile
```
## 三、修改配置
MongoDB 默认存放数据的目录为 `/var/lib/mongo` ,默认存放日志的目录为 `/var/log/mongodb`,采用 TGZ 安装包进行安装时,程序不会自动创建这两个目录,需要预先手动创建。同时由于 `/var/` 下只能存放临时文件,所以这里我们使用其他目录进行存储,命令如下:
```shell
mkdir -p /home/mongodb/data
mkdir -p /home/mongodb/log
```
修改配置,采用 TGZ 安装包进行安装时,程序不会自动创建配置文件,需要手动创建:
```
vim /etc/mongod.conf
```
在配置文件中增加如下配置,这里的配置采用的是 YAML 的格式:
```shell
systemLog:
destination: file
path: "/home/mongodb/log/mongod.log"
logAppend: true
storage:
dbPath: "/home/mongodb/data"
net:
port: 27017
# 如果不修改绑定IP,默认只能在本机访问数据库服务
bindIp: 0.0.0.0
```
> MongoDB 的所有配置项可以参考其官方文档:[Configuration File Options](https://docs.mongodb.com/manual/reference/configuration-options/)
## 四、启动服务
由于已经配置过环境变量,这里直接启动即可,命令如下:
```shell
mongod -f /etc/mongod.conf
```
## 五、连接服务
这里直接使用 mongo shell 进行连接mongo shell 默认就是连接到本地的 `27017` 端口,所以直接启动即可:
```shell
mongo
```
# MongoDB 单机版本环境搭建
<nav>
<a href="#一下载并解压">一、下载并解压</a><br/>
<a href="#二配置环境变量">二、配置环境变量</a><br/>
<a href="#三修改配置">三、修改配置</a><br/>
<a href="#四启动服务">四、启动服务</a><br/>
<a href="#五连接服务">五、连接服务</a><br/>
</nav>
## 一、下载并解压
下载地址为: https://www.mongodb.com/download-center/community ,选择所需版本的 MongoDB 后进行下载:
<div align="center"> <img src="https://github.com/heibaiying/Full-Stack-Notes/blob/master/pictures/mongodb-version-select.png"/> </div>
这里我下载的版本为 `4.0.10` , 安装环境为 `RHEL 7.0`,下载后进行解压:
```shell
tar -zxvf mongodb-linux-x86_64-rhel70-4.0.10.tgz -C /usr/app
```
## 二、配置环境变量
配置环境变量:
```shell
vi /etc/profile
```
```shell
export MONGODB_HOME=/usr/app/mongodb-linux-x86_64-rhel70-4.0.10/
export PATH=${MONGODB_HOME}/bin:$PATH
```
使得配置的环境变量立即生效:
```shell
source /etc/profile
```
## 三、修改配置
MongoDB 默认存放数据的目录为 `/var/lib/mongo` ,默认存放日志的目录为 `/var/log/mongodb`,采用 TGZ 安装包进行安装时,程序不会自动创建这两个目录,需要预先手动创建。同时由于 `/var/` 下只能存放临时文件,所以这里我们使用其他目录进行存储,命令如下:
```shell
mkdir -p /home/mongodb/data
mkdir -p /home/mongodb/log
```
修改配置,采用 TGZ 安装包进行安装时,程序不会自动创建配置文件,需要手动创建:
```
vim /etc/mongod.conf
```
在配置文件中增加如下配置,这里的配置采用的是 YAML 的格式:
```shell
systemLog:
destination: file
path: "/home/mongodb/log/mongod.log"
logAppend: true
storage:
dbPath: "/home/mongodb/data"
net:
port: 27017
# 如果不修改绑定IP,默认只能在本机访问数据库服务
bindIp: 0.0.0.0
```
> MongoDB 的所有配置项可以参考其官方文档:[Configuration File Options](https://docs.mongodb.com/manual/reference/configuration-options/)
## 四、启动服务
由于已经配置过环境变量,这里直接启动即可,命令如下:
```shell
mongod -f /etc/mongod.conf
```
## 五、连接服务
这里直接使用 mongo shell 进行连接mongo shell 默认就是连接到本地的 `27017` 端口,所以直接启动即可:
```shell
mongo
```
成功进入交互式命令行则代表启动成功。

View File

@ -1,169 +1,186 @@
# RabbitMQ 单机环境搭建
# RabbitMQ 单机环境搭建
<nav>
<a href="#一前置条件">一、前置条件</a><br/>
<a href="#二Erlang-安装">二、Erlang 安装</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#21-下载并解压">2.1 下载并解压</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#22-编译和安装">2.2 编译和安装</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#23--验证安装结果">2.3 验证安装结果</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#24-配置环境变量">2.4 配置环境变量</a><br/>
<a href="#三RabbitMQ-安装">三、RabbitMQ 安装</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#31-下载并解压">3.1 下载并解压</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#32-配置环境变量">3.2 配置环境变量</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#33-启动-RabbitMQ-服务">3.3 启动 RabbitMQ 服务</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#34-查看服务状态">3.4 查看服务状态</a><br/>
<a href="#四Web-UI界面">四、Web UI界面</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#41-启动-Web-UI">4.1 启动 Web UI</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#42-新增账户">4.2 新增账户</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#43-使用新账户登录">4.3 使用新账户登录</a><br/>
</nav>
## 一、前置条件
RabbitMQ 由 Erlang 语言所编写,所以在安装 RabbitMQ 前需要安装 Erlang 。两者的版本兼容关系如下。本篇文章选用的 RabbitMQ 版本为 3.7.15 Erlang 版本为 22.0 。
| RabbitMQ version | Minimum required Erlang/OTP | Maximum supported Erlang/OTP |
| :----------------------------------------------------------- | :-------------------------- | :--------------------------- |
| 3.7.15 | 20.3.x | 22.0.x |
| 3.7.7 ~ 3.7.14 | 20.3.x | 21.3.x |
| 3.7.0 ~ 3.7.6 | 19.3 | 20.3.x |
> 表格来源https://www.rabbitmq.com/which-erlang.html
## 二、Erlang 安装
### 2.1 下载并解压
Erlang 源码包下载地址http://erlang.org/download/ ,下载后进行解压:
```shell
# 下载
wget http://erlang.org/download/otp_src_22.0.tar.gz
# 解压
tar -zxvf otp_src_22.0.tar.gz
```
### 2.2 编译和安装
Erlang 的编译过程中使用到了 `ncurses-devel` 库,需要预先安装:
```
yum install ncurses-devel
```
进入解压后的根目录:
```shell
# 配置安装目录
./configure --prefix=/usr/app/erlang
# 编译
make
# 安装
make install
```
### 2.3 验证安装结果
进入安装目录的 bin 目录下,执行 `erl`命令,出现对应的版本号信息则代表安装成功:
```shell
[root@hadoop001 bin]# ./erl
Erlang/OTP 22 [erts-10.4] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:1]
Eshell V10.4 (abort with ^G)
```
### 2.4 配置环境变量
```she
vim /etc/profile
```
配置环境变量:
```shell
export ERLANG_HOME=/usr/app/erlang
export PATH=$PATH:$ERLANG_HOME/bin
```
使得配置的环境变量立即生效:
```shell
source /etc/profile
```
## 三、RabbitMQ 安装
### 3.1 下载并解压
从 RabbitMQ 的 GitHub 仓库进行下载地址为https://github.com/rabbitmq/rabbitmq-server/releases/
```shell
# 下载
wget https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.7.15/rabbitmq-server-generic-unix-3.7.15.tar.xz
# 解压
tar -Jxf rabbitmq-server-generic-unix-3.7.15.tar.xz
```
### 3.2 配置环境变量
```she
vim /etc/profile
```
配置环境变量:
```shell
export RABBITMQ_HOME=/usr/app/rabbitmq_server-3.7.15
export PATH=$PATH:$RABBITMQ_HOME/sbin
```
使得配置的环境变量立即生效:
```shell
source /etc/profile
```
### 3.3 启动 RabbitMQ 服务
以后台守护进程的方式启动 RabbitMQ ,命令如下:
```shell
rabbitmq-server start -detached
```
### 3.4 查看服务状态
```shell
rabbitmqctl status
```
## 四、Web UI界面
### 4.1 启动 Web UI
想要使用 RabbitMQ 的 Web UI 界面,需要启动管理插件,命令如下:
```shell
rabbitmq-plugins enable rabbitmq_management
```
访问端口为 `15672`。默认的用户名和密码都是 `guest` 。如果你所用浏览器和 RabbitMQ 服务不在同一台主机上,此时应该无法登录,并出现下面的提示
![RabbitMQ-访问限制](D:\Full-Stack-Notes\pictures\RabbitMQ-访问限制.png)
之所以会出现这个提示是因为出于安全考虑RabbitMQ 只允许在本机使用默认的`guest`用户名登录。想要在其他主机上登录,可以使用自定义的账户。
### 4.2 新增账户
新增用户,用户名和密码都是 root
```sh
rabbitmqctl add_user root root
```
赋予用户在默认的名为 `/` 的 Virtual Host 上的所有权限:
```shell
rabbitmqctl set_permissions -p / root '.*' '.*' '.*'
```
设置用户的角色为管理员:
```
rabbitmqctl set_user_tags root administrator
```
### 4.3 使用新账户登录
登录后可以查看到RabbitMQ 和 Erlang 的版本号,以及对应的账户信息:
![rabbitmq-管控台](D:\Full-Stack-Notes\pictures\rabbitmq-管控台.png)
## 一、前置条件
RabbitMQ 由 Erlang 语言所编写,所以在安装 RabbitMQ 前需要安装 Erlang 。两者的版本兼容关系如下。本篇文章选用的 RabbitMQ 版本为 3.7.15 Erlang 版本为 22.0 。
| RabbitMQ version | Minimum required Erlang/OTP | Maximum supported Erlang/OTP |
| :----------------------------------------------------------- | :-------------------------- | :--------------------------- |
| 3.7.15 | 20.3.x | 22.0.x |
| 3.7.7 ~ 3.7.14 | 20.3.x | 21.3.x |
| 3.7.0 ~ 3.7.6 | 19.3 | 20.3.x |
> 表格来源https://www.rabbitmq.com/which-erlang.html
## 二、Erlang 安装
### 2.1 下载并解压
Erlang 源码包下载地址http://erlang.org/download/ ,下载后进行解压:
```shell
# 下载
wget http://erlang.org/download/otp_src_22.0.tar.gz
# 解压
tar -zxvf otp_src_22.0.tar.gz
```
### 2.2 编译和安装
Erlang 的编译过程中使用到了 `ncurses-devel` 库,需要预先安装:
```
yum install ncurses-devel
```
进入解压后的根目录:
```shell
# 配置安装目录
./configure --prefix=/usr/app/erlang
# 编译
make
# 安装
make install
```
### 2.3 验证安装结果
进入安装目录的 bin 目录下,执行 `erl`命令,出现对应的版本号信息则代表安装成功:
```shell
[root@hadoop001 bin]# ./erl
Erlang/OTP 22 [erts-10.4] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:1]
Eshell V10.4 (abort with ^G)
```
### 2.4 配置环境变量
```she
vim /etc/profile
```
配置环境变量:
```shell
export ERLANG_HOME=/usr/app/erlang
export PATH=$PATH:$ERLANG_HOME/bin
```
使得配置的环境变量立即生效:
```shell
source /etc/profile
```
## 三、RabbitMQ 安装
### 3.1 下载并解压
从 RabbitMQ 的 GitHub 仓库进行下载地址为https://github.com/rabbitmq/rabbitmq-server/releases/
```shell
# 下载
wget https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.7.15/rabbitmq-server-generic-unix-3.7.15.tar.xz
# 解压
tar -Jxf rabbitmq-server-generic-unix-3.7.15.tar.xz
```
### 3.2 配置环境变量
```she
vim /etc/profile
```
配置环境变量:
```shell
export RABBITMQ_HOME=/usr/app/rabbitmq_server-3.7.15
export PATH=$PATH:$RABBITMQ_HOME/sbin
```
使得配置的环境变量立即生效:
```shell
source /etc/profile
```
### 3.3 启动 RabbitMQ 服务
以后台守护进程的方式启动 RabbitMQ ,命令如下:
```shell
rabbitmq-server start -detached
```
### 3.4 查看服务状态
```shell
rabbitmqctl status
```
## 四、Web UI界面
### 4.1 启动 Web UI
想要使用 RabbitMQ 的 Web UI 界面,需要启动管理插件,命令如下:
```shell
rabbitmq-plugins enable rabbitmq_management
```
访问端口为 `15672`。默认的用户名和密码都是 `guest` 。如果你所用浏览器和 RabbitMQ 服务不在同一台主机上,此时应该无法登录,并出现下面的提示
<div align="center"> <img src="https://github.com/heibaiying/Full-Stack-Notes/blob/master/pictures/RabbitMQ-访问限制.png"/> </div>
之所以会出现这个提示是因为出于安全考虑RabbitMQ 只允许在本机使用默认的`guest`用户名登录。想要在其他主机上登录,可以使用自定义的账户。
### 4.2 新增账户
新增用户,用户名和密码都是 root
```sh
rabbitmqctl add_user root root
```
赋予用户在默认的名为 `/` 的 Virtual Host 上的所有权限:
```shell
rabbitmqctl set_permissions -p / root '.*' '.*' '.*'
```
设置用户的角色为管理员:
```
rabbitmqctl set_user_tags root administrator
```
### 4.3 使用新账户登录
登录后可以查看到RabbitMQ 和 Erlang 的版本号,以及对应的账户信息:
<div align="center"> <img src="https://github.com/heibaiying/Full-Stack-Notes/blob/master/pictures/rabbitmq-管控台.png"/> </div>

View File

@ -1,726 +0,0 @@
# 《Redis开发与运维》读书笔记
## 目录<br/>
<a href="#第二章-API的理解与使用">第二章 API的理解与使用</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#21-预备">2.1 预备</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#211-全局命令">2.1.1 全局命令</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#212-数据结构和内部编码">2.1.2 数据结构和内部编码</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#213-单线程架构">2.1.3 单线程架构</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#22-字符串">2.2 字符串</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#23-哈希">2.3 哈希</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#24-列表">2.4 列表</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#25-集合">2.5 集合</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#26-有序集合">2.6 有序集合</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#27-键管理">2.7 键管理</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#271-单个键管理">2.7.1 单个键管理</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#1键重命名">1.键重命名 </a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#2-随机返回键">2. 随机返回键 </a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#3键过期">3.键过期</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#272-键遍历">2.7.2 键遍历</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#1-全量键遍历">1. 全量键遍历</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#2-渐进式遍历">2. 渐进式遍历</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#273-数据库管理">2.7.3 数据库管理</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#1切换数据库">1.切换数据库</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#2flushdb/flushall">2.flushdb/flushall </a><br/>
<a href="#第三章-小功能-大用处">第三章 小功能 大用处</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#31-慢查询分析">3.1 慢查询分析</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#311-慢查询的两个配置参数">3.1.1 慢查询的两个配置参数</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#32-redis-shell">3.2 redis shell</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#321-redis-cli">3.2.1 redis-cli</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#322-redis-server">3.2.2 redis-server</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#323-redis-benchmark">3.2.3 redis-benchmark</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#33-Pipeline">3.3 Pipeline</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#34-事务与Lua">3.4 事务与Lua</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#35-Bitmaps">3.5 Bitmaps</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#36-HyperLogLog">3.6 HyperLogLog</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#37-发布订阅">3.7 发布订阅</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#38-GEO">3.8 GEO</a><br/>
<a href="#第四章-客户端">第四章 客户端</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#44-客户端管理">4.4 客户端管理</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#441-客户端API">4.4.1 客户端API</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#442-客户端相关配置">4.4.2 客户端相关配置</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#443-客户端统计片段">4.4.3 客户端统计片段</a><br/>
<a href="#第五章-持久化">第五章 持久化</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#51-RDB">5.1 RDB</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#52-AOF">5.2 AOF</a><br/>
<a href="#第六章-复制">第六章 复制</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#61-配置">6.1 配置</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#611-建立复制">6.1.1 建立复制</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#612-断开复制">6.1.2 断开复制</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#613-传输延迟">6.1.3 传输延迟</a><br/>
<a href="#第十章-集群">第十章 集群</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#101-数据分区">10.1 数据分区</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#102-搭建集群">10.2 搭建集群</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#104--集群扩容">10.4 集群扩容</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#1042-扩容集群">10.4.2 扩容集群</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#1043-收缩集群">10.4.3 收缩集群</a><br/>
<a href="#附[CacheCloud-GitHub]https//githubcom/sohutv/cachecloud">附:[CacheCloud GitHub](https://github.com/sohutv/cachecloud)</a><br/>
## 正文<br/>
## 第二章 API的理解与使用
### 2.1 预备
#### 2.1.1 全局命令
1. 查看所有键: **keys \***
2. 查看键总数:**dbsize**
3. 检查键是否存在:**exists key**
4. 删除键:**del key [key ...]** 支持删除多个键
5. 键过期:**expire key seconds**
ttl命令会返回键的剩余过期时间 它有3种返回值
- 大于等于0的整数 键剩余的过期时间。
- -1 键没设置过期时间。
- -2 键不存在
6. 键的数据结构 **type key**
#### 2.1.2 数据结构和内部编码
type命令实际返回的就是当前键的数据结构类型 它们分别是:**string**(字符串) 、 **hash**(哈希) 、 **list**(列表) 、 **set**(集合) 、 **zset**(有序集合)
#### 2.1.3 单线程架构
1. 纯内存访问, Redis将所有数据放在内存中 内存的响应时长大约为100纳秒 这是Redis达到每秒万级别访问的重要基础。
2. 非阻塞I/O Redis使用epoll作为I/O多路复用技术的实现 再加上Redis自身的事件处理模型将epoll中的连接、 读写、 关闭都转换为事件, 不在网络I/O上浪费过多的时间 如图2-6所示。
3. 单线程避免了线程切换和竞态产生的消耗。
### 2.2 字符串
| 作用 | 格式 | 参数或示例 |
| ---------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| 设置值 | set key value \[ex seconds]\[px milliseconds][nx\|xx] setnx setex | ex seconds 为键设置秒级过期时间。 <br/>px milliseconds 为键设置毫秒级过期时间。<br/>nx 键必须不存在, 才可以设置成功, 用于添加。<br/>xx 与nx相反 键必须存在, 才可以设置成功, 用于更新。 |
| 获取值 | get key | r如果获取的键不存在 则返回nil(空) |
| 批量设置 | mset key value [key value ...] | mset a 1 b 2 c 3 d 4 |
| 批量获取值 | mget key [key ...] | mget a b c d |
| 计数 | incr key decr key incrby key increment指定数值自增<br/>decrby key decrement指定数值自减<br/>incrbyfloat key increment (浮点数自增) | 值不是整数, 返回错误。 值是整数, 返回自增或自减后的结果。<br/>键不存在创建键并按照值为0自增或自减 返回结果为1。 |
| 追加值 | append key value | 向字符串的默认追加值 |
| 字符串长度 | strlen key | 获取字符串长度,中文占用三个字节 |
| 设置并返回原值 | getset key value | |
| 设置指定位置的租字符串 | setrange key offeset value | |
| 获取部分字符串 | getrange key start end | |
### 2.3 哈希
| 作用 | 格式 | 参数或示例 |
| ------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| 设置值 | hset key field value | hset user:1 name tom<br/>hset user:1 age 12 |
| 获取值 | hget key field | hget user:1 name |
| 删除field | hdel key field [field ...] | |
| 计算field个数 | hlen key | |
| 批量设置或获取field-value | hmget key field [field]<br/>hmset key field value [field value...] | hmset user:1 name mike age 12 city tianjin<br/>hmget user:1 name city |
| 判断field是否存在 | hexists key field | |
| 获取所有field | hkeys key | |
| 获取所有value | hvals key | |
| 获取所有的filed-value | hgetall key | 如果哈希元素个数比较多, 会存在阻塞Redis的可能。<br/>获取全部 可以使用hscan命令 该命令会渐进式遍历哈希类型 |
| 计数 | hincrby key field<br/>hincrbyfloat key field | |
### 2.4 列表
| 作用 | 格式 | 参数或示例 |
| -------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| 增 | 左侧插入lpush key value [value ...] <br/>右侧插入rpush key value [value ...] <br/>某个指定元素前后插入linsert key before\|after pivot value | |
| 查 | 获取指定范围内的元素列表lrange key start end <br/>获取列表指定索引下标的元素lindex key index <br/>获取列表指定长度llen key | lrange listkey 0 -1 |
| 删 | 从列表左侧弹出元素lpop key <br/>从列表右侧弹出元素rpop key <br/>删除指定元素lrem key count value <br/>截取列表ltrim key start end | count>0 从左到右, 删除最多count个元素。<br/>count<0 从右到左 删除最多count绝对值个元素<br/>count=0 删除所有 |
| 改 | 修改指定索引下标的元素lset key index newValue | |
| 阻塞操作 | blpop key [key ...] timeout <br/>brpop key [key ...] timeout | key[key...] 多个列表的键。 timeout 阻塞时间\|等待时间(单位: 秒) |
### 2.5 集合
集合set 类型也是用来保存多个的字符串元素, 但和列表类型不一样的是, **集合中不允许有重复元素** 并且集合中的元素是无序的, **不能通过索引下标获取元素**
**集合内操作**
| 作用 | 格式 | 参数或示例 |
| -------------------- | ------------------------------ | ----------------------------------------- |
| 添加元素 | sadd key element [element ...] | 返回结果为添加成功的元素个数 |
| 删除元素 | srem key element [element ...] | 返回结果为成功删除的元素个数 |
| 计算元素个数 | scard key | |
| 判断元素是否在集合中 | sismember key element | |
| 随机返回 | srandmember key [count] | 随机从集合返回指定个数元素count 默认为1 |
| 从集合随机弹出元素 | spop key | srandmember 不会从集合中删除元素spop 会 |
| 获取集合中所有元素 | smembers key | 可用sscan 代替 |
**集合间操作**
| 作用 | 格式 |
| ---------------------------- | ------------------------------------------------------------ |
| 求多个集合的交集 | sinter key [key ...] |
| 求多个集合的并集 | suinon key [key ...] |
| 求多个集合的差集 | sdiff key [key ...] |
| 将交集、并集、差集的结果保存 | sinterstore destination key [key ...] <br/>suionstore destination key [key ...]<br/>sdiffstore destination key [key ...] |
### 2.6 有序集合
有序集合中的元素可以排序。 但是它和列表使用索引下标作为排序依据不同的是, 它给每个元素设置一个分数score 作为排序的依据。
**集合内操作**
| 作用 | 格式 | 参数或示例 |
| ------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
| 添加成员 | zadd key score member [score member ...] | nx member必须不存在 才可设置成功, 用于添加。<br> xx member必须存在 才可以设置成功, 用于更新。<br/>ch 返回此次操作后, 有序集合元素和分数发生变化的个数<br/>incr 对score做增加 相当于后面介绍的zincrby。 |
| 计算成员个数 | zcard key | |
| 计算某个成员的分数 | zscore key member | |
| 计算某个成员的排名 | zrank key member zrevrank key member | zrank是从分数从低到高返回排名 zrevrank反之。 |
| 删除成员 | zrem key member [member ...] | |
| 增加成员分数 | zincrby key increment member | zincrby user:ranking 9 tom |
| 返回指定排名范围的成员 | zrange key start end [withscores] zrange key start end [withscores] | zrange是从低到高返回 zrevrange反之。 |
| 返回指定分数范围内的成员 | zrangebyscore key min max \[withscores][limit offset count] <br/>zrevrangebyscore key max min \[withscores][limit offset count] | 其中zrangebyscore按照分数从低到高返回 zrevrangebyscore反之。 [limit offset count]选项可以限制输出的起始位置和个数: 同时min和max还支持开区间小括号 和闭区间(中括号) -inf和+inf分别代表无限小和无限大 |
| 删除指定排名内的升序元素 | zremrangerank key start end | |
| 删除指定分数范围的成员 | zremrangebyscore key min max | |
**集合间操作**
| 作用 | 格式 |
| ---- | ------------------------------------------------------------ |
| 交集 | zinterstore destination numkeys key \[key ...] [weights weight [weight ...]] \[aggregate sum\|min\|max] |
| 并集 | zunionstore destination numkeys key \[key ...] [weights weight [weight ...]] \[aggregate sum\|min\|max] |
- destination 交集计算结果保存到这个键。
- numkeys 需要做交集计算键的个数。
- key[key...] 需要做交集计算的键。
- weights weight[weight...] 每个键的权重, 在做交集计算时, 每个键中的每个member会将自己分数乘以这个权重 每个键的权重默认是1。
- aggregate sum|min|max 计算成员交集后, 分值可以按照sum 、min最小值 、 max最大值 做汇总, 默认值是sum。
### 2.7 键管理
#### 2.7.1 单个键管理
##### 1.键重命名
**rename key newkey**
为了防止被强行rename Redis提供了renamenx命令 确保只有newKey不存在时候才被覆盖。
##### 2. 随机返回键
**random key**
##### 3.键过期
- expire key seconds 键在seconds秒后过期。
- expireat key timestamp 键在秒级时间戳timestamp后过期。
- pexpire key milliseconds 键在milliseconds毫秒后过期。
- pexpireat key milliseconds-timestamp键在毫秒级时间戳timestamp后过期
注意:
1. 如果expire key的键不存在 返回结果为0
2. 如果设置过期时间为负值, 键会立即被删除, 犹如使用del命令一样
3. persist key t命令可以将键的过期时间清除
4. 对于字符串类型键, 执行set命令会去掉过期时间 这个问题很容易在开发中被忽视
5. Redis不支持二级数据结构例如哈希、 列表) 内部元素的过期功能, 例如不能对列表类型的一个元素做过期时间设置
6. setex命令作为set+expire的组合 不但是原子执行, 同时减少了一次网络通讯的时间
#### 2.7.2 键遍历
##### 1. 全量键遍历
**keys pattern**
##### 2. 渐进式遍历
scan cursor \[match pattern] \[count number]
- cursor是必需参数 实际上cursor是一个游标 第一次遍历从0开始 每次scan遍历完都会返回当前游标的值 直到游标值为0 表示遍历结束。
- match pattern是可选参数 它的作用的是做模式的匹配, 这点和keys的模式匹配很像。
- count number是可选参数 它的作用是表明每次要遍历的键个数, 默认值是10 此参数可以适当增大。
#### 2.7.3 数据库管理
##### 1.切换数据库
**select dbIndex**
##### 2.flushdb/flushall
flushdb/flushall命令用于清除数据库 两者的区别的是flushdb只清除当前数据库 flushall会清除所有数据库。
## 第三章 小功能 大用处
### 3.1 慢查询分析
#### 3.1.1 慢查询的两个配置参数
```shell
# 设置慢查询阈值 耗时高于阈值的操作将被记录
config set slowlog-log-slower-than 20000
# 设置慢查询维护日志的记录长度
config set slowlog-max-len 1000
# 将配置持久化到本地配置文件
config rewrite
# 获取慢查询日志
slowlog get [n]
# 获取慢查询日志当前的长度
slowlog len
# 慢查询日志重置
slowlog reset
```
### 3.2 redis shell
#### 3.2.1 redis-cli
```shell
# 1. -r repeat选项代表将执行多次命令
redis-cli -r 3 ping
# 2. -i (interval) 选项代表每隔几秒执行一次命令
redis-cli -r 5 -i 1 ping
# 3. -x 选项代表从标准输入stdin读取数据作为redis-cli 的最后一个参数
echo "world" | redis-cli -x set hello
# 4. --salve 选项是把当前客户端模拟成当前Redis节点的从节点可以用来获取当前Redis节点的更新操作
redis-cli --salve
# 5. --stat 选项可以实时获取Redis的重要统计信息
redis-cli --stat
# --no-raw 选项要求命令的返回结果必须是原始的格式
# --raw 返回格式化之后的结果
$ redis-cli set hello "你好"
$ redis-cli get hello
"\xe4\xbd\xa0\xe5\xa5\xbd"
$redis-cli --no-raw get hello
"\xe4\xbd\xa0\xe5\xa5\xbd"
$redis-cli --raw get hello
你好
```
#### 3.2.2 redis-server
```shell
# --test-memory 选项用来检测当前操作系统能否稳定地分配指定容量给Redis
redis-server --test-memory 1024
```
#### 3.2.3 redis-benchmark
```shell
# 1. -c (client) 选项代表客户端的并发数量默认是50
# 2. -n (num选项代表客户端请求总量默认是100000
redis-benchmark -c 100 -n 20000 代表100个客户端同时请求Redis,一共执行20000次
# 3.-q 选项仅仅显示 redis-benchmark 的 requests per second 信息
redis-benchmark -c 100 -n 20000 -g
# 4.-r 执行 redis-benchmark 的时候插入更多随机的键
redis-benchmark -c 100 -n 20000 -r 10000
# -r 选项会在key,count键上加一个12位的后缀-r 10000 代表只对后四位做随机处理(-r 不是随机数的个数)
# 5.-P选项代表每个请求pipeline的数据量默认为1
# 6.-k<boolean>
# -k 选项代表客户端是否使用keepalive,1为使用0为不使用默认值为 1。
# 7.-t 选项可以对指定命令进行基准测试
redis-benchmark -t get,set -q
# 8.--csv 选项会将结果按照csv格式输出便于后续处理
```
### 3.3 Pipeline
原生批量命令与Pipeline对比 :
- 原生批量命令是原子的, Pipeline是非原子的。
- 原生批量命令是一个命令对应多个key Pipeline支持多个命令。
- 原生批量命令是Redis服务端支持实现的 而Pipeline需要服务端和客户端的共同实现。
### 3.4 事务与Lua
1. **multi**命令代表事务开始, **exec**命令代表事务结束 ,如果要停止事务的执行, 可以使用**discard**命令代替exec命令即可。
2. **Redis并不支持回滚功能**
3. 有些应用场景需要在事务之前, 确保事务中的key没有被其他客户端修改过 才执行事务, 否则不执行(类似乐观锁) Redis提供了**watch**命令来解决这类问题 。
### 3.5 Bitmaps
```shell
# 1.设置值
setbit key offset value
# 2.获取值
getbit key offset
# 3.获取BitMaps指定范围值为1的个数
bitcount [start][end]
# 4.Bitmaps 间的运算
bitop op destkey key[key...]
# op 可以为 and (交集)、or(并集)、not(非)、xor(异或)操作
# 计算Bitmaps中第一个值为targetBit的偏移量
bitpos key tartgetBit [start] [end]
```
### 3.6 HyperLogLog
通过HyperLogLog可以利用极小的内存空间完成独立总数的统计 。
```shell
# 1.添加
pfadd key element [element …]
# 2.计算独立用户数
pfcount key [key …]
# 3.合并
pfmerge destkey sourcekey [sourcekey ...]
```
### 3.7 发布订阅
```shell
# 1. 发布消息
publish channel message
# 2.订阅消息
subscribe channel [channel ...]
# 3.取消订阅
unsubscribe [channel [channel ...]]
# 4.按照模式订阅和取消订阅
psubscribe pattern [pattern...]
punsubscribe [pattern [pattern ...]]
# 查看活跃的频道(指当前频道至少有一个订阅者)
pubsub channels [pattern]
# 查看频道订阅数
pubsub numsub [channel ...]
# 查看模式订阅数
pubsub numpat
```
### 3.8 GEO
```
# 1.增加地理位置信息
geoadd key longitude latitude member [longitude latitude member ...]
geoadd cities:locations 116.28 39.55 beijing
# 2.获取地理位置信息
geopos key member [member ...]
geopos cities:locations tianjin
# 删除地理位置信息
zrem key member
```
## 第四章 客户端
### 4.4 客户端管理
#### 4.4.1 客户端API
**1.client list**
```shell
127.0.0.1:6379> client list
id=1610 addr=10.0.2.2:58879 fd=9 name= age=2169 idle=1590 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=scan
id=1612 addr=10.0.2.2:59560 fd=10 name=heibairuiwen age=1642 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=32742 obl=0 oll=0 omem=0 events=r cmd=client
```
| 参数 | 含义 |
| --------- | ------------------------------------------------------------ |
| id | 客户端连接id |
| addr | 客户端连接IP和端口 |
| fd | socket 的文件描述符 |
| name | 客户端连接名<br/>client setName 设置当前客户端名字;<br/>client getName 获取当前客户端名字 |
| age | 客户端连接存活时间 |
| idle | 客户端连接空闲时间 |
| flags | 客户端类型类型标识 |
| db | 当前客户端正在使用的数据库索引下标 |
| sub/psub | 当前客户端订阅的频道或者模式 |
| multi | 当前事务中已执行命令个数 |
| qbuf | 输入缓冲区总容量<br/>输入缓冲区会根据内容动态调整但大小不能超过1G |
| qbuf-free | 输入缓冲区剩余容量 |
| obl | 输出固定缓冲区的长度 |
| oll | 输出动态缓冲区列表长度 |
| omem | 固定缓冲区和动态缓冲区使用的容量。输出缓冲区的容量控制:<br/>client-output-buffer-limit \<class> \<hard limit> \<soft limit> \<soft seconds><br/>\<class> 客户端类型分为三种。normal 普通客户端slave slave客户端 用于复制pubsub 发布订阅客户端。<br/>\<hard limit> 如果客户端使用的输出缓冲区大于\<hard limit> 客户端会被立即关闭。<br/>\<soft limit>和\<soft seconds> 如果客户端使用的输出缓冲区超过了\<soft limit>并且持续了\<soft limit>秒, 客户端会被立即关闭。<br/>示例client-output-buffer-limit normal 20mb 10mb 120 |
| events | 文件描述符事作件r/w: r 和 w 分别代表客户端套接字可读和可写 |
| cmd | 当前客户端最后一次执行的命令,不包含参数 |
**2.客户端的限制maxclients和timeout**
Redis提供了maxclients参数来限制最大客户端连接数 一旦连接数超过maxclients 新的连接将被拒绝。 maxclients默认值是10000 可以通过info clients来查询当前Redis的连接数。
可以通过config set maxclients对最大客户端连接数进行动态设置。
**3.client kill**
client kill ip:port 此命令用于杀掉指定IP地址和端口的客户端。
**4.client pause**
client pause timeout(毫秒) client pause命令用于阻塞客户端timeout毫秒数 在此期间客户端连接将被阻塞。
**5.monitor**
monitor命令用于监控Redis正在执行的命令。monitor命令能够监听其他客户端正在执行的命令 并记录了详细的时间戳。
#### 4.4.2 客户端相关配置
1. **timeout** 检测客户端空闲连接的超时时间, 一旦idle时间达到了timeout 客户端将会被关闭, 如果设置为0就不进行检测。
2. **tcp-keepalive** 检测TCP连接活性的周期 默认值为0 也就是不进行检测, 如果需要设置, 建议为60 那么Redis会每隔60秒对它创建的TCP连接进行活性检测 防止大量死连接占用系统资源。
3. **tcp-backlog** TCP三次握手后 会将接受的连接放入队列中, tcpbacklog就是队列的大小 它在Redis中的默认值是511。
#### 4.4.3 客户端统计片段
**info clients**
1. **connected_clients** 代表当前Redis节点的客户端连接数 需要重点监控, 一旦超过maxclients 新的客户端连接将被拒绝。
2. **client_longest_output_list** 当前所有输出缓冲区中队列对象个数的最大值。
3. **client_biggest_input_buf** 当前所有输入缓冲区中占用的最大容量。
4. **blocked_clients** 正在执行阻塞命令例如blpop、 brpop、brpoplpush 的客户端个数。
## 第五章 持久化
### 5.1 RDB
RDB 持久化是把当前进程数据生成快照保存到硬盘的过程。触发RBD持久化的过程分为手动触发和自动触发。
**手动触发**
```shell
# 手动触发(阻塞)
save
# 手动触发(非阻塞)
bgsave
```
**自动触发**
1. 使用save相关配置 如“save m n”。 表示m秒内数据集存在n次修改时 自动触发bgsave。
2. 如果从节点执行全量复制操作, 主节点自动执行bgsave生成RDB文件并发送给从节点。
3. 执行debug reload命令重新加载Redis时 也会自动触发save操作。
4. 默认情况下执行shutdown命令时 如果没有开启AOF持久化功能则自动执行bgsave。
**保存**
RDB文件保存在dir配置指定的目录下 文件名通过**dbfilename**配置指定。 可以通过执行**config set dir{newDir}**和**config setdbfilename{newFileName}**运行期动态执行, 当下次运行时RDB文件会保存到新目录。
**缺点**
无法做到实时持久化/秒级持久化,重量级操作,频繁执行成本高
### 5.2 AOF
AOF 持久化以独立日志的方式记录每次写命令重启时在重新执行AOF文件中的命令达到恢复数据的目的。
1. 开启AOF功能需要设置配置 **appendonly yes** 默认不开启。
2. AOF文件名通过**appendfilename**配置设置, 默认文件名是appendonly.aof。
3. 保存路径同RDB持久化方式一致 通过dir配置指定。
**1. AOF缓冲区同步文件策略**
| 可配置值 | 说明 |
| -------------- | ------------------------------------------------------------ |
| always | 命令写入aof_buf后调用系统fsyn操作同步到AOF文件fsync 完成后线程返回 |
| everysec(常用) | 每秒执行一次 |
| no | 同步由操作系统控制 |
**2. AOF重写过程**
**手动触发**:直接调用**bgrewriteaof**命令
**自动触发**:根据**auto-aof-rewrite-min-size**和**auto-aof-rewrite-percentage**参数确定自动触发时机。
- auto-aof-rewrite-min-size 表示运行AOF重写时文件最小体积 默认为64MB。
- auto-aof-rewrite-percentage 代表当前AOF文件空间aof_current_size 和上一次重写后AOF文件空间aof_base_size 的比值。
**3. 错误修复**
对于错误格式的AOF文件 先进行备份, 然后采用**redis-check-aof--fix**命令进行修复, 修复后使用diff-u对比数据的差异 找出丢失的数据, 有些可以人工修改补全。
## 第六章 复制
### 6.1 配置
#### 6.1.1 建立复制
三种方式:
1. 在配置文件中加入slaveof {masterHost} {masterPort}随Redis启动生效。
2. 在redis-server启动命令后加入--slaveof {masterHost} {masterPort}生效。
3. 直接使用命令: slaveof {masterHost} {masterPort}生效。
```shell
127.0.0.1:6380>slaveof 127.0.0.1 6379
```
#### 6.1.2 断开复制
在从节点执行**slaveof no one**来断开与主节点复制关系。 从节点断开复制后**并不会抛弃原有数据** 只是无法再获取主节点上的数
据变化。
通过slaveof命令还可以实现切主操作 所谓切主是指把当前从节点对主节点的复制切换到另一个主节点。 执行slaveof{newMasterIp} {newMasterPort}命令即可。**会清除原有数据**。
注:**默认情况下, 从节点使用slave-read-only=yes配置为只读模式**。
#### 6.1.3 传输延迟
Redis为我们提供了**repl-disable-tcp-nodelay**参数用于控制是否关闭TCP_NODELAY 默认关闭, 说明如下:
- 当关闭时, 主节点产生的命令数据无论大小都会及时地发送给从节点, 这样主从之间延迟会变小, 但增加了网络带宽的消耗。 适用于主从之间的网络环境良好的场景, 如同机架或同机房部署。
- 当开启时, 主节点会合并较小的TCP数据包从而节省带宽。 默认发送时间间隔取决于Linux的内核 一般默认为40毫秒。 这种配置节省了带宽但增大主从之间的延迟。 适用于主从网络环境复杂或带宽紧张的场景, 如跨机房部署。
## 第十章 集群
### 10.1 数据分区
Redis Cluser采用虚拟槽分区 所有的键根据哈希函数映射到0~16383整数槽内 计算公式: slot=CRC16key &16383。 每一个节点负责维护一部分槽以及槽所映射的键值数据。
### 10.2 搭建集群
**用redis-trib.rb搭建集群**
**1.Ruby环境准备**
```shell
# 安装Ruby
wget https:// cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.1.tar.gz
tar xvf ruby-2.3.1.tar.gz
cd ruby-2.3.1
./configure -prefix=/usr/local/ruby
make
make install
cd /usr/local/ruby
sudo cp bin/ruby /usr/local/bin
sudo cp bin/gem /usr/local/bin
# 安装rubygem redis依赖
wget http:// rubygems.org/downloads/redis-3.3.0.gem
gem install -l redis-3.3.0.gem
gem list --check redis gem
# 安装redis-trib.rb
sudo cp /{redis_home}/src/redis-trib.rb /usr/local/bin
# 执行确认
# redis-trib.rb
```
**2.节点配置**
```shell
#节点端口
port 6379
# 开启集群模式
cluster-enabled yes
# 节点超时时间, 单位毫秒
cluster-node-timeout 15000
# 集群内部配置文件
cluster-config-file "nodes-6379.conf"
```
```shell
redis-server conf/redis-6481.conf
redis-server conf/redis-6482.conf
redis-server conf/redis-6483.conf
redis-server conf/redis-6484.conf
redis-server conf/redis-6485.conf
redis-server conf/redis-6486.conf
```
**3.创建集群**
```shell
redis-trib.rb create --replicas 1 127.0.0.1:6481 127.0.0.1:6482 127.0.0.1:6483
127.0.0.1:6484 127.0.0.1:6485 127.0.0.1:6486
```
--replicas参数指定集群中每个主节点配备几个从节点 这里设置为1。
**4.集群完整性检查**
集群完整性指所有的槽都分配到存活的主节点上, 只要16384个槽中有一个没有分配给节点则表示集群不完整。 可以使用redis-trib.rb check命令检测之前创建的两个集群是否成功 check命令只需要给出集群中任意一个节点地址就可以完成整个集群的检查工作 .
```shell
redis-trib.rb check 127.0.0.1:6379
redis-trib.rb check 127.0.0.1:6481
```
### 10.4 集群扩容
#### 10.4.2 扩容集群
**步骤:**
```shell
# 准备新的节点
redis-server conf/redis-6385.conf
redis-server conf/redis-6386.conf
# 加入集群
redis-trib.rb add-node 127.0.0.1:6385 127.0.0.1:6379
redis-trib.rb add-node 127.0.0.1:6386 127.0.0.1:6379
# 槽重新分片
redis-trib.rb reshard 127.0.0.1:6379
#要把节点6386作为6385的从节点 从而保证整个集群的高可用。
127.0.0.1:6386>cluster replicate 1a205dd8b2819a00dd1e8b6be40a8e2abe77b756
#查看情况验证
cluster nodes
```
槽重新分片:
```shell
redis-trib.rb reshard host:port --from <arg> --to <arg> --slots <arg> --yes --timeout
<arg> --pipeline <arg>
```
参数说明:
- host port 必传参数, 集群内任意节点地址, 用来获取整个集群信息。
- --from 制定源节点的id 如果有多个源节点, 使用逗号分隔, 如果是all源节点变为集群内所有主节点 在迁移过程中提示用户输入。
- --to 需要迁移的目标节点的id 目标节点只能填写一个, 在迁移过程中提示用户输入。
- --slots 需要迁移槽的总数量, 在迁移过程中提示用户输入。
- --yes 当打印出reshard执行计划时 是否需要用户输入yes确认后再执行reshard。
- --timeout 控制每次migrate操作的超时时间 默认为60000毫秒。
#### 10.4.3 收缩集群
下线节点:
```shell
redistrib.rb del-node{host port}{downNodeId}
```
## 附:[CacheCloud GitHub](https://github.com/sohutv/cachecloud)

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB