Welcome to mirror list, hosted at ThFree Co, Russian Federation.

index.html « replication « 11 « 2019 - github.com/xiaoheiAh/hugo-theme-pure.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: c6f4055cf9394ec991719d594548da05b3ebe30c (plain)
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
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
<!DOCTYPE html>
<html lang="zh">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <title>
        Redis-复制功能探索 - 赵小黑的博客
      </title>
    <head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <meta name="viewport"
    content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui">
  <meta name="renderer" content="webkit">
  <meta http-equiv="Cache-Control" content="no-transform" />
  <meta http-equiv="Cache-Control" content="no-siteapp" />
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
  <meta name="format-detection" content="telephone=no,email=no,adress=no">
  
  <meta name="theme-color" content="#000000" />
  
  <meta http-equiv="window-target" content="_top" />
  
  
  <meta name="description" content="之前对redis 的复制只有一点点了解,这次想要搞明白的是:如何实现的复制? 复制会遇到哪些问题(时延/一致性保证/网络故障时的处理)? 如何解决?高可用实现方案?
文章有部分是直接翻译的 https://redis.io/topics/replication
" />
  <meta name="generator" content="Hugo 0.58.0 with theme pure" />
  <title>Redis-复制功能探索 - 赵小黑的博客</title>
  

  <link rel="stylesheet" href="https://xiaohei.im/hugo-theme-pure/css/style.css">
  <link rel="stylesheet" href="https://cdn.staticfile.org/highlight.js/9.15.10/styles/github.min.css"> 
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.css">
  <meta property="og:title" content="Redis-复制功能探索" />
<meta property="og:description" content="之前对redis 的复制只有一点点了解,这次想要搞明白的是:如何实现的复制? 复制会遇到哪些问题(时延/一致性保证/网络故障时的处理)? 如何解决?高可用实现方案?

文章有部分是直接翻译的 https://redis.io/topics/replication" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://xiaohei.im/hugo-theme-pure/2019/11/replication/" />
<meta property="article:published_time" content="2019-11-16T14:24:40+08:00" />
<meta property="article:modified_time" content="2019-11-16T14:24:40+08:00" />
<meta itemprop="name" content="Redis-复制功能探索">
<meta itemprop="description" content="之前对redis 的复制只有一点点了解,这次想要搞明白的是:如何实现的复制? 复制会遇到哪些问题(时延/一致性保证/网络故障时的处理)? 如何解决?高可用实现方案?

文章有部分是直接翻译的 https://redis.io/topics/replication">


<meta itemprop="datePublished" content="2019-11-16T14:24:40&#43;08:00" />
<meta itemprop="dateModified" content="2019-11-16T14:24:40&#43;08:00" />
<meta itemprop="wordCount" content="3579">



<meta itemprop="keywords" content="redis," />
<meta name="twitter:card" content="summary"/>
<meta name="twitter:title" content="Redis-复制功能探索"/>
<meta name="twitter:description" content="之前对redis 的复制只有一点点了解,这次想要搞明白的是:如何实现的复制? 复制会遇到哪些问题(时延/一致性保证/网络故障时的处理)? 如何解决?高可用实现方案?

文章有部分是直接翻译的 https://redis.io/topics/replication"/>

  <!--[if lte IE 9]>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/classlist/1.1.20170427/classList.min.js"></script>
    <![endif]-->

  <!--[if lt IE 9]>
      <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
      <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
    <![endif]-->

</head>
  </head>
  

  <body class="main-center theme-black" itemscope itemtype="http://schema.org/WebPage"><header class="header" itemscope itemtype="http://schema.org/WPHeader">
    <div class="slimContent">
      <div class="navbar-header">
        <div class="profile-block text-center">
          <a id="avatar" href="https://github.com/xiaoheiAh" target="_blank">
            <img class="img-circle img-rotate" src="https://xiaohei.im/hugo-theme-pure/avatar.png" width="200" height="200">
          </a>
          <h2 id="name" class="hidden-xs hidden-sm">赵小黑</h2>
          <h3 id="title" class="hidden-xs hidden-sm hidden-md">Java Developer</h3>
          <small id="location" class="text-muted hidden-xs hidden-sm"><i class="icon icon-map-marker"></i>Shanghai, China</small>
        </div><div class="search" id="search-form-wrap">
    <form class="search-form sidebar-form">
        <div class="input-group">
            <input type="text" class="search-form-input form-control" placeholder="搜索" />
            <span class="input-group-btn">
                <button type="submit" class="search-form-submit btn btn-flat" onclick="return false;"><i
                        class="icon icon-search"></i></button>
            </span>
        </div>
        <div class="ins-search">
            <div class="ins-search-mask"></div>
            <div class="ins-search-container">
                <div class="ins-input-wrapper">
                    <input type="text" class="ins-search-input" placeholder="想要查找什么..."
                        x-webkit-speech />
                    <button type="button" class="close ins-close ins-selectable" data-dismiss="modal"
                        aria-label="Close"><span aria-hidden="true">×</span></button>
                </div>
                <div class="ins-section-wrapper">
                    <div class="ins-section-container"></div>
                </div>
            </div>
        </div>
    </form>
</div>
        <button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target="#main-navbar" aria-controls="main-navbar" aria-expanded="false">
          <span class="sr-only">Toggle navigation</span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
        </button>
      </div>
      <nav id="main-navbar" class="collapse navbar-collapse" itemscope itemtype="http://schema.org/SiteNavigationElement" role="navigation">
        <ul class="nav navbar-nav main-nav  menu-highlight">
            <li class="menu-item menu-item-home">
                <a href="/hugo-theme-pure/">
                    <i class="icon icon-home-fill"></i>
                  <span class="menu-title">主页</span>
                </a>
            </li>
            <li class="menu-item menu-item-archives">
                <a href="/hugo-theme-pure/posts">
                    <i class="icon icon-archives-fill"></i>
                  <span class="menu-title">归档</span>
                </a>
            </li>
            <li class="menu-item menu-item-categories">
                <a href="/hugo-theme-pure/categories">
                    <i class="icon icon-folder"></i>
                  <span class="menu-title">分类</span>
                </a>
            </li>
            <li class="menu-item menu-item-tags">
                <a href="/hugo-theme-pure/tags">
                    <i class="icon icon-tags"></i>
                  <span class="menu-title">标签</span>
                </a>
            </li>
            <li class="menu-item menu-item-about">
                <a href="/hugo-theme-pure/about">
                    <i class="icon icon-cup-fill"></i>
                  <span class="menu-title">关于</span>
                </a>
            </li>
        </ul>
      </nav>
    </div>
  </header>
  <aside class="sidebar" itemscope itemtype="http://schema.org/WPSideBar">
  <div class="slimContent">
    
      <div class="widget">
    <h3 class="widget-title">公告</h3>
    <div class="widget-body">
        <div id="board">
            <div class="content"><p>自用科学上网节点推荐(便宜又好用)<a href="https://tianlinzhao.com/aff.php?aff=4969" target="_blank" style="background-color:#FFFF00">点这里跳转</a>
            </div>
        </div>
    </div>
</div>

      <div class="widget">
    <h3 class="widget-title"> 分类</h3>
    <div class="widget-body">
        <ul class="category-list">
            <li class="category-list-item"><a href="https://xiaohei.im/hugo-theme-pure/categories/corejava/" class="category-list-link">corejava</a><span class="category-list-count">7</span></li>
            <li class="category-list-item"><a href="https://xiaohei.im/hugo-theme-pure/categories/hystrix/" class="category-list-link">hystrix</a><span class="category-list-count">2</span></li>
            <li class="category-list-item"><a href="https://xiaohei.im/hugo-theme-pure/categories/leetcode/" class="category-list-link">leetcode</a><span class="category-list-count">3</span></li>
            <li class="category-list-item"><a href="https://xiaohei.im/hugo-theme-pure/categories/redis/" class="category-list-link">redis</a><span class="category-list-count">8</span></li>
            <li class="category-list-item"><a href="https://xiaohei.im/hugo-theme-pure/categories/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97/" class="category-list-link">消息队列</a><span class="category-list-count">4</span></li>
        </ul>
    </div>
</div>
      <div class="widget">
    <h3 class="widget-title"> 标签</h3>
    <div class="widget-body">
        <ul class="tag-list">
            
            
            <li class="tag-list-item"><a href="https://xiaohei.im/hugo-theme-pure/tags/collections/" class="tag-list-link">collections</a><span
                    class="tag-list-count">7</span></li>
            
            
            <li class="tag-list-item"><a href="https://xiaohei.im/hugo-theme-pure/tags/hugo/" class="tag-list-link">hugo</a><span
                    class="tag-list-count">1</span></li>
            
            
            <li class="tag-list-item"><a href="https://xiaohei.im/hugo-theme-pure/tags/hystrix/" class="tag-list-link">hystrix</a><span
                    class="tag-list-count">1</span></li>
            
            
            <li class="tag-list-item"><a href="https://xiaohei.im/hugo-theme-pure/tags/leetcode/" class="tag-list-link">leetcode</a><span
                    class="tag-list-count">3</span></li>
            
            
            <li class="tag-list-item"><a href="https://xiaohei.im/hugo-theme-pure/tags/rabbitmq/" class="tag-list-link">rabbitmq</a><span
                    class="tag-list-count">4</span></li>
            
            
            <li class="tag-list-item"><a href="https://xiaohei.im/hugo-theme-pure/tags/redis/" class="tag-list-link">redis</a><span
                    class="tag-list-count">8</span></li>
            
            
            <li class="tag-list-item"><a href="https://xiaohei.im/hugo-theme-pure/tags/rust/" class="tag-list-link">rust</a><span
                    class="tag-list-count">3</span></li>
            
            
            <li class="tag-list-item"><a href="https://xiaohei.im/hugo-theme-pure/tags/rxjava/" class="tag-list-link">rxjava</a><span
                    class="tag-list-count">2</span></li>
            
            
            <li class="tag-list-item"><a href="https://xiaohei.im/hugo-theme-pure/tags/%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81/" class="tag-list-link">分布式锁</a><span
                    class="tag-list-count">1</span></li>
            
            
            <li class="tag-list-item"><a href="https://xiaohei.im/hugo-theme-pure/tags/%E5%93%8D%E5%BA%94%E5%BC%8F%E7%BC%96%E7%A8%8B/" class="tag-list-link">响应式编程</a><span
                    class="tag-list-count">1</span></li>
            
            
            <li class="tag-list-item"><a href="https://xiaohei.im/hugo-theme-pure/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/" class="tag-list-link">数据结构</a><span
                    class="tag-list-count">1</span></li>
            
        </ul>

    </div>
</div>
      
<div class="widget">
    <h3 class="widget-title">最新文章</h3>
    <div class="widget-body">
        <ul class="recent-post-list list-unstyled no-thumbnail">
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://xiaohei.im/hugo-theme-pure/2019/11/replication/" class="title">Redis-复制功能探索</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2019-11-16 14:24:40 &#43;0800 CST" itemprop="datePublished">2019-11-16</time>
                    </p>
                </div>
            </li>
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://xiaohei.im/hugo-theme-pure/2019/11/event/" class="title">Redis-事件</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2019-11-14 15:01:45 &#43;0800 CST" itemprop="datePublished">2019-11-14</time>
                    </p>
                </div>
            </li>
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://xiaohei.im/hugo-theme-pure/2019/11/aof/" class="title">Redis-AOF持久化</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2019-11-08 15:18:05 &#43;0800 CST" itemprop="datePublished">2019-11-08</time>
                    </p>
                </div>
            </li>
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://xiaohei.im/hugo-theme-pure/2019/11/rdb/" class="title">Redis-RDB持久化</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2019-11-06 19:08:56 &#43;0800 CST" itemprop="datePublished">2019-11-06</time>
                    </p>
                </div>
            </li>
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://xiaohei.im/hugo-theme-pure/2019/11/db/" class="title">Redis-数据库长什么样?</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2019-11-06 11:00:32 &#43;0800 CST" itemprop="datePublished">2019-11-06</time>
                    </p>
                </div>
            </li>
        </ul>
    </div>
</div>
  </div>
</aside>

    
    
  <aside class="sidebar sidebar-toc collapse" id="collapseToc" itemscope itemtype="http://schema.org/WPSideBar">
    <div class="slimContent">
      <nav id="toc" class="article-toc">
        <h3 class="toc-title">文章目录</h3>
        <div class="toc-content always-active"><nav id="TableOfContents">
<ul>
<li>
<ul>
<li><a href="#复制是什么">复制是什么?</a></li>
<li><a href="#redis-主从复制">Redis 主从复制</a>
<ul>
<li><a href="#主从复制作用">主从复制作用</a></li>
<li><a href="#redis-复制设计要点">Redis 复制设计要点</a></li>
<li><a href="#主从复制过程">主从复制过程</a>
<ul>
<li><a href="#backlog-buffer-是啥">backlog buffer 是啥?</a></li>
<li><a href="#全量复制">全量复制</a></li>
<li><a href="#sync-psync">SYNC/PSYNC</a></li>
<li><a href="#replication-id">Replication ID</a>
<ul>
<li><a href="#为什么有两个-replid">为什么有两个<code>replId</code>?</a></li>
<li><a href="#为什么晋升后需要生成新-replid">为什么晋升后需要生成新 replId?</a></li>
</ul></li>
<li><a href="#无盘复制">无盘复制</a></li>
<li><a href="#如何处理可以过期的键">如何处理可以过期的键?</a></li>
<li><a href="#心跳机制">心跳机制</a>
<ul>
<li><a href="#master-slave">master -&gt; slave</a></li>
<li><a href="#replica-master">replica -&gt; master</a></li>
</ul></li>
</ul></li>
</ul></li>
<li><a href="#复制惨痛案例">复制惨痛案例</a>
<ul>
<li>
<ul>
<li><a href="#数据过期问题">数据过期问题</a></li>
<li><a href="#数据延迟不一致">数据延迟不一致</a></li>
<li><a href="#复制超时导致复制中断">复制超时导致复制中断</a>
<ul>
<li><a href="#为什么要判断超时">为什么要判断超时?</a></li>
<li><a href="#判断机制">判断机制?</a></li>
<li><a href="#问题">问题</a></li>
</ul></li>
<li><a href="#backlog-过小导致无限全量复制">backlog 过小导致无限全量复制</a></li>
</ul></li>
</ul></li>
<li><a href="#参考">参考</a></li>
</ul></li>
</ul>
</nav>
        </div>
      </nav>
    </div>
  </aside>
<main class="main" role="main"><div class="content">
  <article id="-" class="article article-type-" itemscope
    itemtype="http://schema.org/BlogPosting">
    
    <div class="article-header">
      <h1 itemprop="name">
  <a
    class="article-title"
    href="/hugo-theme-pure/2019/11/replication/"
    >Redis-复制功能探索</a
  >
</h1>

      <div class="article-meta">
        <span class="article-date">
  <i class="icon icon-calendar-check"></i>
<a href="https://xiaohei.im/hugo-theme-pure/2019/11/replication/" class="article-date">
  <time datetime="2019-11-16 14:24:40 &#43;0800 CST" itemprop="datePublished">2019-11-16</time>
</a>
</span><span class="article-category">
  <i class="icon icon-folder"></i>
  <a class="article-category-link" href="/hugo-theme-pure/categories/redis/"> redis </a>
</span>  
  <span class="article-tag">
    <i class="icon icon-tags"></i>
    <a class="article-tag-link" href="/hugo-theme-pure/tags/redis/"> redis </a>
  </span>

	<span class="article-read hidden-xs">
	    <i class="icon icon-eye-fill" aria-hidden="true"></i>
	    <span id="busuanzi_container_page_pv">
			<span id="busuanzi_value_page_pv">0</span>
		</span>
	</span>
        <span class="post-comment"><i class="icon icon-comment"></i> <a href="/hugo-theme-pure/2019/11/replication/#comments"
            class="article-comment-link">评论</a></span>
		<span class="post-wordcount hidden-xs" itemprop="wordCount">字数统计:3579字</span>
		<span class="post-readcount hidden-xs" itemprop="timeRequired">阅读时长:8分 </span>
      </div>
    </div>
    <div class="article-entry marked-body" itemprop="articleBody">
      <p>之前对<code>redis</code> 的复制只有一点点了解,这次想要搞明白的是:如何实现的复制? 复制会遇到哪些问题(时延/一致性保证/网络故障时的处理)? 如何解决?高可用实现方案?</p>

<p>文章有部分是直接翻译的 <a href="https://redis.io/topics/replication">https://redis.io/topics/replication</a></p>

<h2 id="复制是什么">复制是什么?</h2>

<p>分布式系统有一个重要的点时保证数据不丢失,数据不丢失就意味着不能单点,不能单点就意味着最好能把数据多存几份形成数据的冗余.这就是复制的来由.复制类型主要是两种: <strong>同步</strong>, <strong>异步</strong>. 前者需要等待所有的节点返回写入确认,后者只需要返回个确认收到就行.</p>

<h2 id="redis-主从复制">Redis 主从复制</h2>

<h3 id="主从复制作用">主从复制作用</h3>

<ol>
<li><strong>数据冗余</strong>:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。</li>
<li><strong>故障恢复</strong>:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。</li>
<li><strong>负载均衡</strong>:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。</li>
<li><strong>高可用基石</strong>:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。</li>
</ol>

<h3 id="redis-复制设计要点">Redis 复制设计要点</h3>

<ul>
<li><p>默认使用异步复制 &ndash; replica -&gt; master 异步返回处理了多少数据的结果(<strong>偏移量</strong>)</p></li>

<li><p><code>master</code> 可以多 <code>replicas</code></p></li>

<li><p><code>replicas</code> 可以从其他 <code>replica</code> 同步(从从复制).类似于级联更新的架构.</p></li>
</ul>

<p><img src="https://raw.githubusercontent.com/xiaoheiAh/imgs/master/20191118110202.png" alt="从从复制" /></p>

<ul>
<li><code>master</code> 主节点在同步时不会阻塞.</li>
<li>在 <code>replica</code> 侧复制也是非阻塞的.在进行初始化同步(全量)时,可以使用 <code>replica</code>上的旧数据供客户端查询.也可以在 <code>redis.conf</code> 进行配置,在初始化同步完成前客户端的请求都报错.初始化同步完成后,需要删除老数据,加载新数据.在这段时间中会阻塞外部连接请求,数据量大的话可能要很久.从 <code>4.0</code> 版本后,删除老数据可以通过多线程来优化效率,但是加载新数据还是会 <strong>阻塞</strong>.</li>
<li>复制可以用来弹性扩容,提供多可读副本,提升数据安全性,保证高可用</li>
<li>副本可以避免 <code>master</code> 保存全量数据到磁盘的资源消耗:可以由 <code>replica</code> 完成持久化,或者开启 <code>aof</code> 写入.不过需要慎重: 这样会导致 <code>master</code> 节点再重启时会是空的,其他 <code>replica</code>复制时也就成空的了.</li>
</ul>

<h3 id="主从复制过程">主从复制过程</h3>

<p>每一个 <code>master</code> 节点都会有一个特别大的随机数(40字节十六进制随机字符)作为 <code>replication ID</code> 来标识自己.每个 <code>master</code> 节点也有一个 持续递增的 <code>offset</code> 来记录发送给 <code>replicas</code> 的每一个 <code>byte</code>,利用该 <code>offset</code> 来保证副本更新的状态.</p>

<p>当一个 <code>replica</code> 连接到 <code>master</code> 时,会使用 <code>PSYNC</code> 命令发送之前复制的 <code>master</code> 的 <code>replicationID</code>,以及自己的更新进度(<code>offset</code>).<code>master</code> 可以根据这个值给副本按需返回为更新的数据.如果在<code>master</code> 的 <code>backlog buffer</code> 中没有对应的数据可以给到,副本发送的 <code>replicationID</code> 与 <code>master</code> 的 ID 不一致,就会触发全量复制(<code>Full Synchronization</code>).</p>

<h4 id="backlog-buffer-是啥">backlog buffer 是啥?</h4>

<p>复制积压缓冲区,在 <code>master</code> 有 <code>replica</code> 进行复制时,存储 <code>master</code> 最近一段时间的写命令,以便在 <code>replica</code> 断开重连后,可以利用缓冲区更新断开这段时间中,从节点丢掉的更新.</p>

<p><code>backlog buffer</code> 是有固定的长度,先进先出的队列,默认大小 <code>1MB</code>. 其实就是一个环.<code>buffer</code> 会存储每一个 <code>offset</code> 已经对应的写命令,这样 <code>replica</code> 在断连恢复后,发送 <code>PSYNC</code> 命令提供其最后一次更新的 <code>offset</code>, <code>master</code> 就可以根据 <code>replica</code> 提供的 <code>offset</code> 去 <code>buffer</code> 中找对应的数据发送给 <code>replica</code> 保持最新.</p>

<p>如果断开时间过长,<code>buffer</code> 存储的数据已经换了一批又一批, <code>replica</code> 在重连后发送给 <code>master</code> 的 <code>offset</code> 在 <code>buffer</code> 已经找不到了.此时会触发 <strong>全量复制</strong>.</p>

<h4 id="全量复制">全量复制</h4>

<p><code>master</code>调用 <code>bgsave</code> 在后台生成 <code>rdb</code> 文件.同时记录客户端新的写命令到 <code>backlog buffer</code> 中. <code>rdb</code> 文件生成后,发送给 <code>replica</code> 保存到其硬盘中,然后再加载到内存中并通知<code>master</code> 加载完成.然后 <code>master</code> 会发送 <code>buffer pool</code> 中的命令给 <code>replica</code> 完成最后的同步.</p>

<h4 id="sync-psync">SYNC/PSYNC</h4>

<p>两者都是同步的命令.<code>SYNC</code> 只支持全量同步, <code>PSYNC</code> 支持上述的部分同步.<code>2.8</code> 版本之前只有 <code>SYNC</code>,为了避免每次都只能全量同步造成资源的浪费,就新增了 <code>PSYNC</code> 命令实现部分同步的语义.</p>

<h4 id="replication-id">Replication ID</h4>

<p><code>Replication ID</code> 标记了数据的历史信息,从0开始成为<code>master</code> 的节点,或者晋升成为 <code>master</code> 的 <code>replica</code> 节点,都会生成一个 <code>Replication ID</code>.<code>replicas</code> 的 <code>replId</code> 是和其复制的 <code>master</code> 一致的,<code>master</code> 通过该 ID 和 <code>offset</code> 来判断主从之间数据是否一致.</p>

<h5 id="为什么有两个-replid">为什么有两个<code>replId</code>?</h5>

<pre><code class="language-c">/* src/server.h */
struct redisServer {
  ...
  /* Replication (master) */
  char replid[CONFIG_RUN_ID_SIZE+1];  /* My current replication ID. */
  char replid2[CONFIG_RUN_ID_SIZE+1]; /* replid inherited from master*/
  ...
  long long master_repl_offset;   /* My current replication offset */
  long long second_replid_offset; /* Accept offsets up to this for replid2. */
  ...
}
</code></pre>

<p>一般情况下,故障转移(<code>failover</code>)后,晋升的 <code>replica</code> 需要记录自己之前复制的 <code>master</code> 对应的 <code>replId</code>.其他 <code>replicas</code> 会向新 <code>master</code> 进行部分同步,但发送过来的 <code>replId</code> 还是之前 <code>master</code> 的.所以 <code>replica</code> 在晋升时,会生成新的<code>replId</code>,并将原来的 <code>replId</code> 记录到 <code>replId2</code>,同时记录下当时所更新到的 <code>offset</code> 到 <code>second_replid_offset</code>.当其他的 <code>replica</code> 向新 <code>master</code> 进行连接时,新 <code>master</code> 会比较当前的和之前 <code>master</code> 的 <code>replId</code>,<code>offset</code>,这样就可以防止在故障转移后导致不必要的 <strong>全量复制</strong>.</p>

<h5 id="为什么晋升后需要生成新-replid">为什么晋升后需要生成新 replId?</h5>

<p><code>old master</code> 可能还存活,但由于网络分区原因无法和其他 <code>replicas</code> 通信,如果保留原来的 <code>id</code> 不再生成,就会导致有相同数据相同id的<code>master</code> 存在.</p>

<h4 id="无盘复制">无盘复制</h4>

<p>全量复制时,<code>master</code> 会创建 <code>rdb</code> 文件存到磁盘,然后再读取 <code>rdb</code> 文件发送给 <code>replicas</code>.磁盘性能差的情况下,效率会很低,所以支持了 <strong>无盘复制</strong> &ndash; 子进程直接发送 <code>rdb</code> 给 <code>replicas</code>,不经过硬盘存储.</p>

<h4 id="如何处理可以过期的键">如何处理可以过期的键?</h4>

<ol>
<li>副本不会主动去过期键,而是由 <code>master</code> 过期键后向副本发送 <code>DEL</code> 命令.</li>
<li>由于是通过 <code>master</code> 驱动,副本收到 <code>DEL</code> 命令可能有延迟,这就会导致从副本中还可能查到已过期的键.针对这种情况,副本会利用自身的物理时钟作为依据报告该键不存在(仅在不违反数据一致性的 <strong>只读操作</strong>),因为 <code>DEL</code> 命令总是会发过来的.</li>
<li><code>LUA</code> 脚本执行期间,是不会去执行 <code>key</code> 过期的.脚本执行期间相当于 <code>master</code> 时间冻结了,不作过期时间的记录,所以在这期间过期键只有存在或不存在的概念.这样可以防止键在执行期间过期.同时,<code>master</code> 也需要发送同样的脚本给副本,保持一致.</li>
</ol>

<p>如果<code>replica</code> 晋升 <code>master</code> 了,它就会自己去处理键的过期了.</p>

<h4 id="心跳机制">心跳机制</h4>

<p>在正常的进行 <strong>部分同步</strong> 期间,主从之间会维持心跳,来协助超时判断,数据安全等问题.</p>

<h5 id="master-slave">master -&gt; slave</h5>

<p>主节点发送 <code>PING</code> ,从节点回复 <code>PONG</code>.目的是让从节点进行超时判断.发送频率有 <code>repl-ping-slave-period</code> 参数控制.单位秒,默认 <code>10s</code>.</p>

<h5 id="replica-master">replica -&gt; master</h5>

<p>从节点向主节点发送 <code>REPLCONF ACK {offset}</code> ,频率每秒1次.作用:</p>

<ol>
<li>试试检测主从网络状态,该命令被主节点用于复制超时的判断.</li>
<li>检测命令丢失,主节点会比较从节点发送的 <code>offset</code> 与自身的是否一致,不一致则从 <code>buffer</code> 中查找对应数据进行补发,如果 <code>buffer</code> 中没有对应数据,则会进行全量复制.</li>
<li>辅助保证从节点的数量和延迟,<code>master</code> 通过 <code>min-salves-to-write</code> 和 <code>min-slaves-max-lag</code> 参数,来保证主节点在不安全情况下不会执行写命令.是指从节点数量太少,或延迟过高。例如 <code>min-slaves-to-write</code> 和<code>min-slaves-max-lag</code> 分别是3和10,含义是如果从节点数量小于3个,或所有从节点的延迟值都大于10s,则主节点拒绝执行写命令。</li>
</ol>

<h2 id="复制惨痛案例">复制惨痛案例</h2>

<h4 id="数据过期问题">数据过期问题</h4>

<p>数据删除没有及时同步到从节点,其实在 <code>3.2</code> 版本后避免了这个问题.从节点会对键进行判断,已过期不展示.</p>

<p><a href="#如何处理可以过期的键?">如何处理可以过期的键?</a></p>

<h4 id="数据延迟不一致">数据延迟不一致</h4>

<p>这种情况不可避免.可能的优化措施包括:优化主从节点之间的网络环境(如在同机房部署);监控主从节点延迟通过<code>offset</code>判断,如果从节点延迟过大,通知应用不再通过该从节点读取数据;使用集群同时扩展写负载和读负载等。</p>

<h4 id="复制超时导致复制中断">复制超时导致复制中断</h4>

<h5 id="为什么要判断超时">为什么要判断超时?</h5>

<ol>
<li><code>master</code> 在判断超时后,会释放从节点的连接,释放资源.</li>
<li>断开后即时重连</li>
</ol>

<h5 id="判断机制">判断机制?</h5>

<p>核心参数: <code>repl-timeout</code> ,默认 60s.</p>

<p>(1)主节点:每秒1次调用复制定时函数replicationCron(),在其中判断当前时间距离上次收到各个从节点 <code>REPLCONF ACK</code> 的时间,是否超过了 <code>repl-timeout</code> 值,如果超过了则释放相应从节点的连接。</p>

<p>(2)从节点:从节点对超时的判断同样是在复制定时函数中判断,基本逻辑是:</p>

<ul>
<li>如果当前处于连接建立阶段,且距离上次收到主节点的信息的时间已超过 <code>repl-timeout</code>,则释放与主节点的连接;</li>
<li>如果当前处于数据同步阶段,且收到主节点的 <code>RDB</code> 文件的时间超时,则停止数据同步,释放连接;</li>
<li>如果当前处于命令传播阶段,且距离上次收到主节点的 <code>PING</code> 命令或数据的时间已超过repl-timeout值,则释放与主节点的连接。</li>
</ul>

<h5 id="问题">问题</h5>

<ol>
<li>全量复制时,如果 <code>RDB</code> 文件过大,耗时很长就会触发超时,此时从节点会重连,再生成<code>RDB</code>,再超时,在生成<code>RDB</code>&hellip;解决方案就是单机数据量尽量不要太大,增大 <code>repl-timeout</code>.</li>
<li>慢查询导致服务器阻塞: <code>keys *</code>,<code>hgetall</code></li>
</ol>

<h4 id="backlog-过小导致无限全量复制">backlog 过小导致无限全量复制</h4>

<p><code>backlog buffer</code> 是固定大小的,写入命令超出长度就会覆盖.如果再全量复制的时候用时超长,存入<code>buffer</code> 的命令超过了其大小限制,那么就会导致连接中断,再重连,全量复制,连接中断,全量复制&hellip;.死循环.解决方案就是需要正确设置 <code>backlog buffer</code> 的大小. 通过 <code>client-output-buffer-limit slave {hard limit} {soft limit} {soft seconds}</code> 配置,默认值为 <code>client-output-buffer-limit slave 256MB 64MB 60</code>,其含义是:如果 <code>buffer</code> 大于<code>256MB</code>,或者连续 <code>60s</code> 大于 <code>64MB</code> ,则主节点会断开与该从节点的连接。该参数是可以通过 <code>config set</code> 命令动态配置的(即不重启Redis也可以生效).</p>

<h2 id="参考">参考</h2>

<ol>
<li><p><a href="https://www.cnblogs.com/kismetv/p/9236731.html">深入学习Redis(3):主从复制</a></p></li>

<li><p>「Redis 设计与实现」</p></li>

<li><p><a href="https://redis.io/topics/replication">https://redis.io/topics/replication</a></p></li>
</ol>
    </div>
    <div class="article-footer">
<blockquote class="mt-2x">
  <ul class="post-copyright list-unstyled">
    <li class="post-copyright-link hidden-xs">
      <strong>本文链接: </strong>
      <a href="https://xiaohei.im/hugo-theme-pure/2019/11/replication/" title="Redis-复制功能探索" target="_blank" rel="external">https://xiaohei.im/hugo-theme-pure/2019/11/replication/</a>
    </li>
    <li class="post-copyright-license">
      <strong>License:</strong><a href="http://creativecommons.org/licenses/by/4.0/deed.zh" target="_blank" rel="external">CC BY 4.0 CN</a>
    </li>
  </ul>
</blockquote>

<div class="panel panel-default panel-badger">
  <div class="panel-body">
    <figure class="media">
      <div class="media-left">
        <a href="https://github.com/xiaoheiAh" target="_blank" class="img-burn thumb-sm visible-lg">
          <img src="https://xiaohei.im/hugo-theme-pure/avatar.png" class="img-rounded w-full" alt="">
        </a>
      </div>
      <div class="media-body">
        <h3 class="media-heading"><a href="https://github.com/xiaoheiAh" target="_blank"><span class="text-dark">赵小黑</span><small class="ml-1x">Java Developer</small></a></h3>
        <div>好好学习~天天向上~</div>
      </div>
    </figure>
  </div>
</div>
    </div>
  </article>
<section id="comments">
</section>

</div><nav class="bar bar-footer clearfix" data-stick-bottom>
    <div class="bar-inner">
        <ul class="pager pull-left">
            <li class="prev">
                <a href="https://xiaohei.im/hugo-theme-pure/2019/11/event/" title="Redis-事件"><i
                        class="icon icon-angle-left"
                        aria-hidden="true"></i><span>&nbsp;&nbsp;下一篇</span></a>
            </li>
            
            <li class="toggle-toc">
                <a class="toggle-btn collapsed" data-toggle="collapse" href="#collapseToc" aria-expanded="false"
                    title="文章目录" role="button">
                    <span>[&nbsp;</span><span>文章目录</span>
                    <i class="text-collapsed icon icon-anchor"></i>
                    <i class="text-in icon icon-close"></i>
                    <span>]</span>
                </a>
            </li>
        </ul>
        
        <button type="button" class="btn btn-fancy btn-donate pop-onhover bg-gradient-warning" data-toggle="modal"
            data-target="#donateModal"><span>赏</span></button>
        
        <div class="bar-right">
            <div class="share-component" data-sites="weibo,qq,wechat,facebook,twitter"
                data-mobile-sites="weibo,qq,qzone"></div>
        </div>
    </div>
</nav>


<div class="modal modal-center modal-small modal-xs-full fade" id="donateModal" tabindex="-1" role="dialog">
    <div class="modal-dialog" role="document">
        <div class="modal-content donate">
            <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
                    aria-hidden="true">&times;</span></button>
            <div class="modal-body">
                <div class="donate-box">
                    <div class="donate-head">
                        <p>感谢您的支持,我会继续努力的!</p>
                    </div>
                    <div class="tab-content">
                        <div role="tabpanel" class="tab-pane fade active in" id="alipay">
                            <div class="donate-payimg">
                                <img src="https://xiaohei.im/hugo-theme-pure/donate/alipayimg.png"
                                    alt="扫码支持" title="扫一扫" />
                            </div>
                            <p class="text-muted mv">扫码打赏, 多少你说了算~</p>
                            <p class="text-grey">打开支付宝扫一扫,即可进行扫码打赏哦~</p>
                        </div>
                        <div role="tabpanel" class="tab-pane fade" id="wechatpay">
                            <div class="donate-payimg">
                                <img src="https://xiaohei.im/hugo-theme-pure/donate/wechatpayimg.png"
                                    alt="扫码支持" title="扫一扫" />
                            </div>
                            <p class="text-muted mv">扫码打赏, 多少你说了算~</p>
                            <p class="text-grey">打开微信扫一扫,即可进行扫码打赏哦</p>
                        </div>
                    </div>
                    <div class="donate-footer">
                        <ul class="nav nav-tabs nav-justified" role="tablist">
                            <li role="presentation" class="active">
                                <a href="#alipay" id="alipay-tab" role="tab" data-toggle="tab" aria-controls="alipay"
                                    aria-expanded="true"><i class="icon icon-alipay"></i> 支付宝</a>
                            </li>
                            <li role="presentation" class="">
                                <a href="#wechatpay" role="tab" id="wechatpay-tab" data-toggle="tab"
                                    aria-controls="wechatpay" aria-expanded="false"><i class="icon icon-wepay"></i>
                                    微信支付</a>
                            </li>
                        </ul>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
</main><footer class="footer" itemscope itemtype="http://schema.org/WPFooter">
<ul class="social-links">
    <li><a href="https://github.com/xiaoheiAh" target="_blank" title="github" data-toggle=tooltip data-placement=top >
            <i class="icon icon-github"></i></a></li>
    <li><a href="https://xiaohei.im/index.xml" target="_blank" title="rss" data-toggle=tooltip data-placement=top >
            <i class="icon icon-rss"></i></a></li>
</ul>
  <div class="copyright">
    &copy;2017  -
    2019
    <div class="publishby">
        Theme by <a href="https://github.com/xiaoheiAh" target="_blank"> xiaoheiAh </a>base on<a href="https://github.com/xiaoheiAh/hugo-theme-pure" target="_blank"> pure</a>.
    </div>
  </div>
</footer>

<script src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.min.js"></script>
<script>
   window.jQuery || document.write('<script src="js/jquery.min.js"><\/script>')
</script>
<script type="text/javascript" src="https://cdn.staticfile.org/highlight.js/9.15.10/highlight.min.js"></script>
<script type="text/javascript" src="https://cdn.staticfile.org/highlight.js/9.15.10/languages/rust.min.js"></script>
<script type="text/javascript"
   src="https://cdn.staticfile.org/highlight.js/9.15.10/languages/dockerfile.min.js"></script>
<script>
hljs.configure({
  tabReplace: '    ', 
  classPrefix: ''     
                      
})
hljs.initHighlightingOnLoad();
</script>
<script type="text/javascript" src="https://xiaohei.im/hugo-theme-pure/js/application.js"></script>
<script type="text/javascript" src="https://xiaohei.im/hugo-theme-pure/js/plugin.js"></script>
<script>
      (function (window) {
          var INSIGHT_CONFIG = {
              TRANSLATION: {
                  POSTS: '文章',
                  PAGES: '页面',
                  CATEGORIES: '分类',
                  TAGS: '标签',
                  UNTITLED: '(未命名)',
              },
              ROOT_URL: 'https:\/\/xiaohei.im\/hugo-theme-pure',
              CONTENT_URL: 'https:\/\/xiaohei.im\/hugo-theme-pure\/searchindex.json ',
          };
          window.INSIGHT_CONFIG = INSIGHT_CONFIG;
      })(window);
      </script>
<script type="text/javascript" src="https://xiaohei.im/hugo-theme-pure/js/insight.js"></script>

<script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

<script src="https://cdn.jsdelivr.net/npm/gitalk@1.4.0/dist/gitalk.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/blueimp-md5@2.10.0/js/md5.min.js"></script>
<script type="text/javascript">
    var gitalk = new Gitalk({
        clientID: 'e38fc798c72a7e4e1386',
        clientSecret: 'e151aa3b7b98d3cfaa1f096b88fdd7897e2c8007',
        repo: 'xiaoheiAh.github.io',
        owner: 'xiaoheiAh',
        admin: ['xiaoheiAh'],
        id: md5(location.pathname),
        distractionFreeMode: true
    });
    gitalk.render('comments');
</script>
<script type="application/javascript">
var doNotTrack = false;
if (!doNotTrack) {
	window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
	ga('create', 'UA-98254666-1', 'auto');
	
	ga('send', 'pageview');
}
</script>
<script async src='https://www.google-analytics.com/analytics.js'></script>


  </body>
</html>