主流数据库主从复制差异——oracle、mysql、mongo、redis、oceanbase

oracle DG

ORACLE主备就是DATAGUARD,也就是DG。主库叫primary,备库叫standby

ORACLE的只读库:ADG,ACTIVE DATAGUARD。oracle 11g开始支持,可以将备库打开为readonly状态,可以分摊IO读的业务压力。也就是说备库没有打开为readonly称为DG,打开为readonly称为ADG。

ADG架构

oracle的同步方式:物理备库和逻辑备库。

物理备库:将redo直接应用到备库上,将block块进行覆盖,是block物理层面的复制,跟sql无关。

逻辑备库:将redo解析成sql,通过sql在备库上重演完成备库同步。

物理备库和逻辑备库的优劣

物理备库的优势:

1.高效性。从底层block同步,与上层sql无关,数据同步具有高效性。比如主库一个sql执行10s,更改1000个块,物理备库仅需要更改这个1000个块即可,不需要管sql本身的执行计划。对于sql执行较长,最终更改1、2行数据的情况,物理备库的同步效率会更高。

2.数据一致性。物理备库与上层sql无关,只要没有延时,就不会出现数据不一致的情况。redo本身就是物理形态,由主库生成,通过网络传播到备库去应用,中间对redo没有任何转换,模式简单没有坑。逻辑备库的表必须有主键才能保证数据一致性,备库在应用时必须将物理redo解析成逻辑sql,理论上数据会一致,即时这样数据一致性也没有物理备库那样的强一致优势。如果逻辑备库上因某些原因某行数据不一致,这个小“污点”不易发现,还很有可能会扩大,不一致的数据会越来越多,修复起来也特别困难。

逻辑备库的优势:

1.灵活性。逻辑备库可以处于打开状态,业务允许修改非同步数据甚至同步数据(不建议),灵活定制数据。

2.坏块的处理。物理备库直接使用redo覆盖block,主库物理坏块备库也会坏块。逻辑备库主备物理层block构造不一样,sql可以执行说明sql在备库是可用的,对坏块是一种保护。

oracle物理备库和逻辑备库的选择:

简单粗暴:物理备库。传统行业几乎没有逻辑备库的应用,物理备库的数据一致性和可靠性对传统行业来说非常香,oracle物理备库的应用已经非常广泛,物理DG架构已经非常成熟,业内认证。我们在讨论oracle的备库时一般指的dg物理备库。就是逻辑备库可能会踩坑,如果真的要逻辑备库,为啥不上mysql等开源库,更加灵活,而且for free~

oracle的保护模式

最大保护模式:在Maximum protection下, 可以保证从库和主库数据完全一样,做到zero data loss.事务同时在主从两边提交完成,才算事务完成。如果从库宕机或者网络出现问题,主从库不能通讯,主库也立即宕机。在这种方式下,具有最高的保护等级。但是这种模式对主库性能影响很大,要求高速的网络连接。

最大可用模式:在Maximum availability模式下,如果和从库的连接正常,运行方式等同Maximum protection模式,事务也是主从库同时提交。如果从库和主库失去联系,则主库自动切换到Maximum performance模式下运行,保证主库具有最大的可用性。

最大性能模式:在Maximum performance,主库把归档的 archived log通过arch进程传递给从库,在这种方式下,主库运行性能最高,但是不能保证数据不丢失,且丢失的数据受redo log的大小影响。在redo log过大的情况下,可能一天都没有归档一个日志,可以通过手工切换日志的方式来减小数据的丢失。

保护模式的选择

传统行业大多数情况下都是最大性能模式,少数最大可用模式,最大保护模式几乎没有,主库宕机背不起这锅。

oracle DG的搭建

在物理DG搭建过程中,较为关键的环境就是全量数据的生成。拉全量数据有2种方式,一个是从主库的备份中拉取,restore recover的过程,一个是duplicate(11g开始支持),直接从主库复制全量数据到备库。全量数据搞定后,数据库处于基于某个时间点的一致性状态,这时开启同步追溯redolog观察lag等信息,DG就算搭建完成了。

oracle adg搭建手册:

https://blog.csdn.net/qq_40687433/article/details/85625266

mysql主从

mysql的同步模式

异步复制(Asynchronous replication)

MySQL默认的复制即是异步的,主库在执行完客户端提交的事务后会立即将结果返给给客户端,并不关心从库是否已经接收并处理,这样就会有一个问题,主如果crash掉了,此时主上已经提交的事务可能并没有传到从上,如果此时,强行将从提升为主,可能导致新主上的数据不完整。

全同步复制(Fully synchronous replication)

指当主库执行完一个事务,所有的从库都执行了该事务才返回给客户端。因为需要等待所有从库执行完该事务才能返回,所以全同步复制的性能必然会收到严重的影响。

半同步复制(Semisynchronous replication)

介于异步复制和全同步复制之间,主库在执行完客户端提交的事务后不是立刻返回给客户端,而是等待至少一个从库接收到并写到relay log中才返回给客户端。相对于异步复制,半同步复制提高了数据的安全性,同时它也造成了一定程度的延迟,这个延迟最少是一个TCP/IP往返的时间。所以,半同步复制最好在低延时的网络中使用。

oracle和mysql的模式区别

可以看出oracle的最大保护模式和mysql全同步是类似的,oracle的异步复制和mysql的最大性能模式是类似的。但是oracle的最大可用模式和mysql的半同步是不同的。半同步是针对整个主备集来定义的,备库中只要一个备库接收到binlog并写入relay,主库即可提交。而最大可用模式是针对主备的,是最大保护和最大性能的中间模式,平时处于最大保护模式,当判断备库不可用时,切换到最大性能模式。

mysql的同步方式

mysql的binlog

在解释mysql的同步方式前,需要了解下mysql双写。双写既是redo和binlog同时写,redo是物理数据页redolog,mysql没有归档的概念。binlog是逻辑数据变更日志(oracle只有redo,没有binlog逻辑写)。binlog有3种模式,默认为row模式,它不是纯sql,也不是物理块,而是行的完整变化。

关于mysql双写的思考,mysql为什么有双写,oracle就没有?

很多人说双写是为了保障数据的可恢复性,那为什么oracle就只需要redo,就没人质疑它的可靠性呢?个人认为这跟设计架构有关系,oracle本身从设计之初就是一个整体,redo提前写入落盘即可保证事务的持久性(ACID中的D持久性)。而mysql的binlog是server层的,server层在设计的时候就需要考虑在无法预知存储引擎架构的情况下,如何保证事务的持久性,那么就只能从server层写入文件系统,mysql的备库就需要应用binlog(备库的relay)。redo是innodb存储引擎层,存储引擎在设计时必须考虑存储引擎的可靠性,数据库在崩溃时如何恢复?当redo日志写入但是数据仍未落盘,数据库start时就需要实例恢复,实例恢复就需要应用redo进行前滚。对于mysql来说,双写是有必要的。(这个双写的原因仅代表个人的思考)

binlog的GTID

GTID是binlog中的事物ID,没有binlog就没有GTID。GTID跟mysql的lsn号或oracle的scn号是有区别的。lsn和scn可以理解为数据库内的时间线,GTID是存在于binlog中的事物ID号,备库可以根据GTID去追踪日志。GTID默认是关闭的,建议打开。

mysql的同步

mysql通过传递binlog进行同步,binlog传递到备库后叫relay log,备库应用relay。在数据库没有打开GTID的情况下,备库只有通过pos(position,字节号)找到需要同步的开始时间点。pos同步可能会有问题,因为binlog和relay不一定是一一对应的,log号不一定对应,pos也不一定对应。但是如果开启GTID同步,备库中断只需要找到GTID即可,在开启同步时可以设置master_auto_postion=1,而pos同步需要指定binlog file和binlog  pos,如:master_log_file='master-bin.000002',master_log_pos=154。

mysql主从搭建

如果开启GTID,mysql主从同步是比较简单的,使用change master命令开启同步以后主库传递binlog,备库接受binlog并写入relay,备库应用relay。因为mysql从库是逻辑备库,全量数据拉取也比较灵活,从数据库层来说,mysql拉全量数据有2种办法:用三方工具xtrabackup(物理),mysqldump(逻辑)。xtrabackup可以进行热备份(仅锁innodb元数据,不会锁数据行),根据lsn号scan up log,并将lsn号以后的事务记录下来,在prepare时进行recover(类似oracle的recover),xtrabackup在备份时会记录pos并放在xtrabackup_binlog_pos_innodb,开启主从时可如开启GTID可直接指定auto position,未开启GTID需要指定xtrabackup_binlog_pos_innodb中的pos值。mysqldump需要锁表以保证数据的一致性。mysql从库可以直接打开(建议从库设置成readonly状态)。

mysql xtrabackup搭建主从:

https://blog.csdn.net/qq_40687433/article/details/108004966?ops_request_misc=%25257B%252522request%25255Fid%252522%25253A%252522160854502316780288280464%252522%25252C%252522scm%252522%25253A%25252220140713.130102334.pc%25255Fblog.%252522%25257D&request_id=160854502316780288280464&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v1~rank_blog_v1-1-108004966.pc_v1_rank_blog_v1&utm_term=主从

mysql xtrabackup热备和oracle rman热备的区别:

https://blog.csdn.net/qq_40687433/article/details/107367562?ops_request_misc=%25257B%252522request%25255Fid%252522%25253A%252522160854402916780279192065%252522%25252C%252522scm%252522%25253A%25252220140713.130102334.pc%25255Fblog.%252522%25257D&request_id=160854402916780279192065&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v1~rank_blog_v1-2-107367562.pc_v1_rank_blog_v1&utm_term=rman

 

mongodb主从

mongodb是文档型数据库,非关系型数据库。mongodb的Master-Slaver主从架构已不推荐使用了,mongo的主流主从副本架构为Replica Set(副本集)。

Replica Set副本集

mongodb建议最小架构为1主2从(详看选举机制就知道为啥最小是3个节点)。主节点接收所有写入操作,从节点异步复制和应用主节点oplog。oplog记录数据库上的所有变更操作。mongodb还没有半同步或者保护模式的形式来保护数据的强可靠性,复制操作是异步的。

1主2从副本集:

(secondary间也是有heardbeat的,以判断节点的可用性)

选举机制

heardbeat会判断节点是否可用,当至少有n/2+1个节点都检测到主节点不可用时,那么这几个节点就需要选举出最高领导者primary,已形成新的副本集服务。每个secondary会发起为自己成为primary的投票,这个时候每个赞成票可能为+1,但是每个反对票为较大的负数,比如-10000,(复制集最多只能有50个节点和7个选举节点)所以只要有1个节点认为这个节点不能成为他的主节点,那么这个节点就不能成为主节点,比如当被选举节点的数据更新慢于其他节点时,那么它就不能被选举成为主节点,其他节点会投反对票。所以在n/2+1个节点中肯定会有一个节点是最新的,它会获得n/2个赞成票,这个节点就选举成为主节点。

选举节点

选举节点概念:arbiter为选举节点,仅负责选举,不负责复制存储数据和提供对外服务

1主1从1选举节点副本集:

1:1架构的弊端:当搭建复制集时采用1主1从的架构,那么当2个节点间的网络不可用时,要不是primary继续提供服务,不要是secondary提升为主节点提供服务,那么到底该选哪一个呢?在mongodb复制集架构中,当故障发生选举时,必须有n/2+1个节点存活时,才可提供对外服务,所以在1:1的架构中只要网络不可用,2个节点都不可以成为主节点。以此类推,偶数个节点的复制集,当他们以55分为2个机房中,当2个机房网络不可用,那么这个复制集就不可用,无法提供对外服务。

这时如果我们让复制集成为单数个,就可以解决这个问题,单数如果资源不够用,没有办法再加入secondary怎么办?这个时候就可以使用arbiter选举节点。选举节点不会存储数据,没有mongo server进程。它可消除选举过程的偶数隐患。当选举节点跟secondary一个机房,网络不可用时,primary节点成为备份节点,secondary和arbier成为新的可用复制集。建议应尽可能使用奇数个节点,且全部为数据节点。

ReplicaSet的同步

rs.initiate操作会扫描除了local库外的所有数据库的所有集合,并插入到secondary。secondary成员在初始化完成后立即开启复制oplog,并应用oplog上的变更操作。mongo4.4开始,sync支持流复制oplog。

redis主从

redis是key-value内存型数据库。

redis的持久化

redis不具备ACID中的durable持久性。redis是内存型数据库,数据写在内存中暂不写入磁盘,且没有redolog,一但发生主机崩溃等意外情况,redis的数据存在丢失风险。对于某些应用来说,redis数据这部分允许丢失部分数据。redis可以不优先考虑redo预写和落盘,这也是为什么redis“快”的重要原因。内存型数据的重要模块之一就是持久化(也就是数据落盘),redis也是有持久化的。redis持久化有2种手段:NDB和AOF。

RDB和AOF

redis有2种持久化方式,rdb持久化和aof持久化还有RDB+AOF的持久化

RDB基线全量持久化,全量持久化保留基线数据,rdb文件存储key键值,特定时间点触发,save/bgsave手动触发rdb持久化。save会阻塞所有操作,bgsave则不会,两者都会将内存中的所有数据写入RDB文件当中。

AOF命令持久化,增量持久化保留变更命令,类似binlog。appendfsync打开时才启用aof持久化,默认是关闭的。appendfsync有3种情况,always,everysec,no。

redis4开始支持RDB+AOF的持久化,此时aof仅做增量持久化,不会存储全量日志。redis重启时先加载rdb再加载aof

redis的ACID持久性

如果掉电,丢失的数据取决于持久化的策略。

如果是RDB持久化,那么一般来说肯定会有数据丢失(除非每个事物后都跟上SAVE或BGSAVE,这基本上不可能的)

如果是AOF持久化,appendfsync不为always,肯定会有数据丢失。但是如果是always,每个事物都会写盘,会丢失一定的性能。RDB+AOF持久化同理。

redis主从原理

1.从服务器向主服务器发送SYNC命令

2.主服务器执行BGSAVE命令,生成RDB文件,并使用一个缓冲区记录从bgsave开始的所有写命令

3.主服务器BGSAVE执行完后,将RDB发送给从服务器,从服务器载入RDB文件,将自己的状态更新至主服务器的BGSAVE时的状态

4.主服务器将缓冲区的写命令发送给从服务器,从服务器执行写命令, 将从服务器更新为主服务器的当前态

复制缓冲区和中断重连:

1 复制缓冲区是主服务器固定长度(默认1mb)先进先出队列

2 主库将写入操作放在复制缓冲区,从库断开后,发送从库的偏移量给主库,主库在复制缓冲区中找是否有这个偏移量,有就发送continue继续从这个偏移量写,没有就重新初始化。

redis主从搭建

slaveof命令即可完成初始化和命令传播的操作,一个命令即可。redis的主从同步也是异步的。

redis主从搭建:

https://blog.csdn.net/qq_40687433/article/details/108737408?ops_request_misc=%25257B%252522request%25255Fid%252522%25253A%252522160861988716780273321830%252522%25252C%252522scm%252522%25253A%25252220140713.130102334.pc%25255Fblog.%252522%25257D&request_id=160861988716780273321830&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v1~rank_blog_v1-5-108737408.pc_v1_rank_blog_v1&utm_term=redis

分布式数据库OCEANBASE

ob最小搭建要求就需要3个节点。ob是准内存型数据库,分布式数据库

ob的持久性

ob是准内存型数据库,当事务完成后不会立即写入磁盘,只有当发生转储时才会写入到磁盘。那么ob如何保持数据的持久性?在paxos协议中,事务只有当至少(n/2+1)个节点完成事务时,这个事务才真正完成。比如3个节点的ob,至少要2个节点完成事务,这个事务才真正的完成。就算一个节点宕机,就算有脏数据没有写入磁盘,事务也不会丢失,ob具备事务的持久性

ob的持久化——转储与合并

转储是将内存数据顺序存储到磁盘上

合并是将基线和内存数据离散的存储到磁盘上

合并的写入代价更改,合并会将基线数据读出并跟内存数据进行合并,然后再返回写入到磁盘原来的位置。

转储也会读取基线数据,将增量数据涉及的表全部读取并顺序的写入到磁盘中。

基线数据是顺序存储在磁盘上的,读取内存后会形成b+树。数据在内存中不会直接被修改,而是以事务链表的形式存储变更数据,它可能只会更改一个列,但是不会读取整个数据块到内存中,只有当发生转储或合并时,才会写入到磁盘。

ob不适合大量数据读取或者写入,更适合高并发少量的数据读取或者写入。

总结

mongodb的ReplicaSet跟ob有些类似,他们都把副本集看成一个整体,但是mongodb没有paxos协议支撑主副本数据一致。ob数据更新时不落盘的特性跟redis又有些类似,他们都是舍弃掉了像oracle和mysql这样的实时落盘操作,以大幅提升性能,而redis又不像ob那样从架构上去保证数据不会丢失。而ob的转储和合并又导致ob不适合大数据量的查询和更新,ob对于高并发和结果只影响少量数据的操作是非常适合的。

每个数据库都有其特点,比如oracle的目标就是集所有功能于一身,功能非常强大,当然成本也非常高。mysql同样是关系型数据,聚簇索引的结构也适合于检索数据,对于数据量较少,压力不大的应用是非常适合的,大部分存储在mysql的应用仅需要“存储”功能,mysql是非常合适的。redis和mongo就更加具有针对性。对于数据安全要求没有特别高,但是数据响应极高的场景,就适合使用redis,可能很多开发都不会把他当成数据库来使用。mongodb是非关系型数据库,数据存储非常灵活,mongodb也有键的概念,一个文档可以有多个键,使用起来要比redis复杂许多。oceanbase在双十一的应用相信不会有人质疑其实力,ob很适合高并发低结果集的场景。它的数据镜像架构有别于传统数据库,多数节点写入的前提可以保证其数据不丢失。

猜你喜欢

转载自blog.csdn.net/qq_40687433/article/details/111562584
今日推荐