图形组合!一篇了解 Redis 主从复制角色和场景模式与原理的文章!
目录
- 什么是 Redis 主从复制
- 主从复制的作用及场景
- 主从复制的模式
- 一主一从
- 一主多从
4.主从复制的原理
- 全量复制
- 部分复制
- 总结
什么是 Redis 主从复制
总所周知 Redis 之所以火因为它有着读取速度快、可持久化的优点。Redis 的持久化保证了断电或重启数据不会丢失。但仅仅这样是不够的,持久化是将数据定期写入磁盘中,万一哪一天这一台服务器挂掉了,那所有数据依旧会丢失。为了解决这个单点故障问题,所以就有了主从复制。
主从复制就是将一台 Redis 服务器的数据自动地复制到其他 Redis 服务器上。一台服务器出故障的概率很高,但是多台服务器同时出故障的概率就很低了吧。所谓主从主从,当然是有主服务器(Master)和从服务器(Slave),一个 Master 可以将数据复制到多个 Slave,但是特别注意的是,复制是单向的,只能从 Master 到 Slave。一个 Master 可以有多个 Slave,一个 Slave 也可以有多个 Slave,但是一个 Slave 只能从属一个 Master。如下图这样就是错误的。
主从复制的作用及场景
- 数据冗余:主从复制实现了数据的热备份,相当于一份数据在多个服务器上存储了,是持久化之外的一种数据冗余方式,这样做的目的是以空间换取安全性。如果主服务器挂掉了,可以通过从服务将数据恢复。
- 故障快速修复:当 Master 出现问题的时候,可以快速地将一个 Slave 切换成 Master 继续提供服务,保证项目稳定性。
- 读写分离:主从复制实现读写分离非常简单,写入的时候只操作 Master,读取的时候只操作 Slave,这样读的话可以多个 Slave 满足项目高并发的操作。
- 负载均衡:既然实现了读写分离,当然就能实现负载均衡,多个 Slave 承担数据读取操作,从而分担 Master 服务器的压力。
- 高可用的基石:主从复制还是哨兵模式和集群模式能够实施的基础。
既然主从复制有这些作用,那在实际应用中会用在哪些场景呢?
- 如果项目对数据安全性稳定性要求较高,就会使用主从复制搭建哨兵模式或者搭建集群。
- 海量数据读写,需要做读写分离提高防蚊效率,就会用到主从复制。
- 容灾恢复,如果对数据依赖度很高,害怕数据在服务器挂掉后丢失,就可以通过主从复制防止数据丢失。
主从复制的模式
一主一从
这种模式在实际应用中还是比较少见的其实,一主一从主要是实现读写分离和容灾恢复。考虑到成本的问题,所以采用两台服务器,一个 Redis 服务器 Master 负责读操作,并定期的复制到另个一服务器 Slave。Slave 服务器负责读写操作。在项目中配置的时候配置两个 Redis 连接。
一主多从
一主多从有可以分为几种,如下图:
这种就是所有的 Slave 都从 Master 中进行复制,这样的好处是 配置简单,所有的 Slave 都只用关系 Master 就好了,但是要考虑到其实复制也是会侵占 CPU 内存的,所有的 Slave 都从 Master 复制,可能增大 Master 的负荷。
再来看看下图:
这种模式也是一主多从,但是和上面的所有的 Slave 都从 Master 复制不一样。它是使一个到两个 Slave 从 Master 直接复制,其他的 Slave 从这两个 Slave 中复制。存在层级关系。这样的好处的降低的 Master 服务器的负荷,但是这样会导致如果中间某个 Slave 挂掉了,那依附于它的所有 Slave 都不能用了。
主从复制的原理
上面以及搭建了一个主从复制的样例,是一主两从的,那是怎么 Redis 是怎么具体实现的呢?
在将原理之前,先来看看主从复制的几个概念。启动 Master 后:
127.0.0.1:6379> info server
# Server
redis_version:4.0.9
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:514e9a11b2a67dfc
redis_mode:standalone
os:Linux 5.0.0-23-generic x86_64
arch_bits:64
multiplexing_api:epoll
atomicvar_api:atomic-builtin
gcc_version:7.4.0
process_id:19688
run_id:136de716105e54294144003a881ba29cdfbccfb2
tcp_port:6379
uptime_in_seconds:4515
uptime_in_days:0
hz:10
lru_clock:5556386
executable:/usr/local/redis/etc/redis-server
config_file:/usr/local/redis/etc/redis.conf
这个 run_id 就是 Redis 服务的唯一标识,重启 Redis 服务号,这个 run_id 会改变,多个 Redis 客户端连接到同一个服务端,其 run_id 是一样的,也就是说 run_id 指的是服务端的 id:
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.252.53,port=6389,state=online,offset=5541,lag=1
slave1:ip=192.168.252.53,port=6399,state=online,offset=5541,lag=0
master_replid:f0c89aa8040dfe869de82ee623a1212240456d76
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:5541
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:5541
其中 repl_backlog_size 复制缓存区大小,默认大小为 1M,如果 mater_repl_offset 在这个范围内,就看是部分复制,否则就开始全量复制。
全量复制
先看下图,图画的不是很好见谅。
- 首先 Slave 会向 Master 发送一个 psync 命令,因为是第一次,所以不知道 run_id 和 offset,所以传过来 -1 表示全量复制。
- Master 在接收到 psync 后,将 run_id 和 offset 发送给 Slave,Slave 存储起来。
- Master 进行 bgsave 生成 RDB,并将 RDB 文件发送给 Slave。
- 在 bgsave 和 send RDB 的过程中可能会产生 write 的数据,那么就会把数据存到 repl_back_buffer 中 并将 buffer 发送给 Slave。
- Slave 会清空就数据,然后加载 RDB 和 buffer 将数据存储起来。
部分复制
既然是部分复制,那就是 Slave 已经知道了 Master 的 run_id 和 offset,所以发送 psync 命令带上这两个参数,Master 就知道这是部分复制,然后通过偏移量将需要复制的数据发送给 Slave。
总结
主从复制的过程中既用到了全量复制也用到了部分复制,二者是相互配合使用的。看下面的流程图:
还有一点需要注意的是,如果 Master 重启了,那么它的 run_id 发生了改变,那么依赖它的 Slave 都会进行一次全量复制后在进行部分复制。
最后
觉得不错可以点个赞支持一下!
更多技术文章请关注微信公众号:以Java架构赢天下
上一篇: 从理论到实践的MySQL主从复制原理 - GTID
下一篇: javaWeb项目-ssm+vue网上租车系统功能介绍-本项目源码:java-基于ssm+vue的网上租车系统源码+说明文档资料资源-CSDN文库
推荐阅读
-
异步编程RxJava-介绍-前言 前段时间写了一篇对协程的一些理解,里面提到了不管是协程还是callback,本质上其实提供的是一种异步无阻塞的编程模式;并且介绍了java中对异步无阻赛这种编程模式的支持,主要提到了Future和CompletableFuture;之后有同学在下面留言提到了RxJava,刚好最近在看微服务设计这本书,里面提到了响应式扩展(Reactive extensions,Rx),而RxJava是Rx在JVM上的实现,所有打算对RxJava进一步了解。 RxJava简介 RxJava的官网地址:https://github.com/ReactiveX/RxJava, 其中对RxJava进行了一句话描述:RxJava – Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM. 大意就是:一个在Java VM上使用可观测的序列来组成异步的、基于事件的程序的库。 更详细的说明在Netflix技术博客的一篇文章中描述了RxJava的主要特点: 1.易于并发从而更好的利用服务器的能力。 2.易于有条件的异步执行。 3.一种更好的方式来避免回调地狱。 4.一种响应式方法。 与CompletableFuture对比 之前提到CompletableFuture真正的实现了异步的编程模式,一个比较常见的使用场景: CompletableFuture<Integer> future = CompletableFuture.supplyAsync(耗时函数); Future<Integer> f = future.whenComplete((v, e) -> { System.out.println(v); System.out.println(e); }); System.out.println("other..."); 下面用一个简单的例子来看一下RxJava是如何实现异步的编程模式: Observable<Long> observable = Observable.just(1, 2) .subscribeOn(Schedulers.io).map(new Func1<Integer, Long> { @Override public Long call(Integer t) { try { Thread.sleep(1000); //耗时的操作 } catch (InterruptedException e) { e.printStackTrace; } return (long) (t * 2); } }); observable.subscribe(new Subscriber<Long> { @Override public void onCompleted { System.out.println("onCompleted"); } @Override public void onError(Throwable e) { System.out.println("error" + e); } @Override public void onNext(Long result) { System.out.println("result = " + result); } }); System.out.println("other..."); Func1中以异步的方式执行了一个耗时的操作,Subscriber(观察者)被订阅到Observable(被观察者)中,当耗时操作执行完会回调Subscriber中的onNext方法。 其中的异步方式是在subscribeOn(Schedulers.io)中指定的,Schedulers.io可以理解为每次执行耗时操作都启动一个新的线程。 结构上其实和CompletableFuture很像,都是异步的执行一个耗时的操作,然后在有结果的时候主动告诉我结果。那我们还需要RxJava干嘛,不知道你有没有注意,上面的例子中其实提供2条数据流[1,2],并且处理完任何一个都会主动告诉我,当然这只是它其中的一项功能,RxJava还有很多好用的功能,在下面的内容会进行介绍。 异步观察者模式 上面这段代码有没有发现特别像设计模式中的:观察者模式;首先提供一个被观察者Observable,然后把观察者Subscriber添加到了被观察者列表中; RxJava中一共提供了四种角色:Observable、Observer、Subscriber、Subjects Observables和Subjects是两个被观察者,Observers和Subscribers是观察者; 当然我们也可以查看一下源码,看一下jdk中的Observer和RxJava的Observer jdk中的Observer: public interface Observer { void update(Observable o, Object arg); } RxJava的Observer: public interface Observer<T> { void onCompleted; void onError(Throwable e); void onNext(T t); } 同时可以发现Subscriber是implements Observer的: public abstract class Subscriber<T> implements Observer<T>, Subscription 可以发现RxJava中在Observer中引入了2个新的方法:onCompleted和onError onCompleted:即通知观察者Observable没有更多的数据,事件队列完结 onError:在事件处理过程中出异常时,onError会被触发,同时队列自动终止,不允许再有事件发出。 正是因为RxJava提供了同步和异步两种方式进行事件的处理,个人觉得异步的方式更能体现RxJava的价值,所以这里给他命名为异步观察者模式。 好了,下面正式介绍RxJava的那些灵活的操作符,这里仅仅是简单的介绍和简单的实例,具体用在什么场景下,会在以后的文章中介绍 Maven引入
-
图形组合!一篇了解 Redis 主从复制角色和场景模式与原理的文章!