-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathredis02.html
617 lines (577 loc) · 41.5 KB
/
redis02.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
<!DOCTYPE html><html lang="zh-CN" data-theme="dark"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0,viewport-fit=cover"><title>Redis笔记02(自用) | 惜别的秘密基地</title><meta name="author" content="SekiBetu"><meta name="copyright" content="SekiBetu"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#0d0d0d"><meta name="description" content="随手记点笔记,不全,自用 删除策略 定时删除 定时删除,CPU 占用大 惰性删除 过期数据二次访问后才删除,内存占用大 定期删除 随机抽查删除,hz 值决定了 CPU 和内存哪个占用大 淘汰策略 内存不足时按策略删除 maxmemory ?mb 最大可用内存,默认为 0 不限制,一般设置物理机的 50%以上 maxmemory-samples count 每次随机删除的数据">
<meta property="og:type" content="article">
<meta property="og:title" content="Redis笔记02(自用)">
<meta property="og:url" content="https://sekibetu.com/redis02.html">
<meta property="og:site_name" content="惜别的秘密基地">
<meta property="og:description" content="随手记点笔记,不全,自用 删除策略 定时删除 定时删除,CPU 占用大 惰性删除 过期数据二次访问后才删除,内存占用大 定期删除 随机抽查删除,hz 值决定了 CPU 和内存哪个占用大 淘汰策略 内存不足时按策略删除 maxmemory ?mb 最大可用内存,默认为 0 不限制,一般设置物理机的 50%以上 maxmemory-samples count 每次随机删除的数据">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://sekibetu.com/img/67861832_p0.jpg">
<meta property="article:published_time" content="2020-10-10T15:09:23.000Z">
<meta property="article:modified_time" content="2022-08-27T18:00:34.000Z">
<meta property="article:author" content="SekiBetu">
<meta property="article:tag" content="Redis">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://sekibetu.com/img/67861832_p0.jpg"><script type="application/ld+json">{
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": "Redis笔记02(自用)",
"url": "https://sekibetu.com/redis02.html",
"image": "https://sekibetu.com/img/67861832_p0.jpg",
"datePublished": "2020-10-10T15:09:23.000Z",
"dateModified": "2022-08-27T18:00:34.000Z",
"author": [
{
"@type": "Person",
"name": "SekiBetu",
"url": "https://sekibetu.com/"
}
]
}</script><link rel="shortcut icon" href="/favicon.ico"><link rel="canonical" href="https://sekibetu.com/redis02.html"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/css/index.css?v=5.3.2"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/[email protected]/css/all.min.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/snackbar.min.css" media="print" onload="this.media='all'"><script>
(() => {
const saveToLocal = {
set: (key, value, ttl) => {
if (!ttl) return
const expiry = Date.now() + ttl * 86400000
localStorage.setItem(key, JSON.stringify({ value, expiry }))
},
get: key => {
const itemStr = localStorage.getItem(key)
if (!itemStr) return undefined
const { value, expiry } = JSON.parse(itemStr)
if (Date.now() > expiry) {
localStorage.removeItem(key)
return undefined
}
return value
}
}
window.btf = {
saveToLocal,
getScript: (url, attr = {}) => new Promise((resolve, reject) => {
const script = document.createElement('script')
script.src = url
script.async = true
Object.entries(attr).forEach(([key, val]) => script.setAttribute(key, val))
script.onload = script.onreadystatechange = () => {
if (!script.readyState || /loaded|complete/.test(script.readyState)) resolve()
}
script.onerror = reject
document.head.appendChild(script)
}),
getCSS: (url, id) => new Promise((resolve, reject) => {
const link = document.createElement('link')
link.rel = 'stylesheet'
link.href = url
if (id) link.id = id
link.onload = link.onreadystatechange = () => {
if (!link.readyState || /loaded|complete/.test(link.readyState)) resolve()
}
link.onerror = reject
document.head.appendChild(link)
}),
addGlobalFn: (key, fn, name = false, parent = window) => {
if (!true && key.startsWith('pjax')) return
const globalFn = parent.globalFn || {}
globalFn[key] = globalFn[key] || {}
globalFn[key][name || Object.keys(globalFn[key]).length] = fn
parent.globalFn = globalFn
}
}
const activateDarkMode = () => {
document.documentElement.setAttribute('data-theme', 'dark')
if (document.querySelector('meta[name="theme-color"]') !== null) {
document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
}
}
const activateLightMode = () => {
document.documentElement.setAttribute('data-theme', 'light')
if (document.querySelector('meta[name="theme-color"]') !== null) {
document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
}
}
btf.activateDarkMode = activateDarkMode
btf.activateLightMode = activateLightMode
const theme = saveToLocal.get('theme')
theme === 'dark' ? activateDarkMode() : theme === 'light' ? activateLightMode() : null
const asideStatus = saveToLocal.get('aside-status')
if (asideStatus !== undefined) {
document.documentElement.classList.toggle('hide-aside', asideStatus === 'hide')
}
const detectApple = () => {
if (/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)) {
document.documentElement.classList.add('apple')
}
}
detectApple()
})()
</script><link rel="stylesheet" href="/font/JetBrainsMono-Regular.ttf" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = {
root: '/',
algolia: undefined,
localSearch: undefined,
translate: undefined,
highlight: {"plugin":"highlight.js","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false,"highlightFullpage":false,"highlightMacStyle":true},
copy: {
success: '复制成功',
error: '复制失败',
noSupport: '浏览器不支持'
},
relativeDate: {
homepage: false,
post: false
},
runtime: '',
dateSuffix: {
just: '刚刚',
min: '分钟前',
hour: '小时前',
day: '天前',
month: '个月前'
},
copyright: undefined,
lightbox: 'null',
Snackbar: {"chs_to_cht":"已切换为繁体中文","cht_to_chs":"已切换为简体中文","day_to_night":"已切换为深色模式","night_to_day":"已切换为浅色模式","bgLight":"#49b1f5","bgDark":"#1f1f1f","position":"bottom-left"},
infinitegrid: {
js: 'https://cdn.jsdelivr.net/npm/@egjs/[email protected]/dist/infinitegrid.min.js',
buttonText: '加载更多'
},
isPhotoFigcaption: false,
islazyloadPlugin: false,
isAnchor: false,
percent: {
toc: true,
rightside: true,
},
autoDarkmode: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
title: 'Redis笔记02(自用)',
isHighlightShrink: false,
isToc: true,
pageType: 'post'
}</script><meta name="generator" content="Hexo 7.3.0"><link rel="alternate" href="/atom.xml" title="惜别的秘密基地" type="application/atom+xml">
</head><body><div id="web_bg" style="background-image: url(/img/48036836_p0.jpg);"></div><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img text-center"><img src="/img/SekiBetu.png" onerror="this.onerror=null;this.src='/img/Starfetcher.jpg'" alt="avatar"/></div><div class="site-data text-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">18</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">27</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">0</div></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg" id="page-header" style="background-image: url(/img/67861832_p0.jpg);"><nav id="nav"><span id="blog-info"><a class="nav-site-title" href="/"><span class="site-name">惜别的秘密基地</span></a><a class="nav-page-title" href="/"><span class="site-name">Redis笔记02(自用)</span></a></span><div id="menus"><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div></div><div id="toggle-menu"><span class="site-page"><i class="fas fa-bars fa-fw"></i></span></div></div></nav><div id="post-info"><h1 class="post-title">Redis笔记02(自用)</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2020-10-10T15:09:23.000Z" title="发表于 2020-10-10 23:09:23">2020-10-10</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2022-08-27T18:00:34.000Z" title="更新于 2022-08-28 02:00:34">2022-08-28</time></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">总字数:</span><span class="word-count">1.7k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>5分钟</span></span><span class="post-meta-separator">|</span><span class="post-meta-pv-cv" id="" data-flag-title=""><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">浏览量:</span><span id="busuanzi_value_page_pv"><i class="fa-solid fa-spinner fa-spin"></i></span></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="container post-content" id="article-container"><div id="post-outdate-notice" data="{"limitDay":365,"messagePrev":"本文创建在","messageNext":"天前,其中的内容有可能已经过时","postUpdate":"2022-08-28 02:00:34"}" hidden></div><p>随手记点笔记,不全,自用</p>
<h2 id="删除策略">删除策略</h2>
<h3 id="定时删除">定时删除</h3>
<ul>
<li>定时删除,CPU 占用大</li>
</ul>
<h3 id="惰性删除">惰性删除</h3>
<ul>
<li>过期数据二次访问后才删除,内存占用大</li>
</ul>
<h3 id="定期删除">定期删除</h3>
<ul>
<li>随机抽查删除,hz 值决定了 CPU 和内存哪个占用大</li>
</ul>
<h3 id="淘汰策略">淘汰策略</h3>
<ul>
<li>
<p>内存不足时按策略删除</p>
<ul>
<li>
<p>maxmemory ?mb 最大可用内存,默认为 0 不限制,一般设置物理机的 50%以上</p>
</li>
<li>
<p>maxmemory-samples count 每次随机删除的数据个数</p>
</li>
<li>
<p>maxmemory-policy policy 删除策略</p>
<ul>
<li>
<p>volatile 易失数据</p>
<ul>
<li>volatile-lru 按最后一次使用时间</li>
<li>volatile-lfu 按最近使用次数</li>
<li>volatile-ttl 按即将过期的数据</li>
<li>volatile-random 随机</li>
</ul>
</li>
<li>
<p>allkeys 全库数据</p>
<ul>
<li>allkeys-lru 按最后一次使用时间</li>
<li>allkeys-lfu 按最近使用次数</li>
<li>allkeys-random 随机</li>
</ul>
</li>
<li>
<p>no-enviction 放弃数据驱逐</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="主从复制">主从复制</h2>
<h3 id="建立连接的流程">建立连接的流程</h3>
<ul>
<li>设置 master 地址和端口并保存</li>
<li>建立 socket 连接</li>
<li>发送 ping 命令(定时器任务)</li>
<li>身份验证</li>
<li>发送 slave 端口信息</li>
</ul>
<h3 id="数据同步">数据同步</h3>
<ul>
<li>
<p>全量复制</p>
<ul>
<li>发送指令 psync2 <runid> <offset></li>
<li>执行 bgsave</li>
<li>第一个 slave 连接时创建命令缓冲区</li>
<li>生成 RDB 文件通过 socket 发给 slave</li>
<li>接收 RDB,清空数据,执行恢复过程</li>
</ul>
</li>
<li>
<p>部分复制</p>
<ul>
<li>发送命令告知 RDB 已经恢复完成</li>
<li>发送复制缓冲区信息</li>
<li>接收信息,执行 bgrewriteaof,恢复数据</li>
</ul>
</li>
<li>
<p>心跳机制</p>
<ul>
<li>
<p>master 心跳</p>
<ul>
<li>内部指令 PING</li>
<li>周期 repl-ping-slave-period 默认 10 秒</li>
<li>INFO replication 获取 slave 最后一次连接时间间隔,lag 项维持在 0 或 1 视为正常</li>
</ul>
</li>
<li>
<p>slave 心跳</p>
<ul>
<li>内部指令 REPLCONF ACK {offset}</li>
<li>周期 1 秒</li>
<li>汇报 slave 自己的复制偏移量,获取最新的数据变更指令</li>
<li>判断 master 是否在线</li>
</ul>
</li>
</ul>
</li>
<li>
<p>注意事项</p>
<ul>
<li>master 数据同步应避开流量高峰期</li>
<li>复制缓冲区太小会导致数据溢出,出现数据丢失并自动进行二次全量复制,死循环 repl=backlog-size ?mb 建议留下 30%~50%的内存用于执行 bgsave 命令和创建复制缓冲区</li>
<li>避免 slave 同步过程服务器响应阻塞或者数据不同步,建议关闭此期间的对外服务 slave-serve-stale-data yes | no</li>
<li>数据同步阶段,master 主动发送命令给 slave,可以理解为是一个客户端</li>
<li>多个 slave 同时对 master 请求同步,RDB 只会有一份,但是带宽压力变大,可以适量错峰但是 RDB 会有多份</li>
<li>slave 过多可以采用树状结构,但是数据一致性差</li>
</ul>
</li>
</ul>
<h2 id="哨兵模式">哨兵模式</h2>
<h3 id="检测-master-是否宕机,master-宕机后选举-slave-为-master">检测 master 是否宕机,master 宕机后选举 slave 为 master</h3>
<h3 id="建立过程配置">建立过程配置</h3>
<ul>
<li>sentinel monitor master_name master_host master_port sentinel_number 设置监听的主服务器信息,sentinel_number 表示参与投票的哨兵数量</li>
<li>sentinel down-after-milliseconds master_name million_seconds 设置宕机时长,控制是否进行主从切换</li>
<li>sentinel failover-timeout master_name million_seconds 设置故障切换操作的最大超时时长</li>
<li>sentinel parallel-syncs master_name sync_slave_number 设置主从切换后,同时进行数据同步的 slave 数量,越大网络资源要求越高,越小同步时间越长</li>
</ul>
<h3 id="监控阶段">监控阶段</h3>
<ul>
<li>检查各个哨兵是否在线</li>
<li>先向 master 发 info 查询其信息和名下 slave</li>
<li>再向 slave 发 info 查询 slave 具体信息</li>
</ul>
<h3 id="故障转移阶段">故障转移阶段</h3>
<ul>
<li>
<p>单个哨兵监测到 master 无响应(主观下线) SRI_S_DOWN</p>
</li>
<li>
<p>半数哨兵监测到 master 无响应(客观下线) SRI_O_DOWN</p>
</li>
<li>
<p>哨兵选举</p>
</li>
<li>
<p>选举 master 优先级</p>
<ul>
<li>
<p>不在线的</p>
</li>
<li>
<p>响应慢的</p>
</li>
<li>
<p>与原来 master 断开连接时间长的</p>
</li>
<li>
<p>优先原则</p>
<ul>
<li>优先级</li>
<li>offset 偏移量大</li>
<li>runid</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="Cluster-集群">Cluster 集群</h2>
<h3 id="数据存储结构">数据存储结构</h3>
<ul>
<li>
<p>保存流程</p>
<ul>
<li>CRC(key)%16384 计算结果为某台服务器中的槽位地址,该槽位不止存储一个 key,而是大量 key</li>
</ul>
</li>
<li>
<p>查询流程</p>
<ul>
<li>各个数据库相互通信,保存各个库中槽位的编号数据</li>
<li>一次查询命中直接返回</li>
<li>一次未命中,告知具体的位置</li>
</ul>
</li>
</ul>
<h3 id="配置">配置</h3>
<ul>
<li>cluster-enabled yes|no 是否启用 cluster,加入 cluster 节点</li>
<li>cluster-config-file filename cluster 配置文件名,该文件会自动生成,尽量手动命名否则会共用</li>
<li>cluster-node-timeout milliseconds 节点服务响应超时时间</li>
<li>cluster-migration-barrier min_slave_number master 连接的 slave 最小数量</li>
</ul>
<h2 id="企业级解决方案">企业级解决方案</h2>
<h3 id="缓存预热">缓存预热</h3>
<ul>
<li>现象:启动服务器后立刻宕机</li>
<li>解决思路:系统启动前,提前将相关的缓存数据直接加载到缓存系统。避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!</li>
</ul>
<h3 id="缓存雪崩">缓存雪崩</h3>
<ul>
<li>
<p>现象:短时间范围内,大量 key 集中过期导致一系列宕机</p>
</li>
<li>
<p>解决思路</p>
<ul>
<li>更多的页面静态化处理</li>
<li>构建多级缓存架构<br>
Nginx 缓存+redis 缓存+ehcache 缓存</li>
<li>检测 Mysql 严重耗时业务进行优化<br>
对数据库的瓶颈排查:例如超时查询、耗时较高事务等</li>
<li>预警机制</li>
<li>限流、降级</li>
</ul>
</li>
<li>
<p>具体解决方案</p>
<ul>
<li>切换为 LFU 淘汰策略</li>
<li>调整过期的时间,使其错峰</li>
<li>超热数据暂时使用永久 key</li>
<li>定期维护(自动+人工)<br>
对即将过期数据做访问量分析,确认是否延时,配合访问量统计,做热点数据的延时</li>
<li>加锁:慎用!</li>
</ul>
</li>
</ul>
<h3 id="缓存击穿">缓存击穿</h3>
<ul>
<li>
<p>现象:Redis 中某个高热点 key 过期,该 key 访问量巨大</p>
</li>
<li>
<p>解决方案</p>
<ul>
<li>增加热点 key 的时间</li>
<li>设置热点 key 为永久</li>
<li>高峰期来临前自动刷新有效期</li>
<li>二级缓存,设置不同的过期时间错峰</li>
<li>分布式锁</li>
</ul>
</li>
</ul>
<h3 id="缓存穿透">缓存穿透</h3>
<ul>
<li>
<p>现象:黑客大量访问不存在的数据,跳过 redis 直接攻击数据库</p>
</li>
<li>
<p>解决方案</p>
<ul>
<li>1、对查询结果为 null 的数据进行缓存(长期使用,定期清理),设定短时限,例如 30-60 秒,最高 5 分钟</li>
<li>2、白名单策略<br>
提前预热各种分类数据 id 对应的 bitmaps,id 作为 bitmaps 的 offset,相当于设置了数据白名单。当加载正常数据时放行,加载异常数据时直接拦截(效率偏低)<br>
使用布隆过滤器(有关布隆过滤器的命中问题对当前状况可以忽略)</li>
<li>3、实时监控 redis 命中率,提前预防,使用黑名单进行防控</li>
<li>4、key 加密<br>
问题出现后,临时启动防灾业务 key,对 key 进行业务层传输加密服务,设定校验程序,过来的 key 校验<br>
例如每天随机分配 60 个加密串,挑选 2 到 3 个,混淆到页面数据 id 中,发现访问 key 不满足规则,驳回数据访问</li>
</ul>
</li>
</ul>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta"><i class="fas fa-circle-user fa-fw"></i>文章作者: </span><span class="post-copyright-info"><a href="https://sekibetu.com">SekiBetu</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta"><i class="fas fa-square-arrow-up-right fa-fw"></i>文章链接: </span><span class="post-copyright-info"><a href="https://sekibetu.com/redis02.html">https://sekibetu.com/redis02.html</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta"><i class="fas fa-circle-exclamation fa-fw"></i>版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外,均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来源 <a href="https://sekibetu.com" target="_blank">惜别的秘密基地</a>!</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/Redis/">Redis</a></div><div class="post-share"><div class="social-share" data-image="/img/67861832_p0.jpg" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/sharejs/dist/css/share.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/[email protected]/sharejs/dist/js/social-share.min.js" defer></script></div></div><nav class="pagination-post" id="pagination"><a class="pagination-related" href="/mybatis01.html" title="MyBatis如何获取刚刚插入数据的ID"><img class="cover" src="/img/67861832_p0.jpg" onerror="onerror=null;src='/img/Starfetcher.jpg'" alt="cover of previous post"><div class="info"><div class="info-1"><div class="info-item-1">上一篇</div><div class="info-item-2">MyBatis如何获取刚刚插入数据的ID</div></div><div class="info-2"><div class="info-item-1"> 有时业务逻辑中需要获取刚刚插入的数据的自增 ID 值以用于后续使用,MyBatis 提供了 LAST_INSERT_ID() 函数获取该 ID 值: 1234567891011<mapper> <insert id="add" parameterType="pojo"> <!--insert操作结束后查询最后一条插入的数据的ID值并将其赋值给pojo对象中的id属性--> <selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id"> select LAST_INSERT_ID() </selectKey> insert into table(items) values(#{items}) ...</div></div></div></a><a class="pagination-related" href="/docker01.html" title="Docker笔记(自用)"><img class="cover" src="/img/67861832_p0.jpg" onerror="onerror=null;src='/img/Starfetcher.jpg'" alt="cover of next post"><div class="info text-right"><div class="info-1"><div class="info-item-1">下一篇</div><div class="info-item-2">Docker笔记(自用)</div></div><div class="info-2"><div class="info-item-1">随手记点笔记,不全,自用 Docker 基础命令 服务相关命令 systemctl start docker systemctl stop docker systemctl restart docker systemctl status docker systemctl enable docker 为 docker 服务设置开机自启 镜像相关命令 docker images 查看本地镜像 docker search 镜像名称 搜索镜像 docker pull 镜像名称:版本号 从 docker 仓库拉取某版本的镜像到本地 docker build 创建 dockerfile 镜像 容器相关命令 docker ps -a 查看所有本地容器 举例:docker run -it --name=cl centos:7 /bin/bash 创建一个名为 cl 的 centos7 的容器并以 bash 这个 shell 进入交互式界面 exit 可以退出容器但会使带-t 参数的交互式容器停止,所以要避免-t 参数的使用,但是可以使用^p^q...</div></div></div></a></nav><div class="relatedPosts"><div class="headline"><i class="fas fa-thumbs-up fa-fw"></i><span>相关推荐</span></div><div class="relatedPosts-list"><a class="pagination-related" href="/redis01.html" title="Redis笔记(自用)"><img class="cover" src="/img/67861832_p0.jpg" alt="cover"><div class="info text-center"><div class="info-1"><div class="info-item-1"><i class="far fa-calendar-alt fa-fw"></i> 2020-08-01</div><div class="info-item-2">Redis笔记(自用)</div></div><div class="info-2"><div class="info-item-1">Redis Redis: Remote Dictionary Server 三个特点: Redis 支持数据持久化. 可以将内存中的数据保持在磁盘中, 重启后可再次使用 Redis 支持 key-val, list, set, zset, hash 等数据结构存储 Redis 支持数据备份, master-slave 模式数据备份 零碎基础知识 单进程 (*) 单进程处理客户端的请求, 对读写事件响应是通过 epoll 函数而包装来操作. Redis 实际处理速度完全依靠主进程执行效率 默认 16 个数据库, 类似数组下标从 0 开始, 初始默认使用 0 号库 select 切换数据库 dbsize 查看当前数据库的 key 的数量 flushdb 清空当前数据库 flushall 删全部库 统一密码管理, 16 个库同一个密码 Redis 索引是从 0 开始 默认端口 6379 Redis 数据类型 五大数据类型 String (字符串) Hash (哈希, 类似 Java HashMap) List (列表) Set (集合) Zset (Sorted Set:...</div></div></div></a></div></div><hr class="custom-hr"/><div id="post-comment"><div class="comment-head"><div class="comment-headline"><i class="fas fa-comments fa-fw"></i><span> 评论</span></div><div class="comment-switch"><span class="first-comment">Utterances</span><span id="switch-btn"></span><span class="second-comment">Giscus</span></div></div><div class="comment-wrap"><div><div id="utterances-wrap"></div></div><div><div id="giscus-wrap"></div></div></div></div></div><div class="aside-content" id="aside-content"><div class="card-widget card-info text-center"><div class="avatar-img"><img src="/img/SekiBetu.png" onerror="this.onerror=null;this.src='/img/Starfetcher.jpg'" alt="avatar"/></div><div class="author-info-name">SekiBetu</div><div class="author-info-description">记录与分享各种东西</div><div class="site-data"><a href="/archives/"><div class="headline">文章</div><div class="length-num">18</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">27</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">0</div></a></div><a id="card-info-btn" target="_blank" rel="noopener" href="https://github.com/SekiBetu"><i class="fab fa-github"></i><span>Follow Me</span></a><div class="card-info-social-icons"><a class="social-icon" href="https://twitter.com/_SekiBetu_" target="_blank" title="Twitter"><i class="fab fa-twitter"></i></a><a class="social-icon" href="mailto:[email protected]" target="_blank" title="Email"><i class="fas fa-envelope"></i></a><a class="social-icon" href="https://sekibetu.com/atom.xml" target="_blank" title="RSS"><i class="fas fa-rss"></i></a></div></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn fa-shake"></i><span>公告</span></div><div class="announcement_content">This is my Blog</div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content is-expand"><ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%88%A0%E9%99%A4%E7%AD%96%E7%95%A5"><span class="toc-number">1.</span> <span class="toc-text">删除策略</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%AE%9A%E6%97%B6%E5%88%A0%E9%99%A4"><span class="toc-number">1.1.</span> <span class="toc-text">定时删除</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%83%B0%E6%80%A7%E5%88%A0%E9%99%A4"><span class="toc-number">1.2.</span> <span class="toc-text">惰性删除</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%AE%9A%E6%9C%9F%E5%88%A0%E9%99%A4"><span class="toc-number">1.3.</span> <span class="toc-text">定期删除</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%B7%98%E6%B1%B0%E7%AD%96%E7%95%A5"><span class="toc-number">1.4.</span> <span class="toc-text">淘汰策略</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6"><span class="toc-number">2.</span> <span class="toc-text">主从复制</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%BB%BA%E7%AB%8B%E8%BF%9E%E6%8E%A5%E7%9A%84%E6%B5%81%E7%A8%8B"><span class="toc-number">2.1.</span> <span class="toc-text">建立连接的流程</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%95%B0%E6%8D%AE%E5%90%8C%E6%AD%A5"><span class="toc-number">2.2.</span> <span class="toc-text">数据同步</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%93%A8%E5%85%B5%E6%A8%A1%E5%BC%8F"><span class="toc-number">3.</span> <span class="toc-text">哨兵模式</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%A3%80%E6%B5%8B-master-%E6%98%AF%E5%90%A6%E5%AE%95%E6%9C%BA%EF%BC%8Cmaster-%E5%AE%95%E6%9C%BA%E5%90%8E%E9%80%89%E4%B8%BE-slave-%E4%B8%BA-master"><span class="toc-number">3.1.</span> <span class="toc-text">检测 master 是否宕机,master 宕机后选举 slave 为 master</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%BB%BA%E7%AB%8B%E8%BF%87%E7%A8%8B%E9%85%8D%E7%BD%AE"><span class="toc-number">3.2.</span> <span class="toc-text">建立过程配置</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%9B%91%E6%8E%A7%E9%98%B6%E6%AE%B5"><span class="toc-number">3.3.</span> <span class="toc-text">监控阶段</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%95%85%E9%9A%9C%E8%BD%AC%E7%A7%BB%E9%98%B6%E6%AE%B5"><span class="toc-number">3.4.</span> <span class="toc-text">故障转移阶段</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Cluster-%E9%9B%86%E7%BE%A4"><span class="toc-number">4.</span> <span class="toc-text">Cluster 集群</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%95%B0%E6%8D%AE%E5%AD%98%E5%82%A8%E7%BB%93%E6%9E%84"><span class="toc-number">4.1.</span> <span class="toc-text">数据存储结构</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%85%8D%E7%BD%AE"><span class="toc-number">4.2.</span> <span class="toc-text">配置</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BC%81%E4%B8%9A%E7%BA%A7%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88"><span class="toc-number">5.</span> <span class="toc-text">企业级解决方案</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BC%93%E5%AD%98%E9%A2%84%E7%83%AD"><span class="toc-number">5.1.</span> <span class="toc-text">缓存预热</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BC%93%E5%AD%98%E9%9B%AA%E5%B4%A9"><span class="toc-number">5.2.</span> <span class="toc-text">缓存雪崩</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BC%93%E5%AD%98%E5%87%BB%E7%A9%BF"><span class="toc-number">5.3.</span> <span class="toc-text">缓存击穿</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BC%93%E5%AD%98%E7%A9%BF%E9%80%8F"><span class="toc-number">5.4.</span> <span class="toc-text">缓存穿透</span></a></li></ol></li></ol></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/linus01.html" title="对Linux社区封禁俄罗斯开发者且linus本人支持这一行为的评价">对Linux社区封禁俄罗斯开发者且linus本人支持这一行为的评价</a><time datetime="2024-10-24T13:54:15.000Z" title="发表于 2024-10-24 21:54:15">2024-10-24</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/followis.html" title="三分钟,让Follow认证我的Hexo博客订阅源">三分钟,让Follow认证我的Hexo博客订阅源</a><time datetime="2024-10-14T12:04:50.000Z" title="发表于 2024-10-14 20:04:50">2024-10-14</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/rss01.html" title="给 Hexo 博客加上 PubSubHubbub 协议实现 RSS 实时推送">给 Hexo 博客加上 PubSubHubbub 协议实现 RSS 实时推送</a><time datetime="2022-06-29T21:55:05.000Z" title="发表于 2022-06-30 05:55:05">2022-06-30</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/sniff01.html" title="抓取安卓端FGO游戏数据并导入素材规划软件Chaldea教程(需解锁BootLoader)">抓取安卓端FGO游戏数据并导入素材规划软件Chaldea教程(需解锁BootLoader)</a><time datetime="2022-06-08T11:58:22.000Z" title="发表于 2022-06-08 19:58:22">2022-06-08</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/ssh01.html" title="SSH客户端简单对比">SSH客户端简单对比</a><time datetime="2022-06-07T14:37:06.000Z" title="发表于 2022-06-07 22:37:06">2022-06-07</time></div></div></div></div></div></div></main><footer id="footer" style="background-image: url(/img/67861832_p0.jpg);"><div id="footer-wrap"><div class="copyright">©2020 - 2025 By SekiBetu</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div><div class="footer_custom_text"><a href="https://icp.gov.moe/?keyword=20213842" target="_blank">萌ICP备20213842号</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="darkmode" type="button" title="日间和夜间模式切换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside-config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><a id="to_comment" href="#post-comment" title="前往评论"><i class="fas fa-comments"></i></a><button id="go-up" type="button" title="回到顶部"><span class="scroll-percent"></span><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/js/utils.js?v=5.3.2"></script><script src="/js/main.js?v=5.3.2"></script><script src="https://cdn.jsdelivr.net/npm/[email protected]/instantpage.min.js" type="module"></script><script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/snackbar.min.js"></script><div class="js-pjax"><script>(() => {
const isShuoshuo = GLOBAL_CONFIG_SITE.pageType === 'shuoshuo'
const option = null
const getUtterancesTheme = theme => theme === 'dark' ? 'github-dark' : 'github-light'
const loadUtterances = (el = document, key) => {
if (isShuoshuo) {
window.shuoshuoComment.destroyUtterances = () => {
if (el.children.length) {
el.innerHTML = ''
el.classList.add('no-comment')
}
}
}
const config = {
src: 'https://utteranc.es/client.js',
repo: 'SekiBetu/BlogComments',
theme: getUtterancesTheme(document.documentElement.getAttribute('data-theme')),
crossorigin: 'anonymous',
async: true,
...option,
'issue-term': isShuoshuo ? key : (option && option['issue-term']) || 'title'
}
const ele = document.createElement('script')
Object.entries(config).forEach(([key, value]) => ele.setAttribute(key, value))
el.querySelector('#utterances-wrap').appendChild(ele)
}
const changeUtterancesTheme = theme => {
const iframe = document.querySelector('#utterances-wrap iframe')
if (iframe) {
const message = {
type: 'set-theme',
theme: getUtterancesTheme(theme)
};
iframe.contentWindow.postMessage(message, 'https://utteranc.es')
}
}
btf.addGlobalFn('themeChange', changeUtterancesTheme, 'utterances')
if (isShuoshuo) {
'Utterances' === 'Utterances'
? window.shuoshuoComment = { loadComment: loadUtterances }
: window.loadOtherComment = loadUtterances
return
}
if ('Utterances' === 'Utterances' || !false) {
if (false) btf.loadComment(document.getElementById('utterances-wrap'), loadUtterances)
else loadUtterances()
} else {
window.loadOtherComment = loadUtterances
}
})()</script><script>(() => {
const isShuoshuo = GLOBAL_CONFIG_SITE.pageType === 'shuoshuo'
const option = null
const getGiscusTheme = theme => theme === 'dark' ? 'dark' : 'light'
const createScriptElement = config => {
const ele = document.createElement('script')
Object.entries(config).forEach(([key, value]) => {
ele.setAttribute(key, value)
})
return ele
}
const loadGiscus = (el = document, key) => {
const mappingConfig = isShuoshuo
? { 'data-mapping': 'specific', 'data-term': key }
: { 'data-mapping': (option && option['data-mapping']) || 'pathname' }
const giscusConfig = {
src: 'https://giscus.app/client.js',
'data-repo': 'SekiBetu/BlogComments',
'data-repo-id': 'MDEwOlJlcG9zaXRvcnk0MDU2MzIxMzY=',
'data-category-id': 'DIC_kwDOGC10iM4CPwsn',
'data-theme': getGiscusTheme(document.documentElement.getAttribute('data-theme')),
'data-reactions-enabled': '1',
crossorigin: 'anonymous',
async: true,
...option,
...mappingConfig
}
const scriptElement = createScriptElement(giscusConfig)
el.querySelector('#giscus-wrap').appendChild(scriptElement)
if (isShuoshuo) {
window.shuoshuoComment.destroyGiscus = () => {
if (el.children.length) {
el.innerHTML = ''
el.classList.add('no-comment')
}
}
}
}
const changeGiscusTheme = theme => {
const iframe = document.querySelector('#giscus-wrap iframe')
if (iframe) {
const message = {
giscus: {
setConfig: {
theme: getGiscusTheme(theme)
}
}
}
iframe.contentWindow.postMessage(message, 'https://giscus.app')
}
}
btf.addGlobalFn('themeChange', changeGiscusTheme, 'giscus')
if (isShuoshuo) {
'Utterances' === 'Giscus'
? window.shuoshuoComment = { loadComment: loadGiscus }
: window.loadOtherComment = loadGiscus
return
}
if ('Utterances' === 'Giscus' || !false) {
if (false) btf.loadComment(document.getElementById('giscus-wrap'), loadGiscus)
else loadGiscus()
} else {
window.loadOtherComment = loadGiscus
}
})()</script></div><div class="aplayer no-destroy" data-id="18480" data-server="netease" data-type="artist" data-fixed="true" data-mini="true" data-order="random" data-preload="metadata" data-autoplay="true" data-lrctype="3"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/APlayer.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/APlayer.min.js"></script><script src="https://cdn.jsdelivr.net/npm/[email protected]/metingjs/dist/Meting.min.js"></script><script>(() => {
const destroyAplayer = () => {
if (window.aplayers) {
for (let i = 0; i < window.aplayers.length; i++) {
if (!window.aplayers[i].options.fixed) {
window.aplayers[i].destroy()
}
}
}
}
const runMetingJS = () => {
typeof loadMeting === 'function' && document.getElementsByClassName('aplayer').length && loadMeting()
}
btf.addGlobalFn('pjaxSend', destroyAplayer, 'destroyAplayer')
btf.addGlobalFn('pjaxComplete', loadMeting, 'runMetingJS')
})()</script><script src="https://cdn.jsdelivr.net/npm/[email protected]/pjax.min.js"></script><script>(() => {
const pjaxSelectors = ["link[rel=\"canonical\"]","meta[property=\"og:image\"]","meta[property=\"og:title\"]","meta[property=\"og:url\"]","head > title","#config-diff","#body-wrap","#rightside-config-hide","#rightside-config-show",".js-pjax"]
window.pjax = new Pjax({
elements: 'a:not([target="_blank"])',
selectors: pjaxSelectors,
cacheBust: false,
analytics: false,
scrollRestoration: false
})
const triggerPjaxFn = (val) => {
if (!val) return
Object.values(val).forEach(fn => fn())
}
document.addEventListener('pjax:send', () => {
// removeEventListener
btf.removeGlobalFnEvent('pjaxSendOnce')
btf.removeGlobalFnEvent('themeChange')
// reset readmode
const $bodyClassList = document.body.classList
if ($bodyClassList.contains('read-mode')) $bodyClassList.remove('read-mode')
triggerPjaxFn(window.globalFn.pjaxSend)
})
document.addEventListener('pjax:complete', () => {
btf.removeGlobalFnEvent('pjaxCompleteOnce')
document.querySelectorAll('script[data-pjax]').forEach(item => {
const newScript = document.createElement('script')
const content = item.text || item.textContent || item.innerHTML || ""
Array.from(item.attributes).forEach(attr => newScript.setAttribute(attr.name, attr.value))
newScript.appendChild(document.createTextNode(content))
item.parentNode.replaceChild(newScript, item)
})
triggerPjaxFn(window.globalFn.pjaxComplete)
})
document.addEventListener('pjax:error', e => {
if (e.request.status === 404) {
pjax.loadUrl('/404.html')
}
})
})()</script><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script></div></body></html>