数据库读写分离、数据一致性的冲突、msql主从复制

 

本文只作为知识点扫盲,并不做任何深入,单纯记录相关知识点,以备后期检索

文中相关内容已标明转载地址


面对数据一致性问题的选择:


观点一:https://www.cnblogs.com/lice-blog/p/11569748.html

读写分离: 为保证数据库数据的一致性,我们要求所有对于数据库的更新操作都是针对主数据库的,但是读操作是可以针对从数据库来进行。大多数站点的数据库读操作比写操作更加密集,而且查询条件相对复杂,数据库的大部分性能消耗在查询操作上了。

主从复制数据是异步完成的,这就导致主从数据库中的数据有一定的延迟,在读写分离的设计中必须要考虑这一点。

1. 适当放弃一致性:在一些实时性要求不高的场合,我们适当放弃一致性要求。这样就可以充分利用多种手段来提高系统吞吐量,例如页面缓存、分布式数据缓存、数据库读写分离等等。

以博客为例,用户登录后发表了一篇文章,他需要马上看到自己的文章,但是对于其它用户来讲可以允许延迟一段时间(1分钟/5分钟/30分钟),不会造成什么问题。这时对于当前用户就需要读主数据库,对于其他访问量更大的外部用户就可以读从数据库。


2. 可以通过程序控制,将强一致性要求的功能(比如存钱、取钱)的读写操作均指向主数据库,或者将写操作采用“双写”的方式实现;而弱一致性(最终一致性)要求的功能(比如更新微博(写)、金融查询账户(读))实现读写分离。

总结:要使用读写分离来实现系统吞吐量的提升就要从业务上想办法降低一致性的要求。对必须要有一致性的功能是无法进行读写分离的,可以采用多库不区分读写以及memcache缓存技术来实现。

其他方案:

1、利用客户端缓存,减少对数据库的反复读取,当用户读取一次评论之后便将评论信息写入本地cookie,当用户在一段时间内不停刷新页面的时候,就不让他再读数据库了直接去cookie里面取数据。添加到数据库数据成功的同时也返回数据告诉客户端也添加到cookie里面去。这样用户就知道他自己成功评论了,而且不论他怎么刷都伤不到服务器。 

2、利用缓存服务器的缓存,减少对数据库的反复读取,和cookie差不多,只不过是存在了服务器的内存里面。这样比读数据库快,但是需要注意这种情况下,如果用户玩命的刷,服务器还是很伤。就算是读内存还是得读服务器的东西。
 
3、没必要将所有的评论都放在数据库里,如果评论太多太久远的没有意义的就删了吧。

4、关于同一时间并发的评论,直接先不写数据库,先全写到内存里去合并数量,然后按照数据库能接受的节奏,写进数据库。其实这个也是治标不治本,真正的洪流来了,怎么优化都没用。直接封IP吧。 
 
最后的大招: 
告诉用户他的数据已经提交,但是服务器更新需要一定的时间,请不要着急等30秒后刷新看看。这招最简单,根本就不用什么程序。

观点二:https://www.cnblogs.com/lenther2002/p/5021474.html

处理一个数据库死锁的异常时候,其中一个建议就是使用 NOLOCK 或者 READPAST,对于非银行等严格要求事务的行业,搜索记录中出现或者不出现某条记录,都是在可容忍范围内,所以碰到死锁,应该首先考虑,我们业务逻辑是否能容忍出现或者不出现某些记录,而不是寻求对双方都加锁条件下如何解锁的问题。

NOLOCK 和 READPAST 都是处理查询、插入、删除等操作时候,如何应对锁住的数据记录。但是这时候一定要注意NOLOCK 和 READPAST的局限性,确认你的业务逻辑可以容忍这些记录的出现或者不出现:  简单来说:

NOLOCK 可能把没有提交事务的数据也显示出来.

READPAST 会把被锁住的行不显示出来 

不使用 NOLOCK 和 READPAST ,在 Select 操作时候则有可能报错误:事务(进程 ID **)与另一个进程被死锁在 锁 资源上,并且已被选作死锁牺牲品。


https://www.cnblogs.com/bigox/p/11530540.html

MySQL主从复制(异步复制与半同步复制)

1.MySQl主从复制

  • 原理:将主服务器的binlog日志复制到从服务器上执行一遍,达到主从数据的一致状态。

  • 过程:从库开启一个I/O线程,向主库请求Binlog日志。主节点开启一个binlog dump线程,检查自己的二进制日志,并发送给从节点;从库将接收到的数据保存到中继日志(Relay log)中,另外开启一个SQL线程,把Relay中的操作在自身机器上执行一遍

  • 优点

    • 作为备用数据库,并且不影响业务
    • 可做读写分离,一般是一个写库,一个或多个读库,分布在不同的服务器上,充分发挥服务器和数据库的性能,但要保证数据的一致性

2.主从复制的日志格式

这里的日志格式就是指二进制日志的三种格式:基于语句statement的复制、基于行row的复制、基于语句和行(mix)的复制。其中基于row的复制方式更能保证主从库数据的一致性,但日志量较大,在设置时考虑磁盘的空间问题

show variables like ‘%binlog%format%’;    #查看当前使用的binlog的格式
set binlog_format = ‘row’;                #设置格式,这种方法只在当前session生效
set global binlog_format = ‘row’;       #在全局下设置binlog格式,会影响所有的Session

3. 复制架构

3.1、一主多从架构

在主库的请求压力非常大时,可通过配置一主多从复制架构实现读写分离,把大量对实时性要求不是很高的请求通过负载均衡分发到多个从库上去读取数据,降低主库的读取压力。而且在主库出现宕机时,可将一个从库切换为主库继续提供服务(主备切换)

3.2、多级复制架构

因为每个从库在主库上都会有一个独立的Binlog Dump线程来推送binlog日志,所以随着从库数量的增加,主库的IO压力和网络压力也会随之增加,这时,多级复制架构应运而生。

多级复制架构只是在一主多从的基础上,在主库和各个从库之间增加了一个二级主库Master2,这个二级主库仅仅用来将一级主库推送给它的BInlog日志再推送给各个从库,以此来减轻一级主库的推送压力。

但它的缺点就是Binlog日志要经过两次复制才能到达从库,增加了复制的延时。

我们可以通过在二级从库上应用Blackhol存储引擎(黑洞引擎)来解决这一问题,降低多级复制的延时。

“黑洞引擎”就是写入Blackhole表中数据并不会写到磁盘上,所以这个Blackhole表永远是个空表,对数据的插入/更新/删除操作仅在Binlog中记录,并复制到从库中去。

3.3、双主复制/Dual Master架构

双主复制架构适用于需要进行主从切换的场景

在只有一个主库的架构下,当主库宕机后,将其中一个从库切换为主库继续提供服务。原来的主库就没有数据来源了,那么当这个新的主库接收到新的数据时,原来的主库却没有同步,因此他们的数据差异越来越大,那么原来的主库就无法成为主从复制环境中的一员了。当原来的主库恢复正常后,需要重新将其添加进复制环境中去。

那为了避免重复添加主库的问题,双主复制应运而生。两个数据库互为主从,当主库宕机恢复后,由于它还是原来从库(现在主库)的从机,所以它还是会复制新的主库上的数据。那么无论主库的角色怎么切换,原来的主库都不会脱离复制环境。

4.复制方式

MySQL的主从复制有两种复制方式,分别是异步复制和半同步复制

4.1异步复制

1、逻辑上

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

2、技术上

主库将事务 Binlog 事件写入到 Binlog 文件中,此时主库只会通知一下 Dump 线程发送这些新的 Binlog,然后主库就会继续处理提交操作,而此时不会保证这些 Binlog 传到任何一个从库节点上

4.2全同步复制

基本不会考虑该模式

1、逻辑上

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

2、技术上

当主库提交事务之后,所有的从库节点必须收到、APPLY并且提交这些事务,然后主库线程才能继续做后续操作。但缺点是,主库完成一个事务的时间会被拉长,性能降低。

4.3半同步复制

1、逻辑上

是介于全同步复制与全异步复制之间的一种,主库只需要等待至少一个从库节点收到并且 Flush Binlog 到 Relay Log 文件即可,主库不需要等待所有从库给主库反馈同时,这里只是一个收到的反馈,而不是已经完全完成并且提交的反馈,如此,节省了很多时间。

2、技术上

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

mysql具体如何配置可参考

https://www.cnblogs.com/zero-gg/p/9057092.html

mqspl半同步存在的一些问题

https://www.cnblogs.com/jichunhu/p/5825801.html


https://www.jianshu.com/p/5387bf6b6dec

数据不一致冲突产生的原因:从数据库同步数据的同时可能给业务方返回的是旧的数据,即所谓的脏读现象

异步复制:

【1】系统先对Master-DB进行了一个写操作,写主库,主库写入完毕,返回成功,并不关心从库是否已同步更新;
【2】很短的时间内并发进行了一个读操作,读从库,此时主从同步没有完成,故读取到了一个旧数据(“旧”是个相对概念,用户已经收到写入成功的消息,那么原数据就相对而言成了旧数据);
【3】主从同步完成。

该模式其他的问题在于假如在写主库发生之后,主从同步完成之前发生了主备切换,那么新主库中就会丢失掉之前的写事务


数据一致性冲突的解决方案:


方案一、读写都在主库

 显然,这是一种最简单的方法,读写全落在主库上,必然不会带来不一致问题(针对一些强一致性要求的数据可以这么做,但是一些弱一致性需求的数据则不需要)。如图所示:

 

方案二、semi-sync(半同步复制)

之所以会读取到旧数据,关键在于主从同步需要一个时间段,而读取请求可能刚好就发生在同步阶段。为了读取到最新的数据,需要等主从同步完成之后,主库上的写请求再返回。示意图如图所示:

【1】系统先对DB-master进行了一个写操作,写主库;
【2】等主从同步完成,写主库的请求才返回成功;
【3】读从库,读到最新的数据(如果读请求先完成,写请求后完成,读取到的是“当时”最新的数据,这就不算是脏数据。始终保证读到的是当时的最新数据)

显然带来的后果就是主库的写请求时延会增加,吞吐量会降低。

方案三、数据库中间件

借助中间件的路由作用,对服务层的读写请求进行分发,从而避免出现不一致问题。示意图如图所示:

【1】所有的读写都走数据库中间件,通常情况下,写请求路由到主库,读请求路由到从库;
【2】记录所有路由到主库的key,在经验主从同步时间窗口(根据经验设置一个允许同步时间)内(假设是500ms),如果有读请求访问中间件,此时有可能从库还是旧数据,就把这个key上的读请求路由到主库;
【3】经验主从同步时间过完后,对应key的读请求继续路由到从库

中间件带来的好处就是能保证数据的绝对一致性,但同时也带来成本上升的问题。

方案四、利用缓存

 原理同方案三类似,当写请求发生时,

【1】将某个库上的某个key要发生写操作,记录在cache里,并设置“经验主从同步时间”的cache超时时间;
【2】修改数据库

而读取请求发生的时候:

从图中可以看出:
1)先到cache里查看,对应库的对应key有没有相关数据;
2)如果cache hit,有相关数据,说明这个key上刚发生过写操作,此时需要将请求路由到主库读最新的数据;
3)如果cache miss,说明这个key上近期没有发生过写操作,此时将请求路由到从库,继续读写分离。
显然,利用缓存,减少了中间件带来的成本问题,但多了一个Cache组件,并且读写数据库多了一步Cache操作,操作相对其他稍较繁琐。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值