Skip to content

Commit 8a757d2

Browse files
committed
Merge branch 'master' of https://github.com/Snailclimb/JavaGuide
2 parents 700d2ec + cc82e27 commit 8a757d2

File tree

1 file changed

+169
-50
lines changed

1 file changed

+169
-50
lines changed
Lines changed: 169 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,68 @@
11
相关阅读:
22

33
- [史上最全Redis高可用技术解决方案大全](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484850&idx=1&sn=3238360bfa8105cf758dcf7354af2814&chksm=cea24a79f9d5c36fb2399aafa91d7fb2699b5006d8d037fe8aaf2e5577ff20ae322868b04a87&token=1082669959&lang=zh_CN&scene=21#wechat_redirect)
4+
- [Raft协议实战之Redis Sentinel的选举Leader源码解析](http://weizijun.cn/2015/04/30/Raft%E5%8D%8F%E8%AE%AE%E5%AE%9E%E6%88%98%E4%B9%8BRedis%20Sentinel%E7%9A%84%E9%80%89%E4%B8%BELeader%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/)
5+
6+
目录:
7+
8+
<!-- TOC -->
9+
10+
- [Redis 集群以及应用](#redis-集群以及应用)
11+
- [集群](#集群)
12+
- [主从复制](#主从复制)
13+
- [主从链(拓扑结构)](#主从链拓扑结构)
14+
- [复制模式](#复制模式)
15+
- [问题点](#问题点)
16+
- [哨兵机制](#哨兵机制)
17+
- [拓扑图](#拓扑图)
18+
- [节点下线](#节点下线)
19+
- [Leader选举](#Leader选举)
20+
- [故障转移](#故障转移)
21+
- [读写分离](#读写分离)
22+
- [定时任务](#定时任务)
23+
- [分布式集群(Cluster)](#分布式集群cluster)
24+
- [拓扑图](#拓扑图)
25+
- [通讯](#通讯)
26+
- [集中式](#集中式)
27+
- [Gossip](#gossip)
28+
- [寻址分片](#寻址分片)
29+
- [hash取模](#hash取模)
30+
- [一致性hash](#一致性hash)
31+
- [hash槽](#hash槽)
32+
- [使用场景](#使用场景)
33+
- [热点数据](#热点数据)
34+
- [会话维持 Session](#会话维持-session)
35+
- [分布式锁 SETNX](#分布式锁-setnx)
36+
- [表缓存](#表缓存)
37+
- [消息队列 list](#消息队列-list)
38+
- [计数器 string](#计数器-string)
39+
- [缓存设计](#缓存设计)
40+
- [更新策略](#更新策略)
41+
- [更新一致性](#更新一致性)
42+
- [缓存粒度](#缓存粒度)
43+
- [缓存穿透](#缓存穿透)
44+
- [解决方案](#解决方案)
45+
- [缓存雪崩](#缓存雪崩)
46+
- [出现后应对](#出现后应对)
47+
- [请求过程](#请求过程)
48+
49+
<!-- /MarkdownTOC -->
450

551
# Redis 集群以及应用
652

753
## 集群
54+
855
### 主从复制
56+
957
#### 主从链(拓扑结构)
58+
1059
![主从](https://user-images.githubusercontent.com/26766909/67539461-d1a26c00-f714-11e9-81ae-61fa89faf156.png)
1160

1261
![主从](https://user-images.githubusercontent.com/26766909/67539485-e0891e80-f714-11e9-8980-d253239fcd8b.png)
1362

1463
#### 复制模式
15-
- 全量复制:master 全部同步到 slave
16-
- 部分复制:slave 数据丢失进行备份
64+
- 全量复制:Master 全部同步到 Slave
65+
- 部分复制:Slave 数据丢失进行备份
1766

1867
#### 问题点
1968
- 同步故障
@@ -26,124 +75,194 @@
2675
- 优化参数不一致:内存不一致.
2776
- 避免全量复制
2877
- 选择小主节点(分片)、低峰期间操作.
29-
- 如果节点运行 id 不匹配(如主节点重启、运行 id 发送变化),此时要执行全量复制,应该配合哨兵和集群解决.
30-
- 主从复制挤压缓冲区不足产生的问题(网络中断,部分复制无法满足),可增大复制缓冲区( rel_backlog_size 参数).
78+
- 如果节点运行 id 不匹配(如主节点重启、运行 id 发送变化)此时要执行全量复制应该配合哨兵和集群解决.
79+
- 主从复制挤压缓冲区不足产生的问题(网络中断部分复制无法满足)可增大复制缓冲区( rel_backlog_size 参数).
3180
- 复制风暴
3281

3382
### 哨兵机制
83+
3484
#### 拓扑图
85+
3586
![image](https://user-images.githubusercontent.com/26766909/67539495-f0086780-f714-11e9-9eab-c11a163ac6c0.png)
3687

3788
#### 节点下线
38-
- 客观下线
39-
- 所有 Sentinel 节点对 Redis 节点失败要达成共识,即超过 quorum 个统一.
89+
4090
- 主观下线
41-
- 即 Sentinel 节点对 Redis 节点失败的偏见,超出超时时间认为 Master 已经宕机.
42-
#### leader选举
43-
- 选举出一个 Sentinel 作为 Leader:集群中至少有三个 Sentinel 节点,但只有其中一个节点可完成故障转移.通过以下命令可以进行失败判定或领导者选举.
91+
- 即 Sentinel 节点对 Redis 节点失败的偏见,超出超时时间认为 Master 已经宕机。
92+
- Sentinel 集群的每一个 Sentinel 节点会定时对 Redis 集群的所有节点发心跳包检测节点是否正常。如果一个节点在 `down-after-milliseconds` 时间内没有回复 Sentinel 节点的心跳包,则该 Redis 节点被该 Sentinel 节点主观下线。
93+
- 客观下线
94+
- 所有 Sentinel 节点对 Redis 节点失败要达成共识,即超过 quorum 个统一。
95+
- 当节点被一个 Sentinel 节点记为主观下线时,并不意味着该节点肯定故障了,还需要 Sentinel 集群的其他 Sentinel 节点共同判断为主观下线才行。
96+
- 该 Sentinel 节点会询问其它 Sentinel 节点,如果 Sentinel 集群中超过 quorum 数量的 Sentinel 节点认为该 Redis 节点主观下线,则该 Redis 客观下线。
97+
98+
#### Leader选举
99+
100+
- 选举出一个 Sentinel 作为 Leader:集群中至少有三个 Sentinel 节点,但只有其中一个节点可完成故障转移.通过以下命令可以进行失败判定或领导者选举。
44101
- 选举流程
45-
1. 每个主观下线的 Sentinel 节点向其他 Sentinel 节点发送命令,要求设置它为领导者.
46-
1. 收到命令的 Sentinel 节点如果没有同意通过其他 Sentinel 节点发送的命令,则同意该请求,否则拒绝.
47-
1. 如果该 Sentinel 节点发现自己的票数已经超过 Sentinel 集合半数且超过 quorum,则它成为领导者.
48-
1. 如果此过程有多个 Sentinel 节点成为领导者,则等待一段时间再重新进行选举.
102+
1. 每个主观下线的 Sentinel 节点向其他 Sentinel 节点发送命令,要求设置它为领导者.
103+
2. 收到命令的 Sentinel 节点如果没有同意通过其他 Sentinel 节点发送的命令,则同意该请求,否则拒绝。
104+
3. 如果该 Sentinel 节点发现自己的票数已经超过 Sentinel 集合半数且超过 quorum,则它成为领导者。
105+
4. 如果此过程有多个 Sentinel 节点成为领导者,则等待一段时间再重新进行选举。
106+
49107
#### 故障转移
108+
50109
- 转移流程
51-
1. Sentinel 选出一个合适的 Slave 作为新的 Master(slaveof no one 命令).
52-
1. 向其余 Slave 发出通知,让它们成为新 Master 的 Slave( parallel-syncs 参数).
53-
1. 等待旧 Master 复活,并使之称为新 Master 的 Slave.
54-
1. 向客户端通知 Master 变化.
110+
1. Sentinel 选出一个合适的 Slave 作为新的 Master(slaveof no one 命令)
111+
2. 向其余 Slave 发出通知让它们成为新 Master 的 Slave( parallel-syncs 参数)
112+
3. 等待旧 Master 复活并使之称为新 Master 的 Slave
113+
4. 向客户端通知 Master 变化
55114
- 从 Slave 中选择新 Master 节点的规则(slave 升级成 master 之后)
56-
1. 选择 slave-priority 最高的节点.
57-
1. 选择复制偏移量最大的节点(同步数据最多).
58-
1. 选择 runId 最小的节点.
115+
1. 选择 slave-priority 最高的节点。
116+
2. 选择复制偏移量最大的节点(同步数据最多)。
117+
3. 选择 runId 最小的节点。
118+
119+
>Sentinel 集群运行过程中故障转移完成,所有 Sentinel 又会恢复平等。Leader 仅仅是故障转移操作出现的角色。
120+
59121
#### 读写分离
122+
60123
#### 定时任务
61-
- 每 1s 每个 Sentinel 对其他 Sentinel 和 Redis 执行 ping,进行心跳检测.
62-
- 每 2s 每个 Sentinel 通过 Master 的 Channel 交换信息(pub - sub).
63-
- 每 10s 每个 Sentinel 对 Master 和 Slave 执行 info,目的是发现 Slave 节点、确定主从关系.
124+
125+
- 每 1s 每个 Sentinel 对其他 Sentinel 和 Redis 执行 ping,进行心跳检测。
126+
- 每 2s 每个 Sentinel 通过 Master 的 Channel 交换信息(pub - sub)。
127+
- 每 10s 每个 Sentinel 对 Master 和 Slave 执行 info,目的是发现 Slave 节点、确定主从关系。
64128

65129
### 分布式集群(Cluster)
130+
66131
#### 拓扑图
67132

68133
![image](https://user-images.githubusercontent.com/26766909/67539510-f8f93900-f714-11e9-9d8d-08afdecff95a.png)
69134

70135
#### 通讯
136+
71137
##### 集中式
72-
> 将集群元数据(节点信息、故障等等)几种存储在某个节点上.
138+
139+
> 将集群元数据(节点信息、故障等等)几种存储在某个节点上。
73140
- 优势
74-
1. 元数据的更新读取具有很强的时效性,元数据修改立即更新
141+
1. 元数据的更新读取具有很强的时效性元数据修改立即更新
75142
- 劣势
76143
1. 数据集中存储
144+
77145
##### Gossip
146+
78147
![image](https://user-images.githubusercontent.com/26766909/67539546-16c69e00-f715-11e9-9891-1e81b6af624c.png)
79148

80149
- [Gossip 协议](https://www.jianshu.com/p/8279d6fd65bb)
81150

82151
#### 寻址分片
152+
83153
##### hash取模
154+
84155
- hash(key)%机器数量
85156
- 问题
86-
1. 机器宕机,造成数据丢失,数据读取失败
157+
1. 机器宕机造成数据丢失数据读取失败
87158
1. 伸缩性
159+
88160
##### 一致性hash
161+
89162
- ![image](https://user-images.githubusercontent.com/26766909/67539595-352c9980-f715-11e9-8e4a-9d9c04027785.png)
90163

91164
- 问题
92165
1. 一致性哈希算法在节点太少时,容易因为节点分布不均匀而造成缓存热点的问题。
93166
- 解决方案
94167
- 可以通过引入虚拟节点机制解决:即对每一个节点计算多个 hash,每个计算结果位置都放置一个虚拟节点。这样就实现了数据的均匀分布,负载均衡。
168+
95169
##### hash槽
170+
96171
- CRC16(key)%16384
97172
-
98173
![image](https://user-images.githubusercontent.com/26766909/67539610-3fe72e80-f715-11e9-8e0d-ea58bc965795.png)
99174

175+
## 使用场景
100176

177+
### 热点数据
101178

179+
存取数据优先从 Redis 操作,如果不存在再从文件(例如 MySQL)中操作,从文件操作完后将数据存储到 Redis 中并返回。同时有个定时任务后台定时扫描 Redis 的 key,根据业务规则进行淘汰,防止某些只访问一两次的数据一直存在 Redis 中。
180+
>例如使用 Zset 数据结构,存储 Key 的访问次数/最后访问时间作为 Score,最后做排序,来淘汰那些最少访问的 Key。
181+
182+
如果企业级应用,可以参考:[阿里云的 Redis 混合存储版][1]
102183

184+
### 会话维持 Session
103185

186+
会话维持 Session 场景,即使用 Redis 作为分布式场景下的登录中心存储应用。每次不同的服务在登录的时候,都会去统一的 Redis 去验证 Session 是否正确。但是在微服务场景,一般会考虑 Redis + JWT 做 Oauth2 模块。
187+
>其中 Redis 存储 JWT 的相关信息主要是留出口子,方便以后做统一的防刷接口,或者做登录设备限制等。
104188
105-
## 使用场景
106-
### 热点数据
107-
### 会话维持 session
108189
### 分布式锁 SETNX
190+
191+
命令格式:`SETNX key value`:当且仅当 key 不存在,将 key 的值设为 value。若给定的 key 已经存在,则 SETNX 不做任何动作。
192+
193+
1. 超时时间设置:获取锁的同时,启动守护线程,使用 expire 进行定时更新超时时间。如果该业务机器宕机,守护线程也挂掉,这样也会自动过期。如果该业务不是宕机,而是真的需要这么久的操作时间,那么增加超时时间在业务上也是可以接受的,但是肯定有个最大的阈值。
194+
2. 但是为了增加高可用,需要使用多台 Redis,就增加了复杂性,就可以参考 Redlock:[Redlock分布式锁](Redlock分布式锁.md#怎么在单节点上实现分布式锁)
195+
109196
### 表缓存
197+
198+
Redis 缓存表的场景有黑名单、禁言表等。访问频率较高,即读高。根据业务需求,可以使用后台定时任务定时刷新 Redis 的缓存表数据。
199+
110200
### 消息队列 list
111-
### 计数器 string
112201

202+
主要使用了 List 数据结构。
203+
List 支持在头部和尾部操作,因此可以实现简单的消息队列。
204+
1. 发消息:在 List 尾部塞入数据。
205+
2. 消费消息:在 List 头部拿出数据。
113206

207+
同时可以使用多个 List,来实现多个队列,根据不同的业务消息,塞入不同的 List,来增加吞吐量。
114208

209+
### 计数器 string
115210

211+
主要使用了 INCR、DECR、INCRBY、DECRBY 方法。
212+
213+
INCR key:给 key 的 value 值增加一
214+
DECR key:给 key 的 value 值减去一
116215

117216
## 缓存设计
217+
118218
### 更新策略
119-
- LRU、LFU、FIFO 算法自动清除:一致性最差,维护成本低.
120-
- 超时自动清除(key expire):一致性较差,维护成本低.
121-
- 主动更新:代码层面控制生命周期,一致性最好,维护成本高.
219+
220+
- LRU、LFU、FIFO 算法自动清除:一致性最差,维护成本低。
221+
- 超时自动清除(key expire):一致性较差,维护成本低。
222+
- 主动更新:代码层面控制生命周期,一致性最好,维护成本高。
223+
224+
在 Redis 根据在 redis.conf 的参数 `maxmemory` 来做更新淘汰策略:
225+
1. noeviction: 不删除策略, 达到最大内存限制时, 如果需要更多内存, 直接返回错误信息。大多数写命令都会导致占用更多的内存(有极少数会例外, 如 DEL 命令)。
226+
2. allkeys-lru: 所有 key 通用; 优先删除最近最少使用(less recently used ,LRU) 的 key。
227+
3. volatile-lru: 只限于设置了 expire 的部分; 优先删除最近最少使用(less recently used ,LRU) 的 key。
228+
4. allkeys-random: 所有key通用; 随机删除一部分 key。
229+
5. volatile-random: 只限于设置了 expire 的部分; 随机删除一部分 key。
230+
6. volatile-ttl: 只限于设置了 expire 的部分; 优先删除剩余时间(time to live,TTL) 短的key。
231+
122232
### 更新一致性
123-
- 读请求:先读缓存,缓存没有的话,就读数据库,然后取出数据后放入缓存,同时返回响应.
124-
- 写请求:先删除缓存,然后再更新数据库(避免大量地写、却又不经常读的数据导致缓存频繁更新).
233+
234+
- 读请求:先读缓存,缓存没有的话,就读数据库,然后取出数据后放入缓存,同时返回响应。
235+
- 写请求:先删除缓存,然后再更新数据库(避免大量地写、却又不经常读的数据导致缓存频繁更新)。
236+
125237
### 缓存粒度
126-
- 通用性:全量属性更好.
127-
- 占用空间:部分属性更好.
128-
- 代码维护成本.
238+
239+
- 通用性:全量属性更好。
240+
- 占用空间:部分属性更好。
241+
- 代码维护成本。
129242

130243
### 缓存穿透
131-
> 当大量的请求无命中缓存、直接请求到后端数据库(业务代码的 bug、或恶意攻击),同时后端数据库也没有查询到相应的记录、无法添加缓存.
132-
这种状态会一直维持,流量一直打到存储层上,无法利用缓存、还会给存储层带来巨大压力.
133-
>
244+
245+
> 当大量的请求无命中缓存、直接请求到后端数据库(业务代码的 bug、或恶意攻击),同时后端数据库也没有查询到相应的记录、无法添加缓存。
246+
> 这种状态会一直维持,流量一直打到存储层上,无法利用缓存、还会给存储层带来巨大压力。
247+
134248
#### 解决方案
249+
135250
1. 请求无法命中缓存、同时数据库记录为空时在缓存添加该 key 的空对象(设置过期时间),缺点是可能会在缓存中添加大量的空值键(比如遭到恶意攻击或爬虫),而且缓存层和存储层数据短期内不一致;
136-
1. 使用布隆过滤器在缓存层前拦截非法请求、自动为空值添加黑名单(同时可能要为误判的记录添加白名单).但需要考虑布隆过滤器的维护(离线生成/ 实时生成).
251+
2. 使用布隆过滤器在缓存层前拦截非法请求、自动为空值添加黑名单(同时可能要为误判的记录添加白名单).但需要考虑布隆过滤器的维护(离线生成/ 实时生成)。
252+
137253
### 缓存雪崩
138-
> 缓存崩溃时请求会直接落到数据库上,很可能由于无法承受大量的并发请求而崩溃,此时如果只重启数据库,或因为缓存重启后没有数据,新的流量进来很快又会把数据库击倒
139-
>
254+
255+
> 缓存崩溃时请求会直接落到数据库上,很可能由于无法承受大量的并发请求而崩溃,此时如果只重启数据库,或因为缓存重启后没有数据,新的流量进来很快又会把数据库击倒。
256+
140257
#### 出现后应对
141-
- 事前:Redis 高可用,主从 + 哨兵,Redis Cluster,避免全盘崩溃.
142-
- 事中:本地 ehcache 缓存 + hystrix 限流 & 降级,避免数据库承受太多压力.
143-
- 事后:Redis 持久化,一旦重启,自动从磁盘上加载数据,快速恢复缓存数据.
144-
#### 请求过程
145-
1. 用户请求先访问本地缓存,无命中后再访问 Redis,如果本地缓存和 Redis 都没有再查数据库,并把数据添加到本地缓存和 Redis;
146-
1. 由于设置了限流,一段时间范围内超出的请求走降级处理(返回默认值,或给出友情提示).
147258

259+
- 事前:Redis 高可用,主从 + 哨兵,Redis Cluster,避免全盘崩溃。
260+
- 事中:本地 ehcache 缓存 + hystrix 限流 & 降级,避免数据库承受太多压力。
261+
- 事后:Redis 持久化,一旦重启,自动从磁盘上加载数据,快速恢复缓存数据。
262+
263+
#### 请求过程
148264

265+
1. 用户请求先访问本地缓存,无命中后再访问 Redis,如果本地缓存和 Redis 都没有再查数据库,并把数据添加到本地缓存和 Redis;
266+
2. 由于设置了限流,一段时间范围内超出的请求走降级处理(返回默认值,或给出友情提示)。
149267

268+
[1]: https://promotion.aliyun.com/ntms/act/redishybridstorage.html?spm=5176.54432.1380373.5.41921cf20pcZrZ&aly_as=ArH4VaEb

0 commit comments

Comments
 (0)