DB主从一致性的几种解决方法

来源:互联网 发布:腾讯高级php面试题 编辑:程序博客网 时间:2024/05/29 18:41

DB主从一致性的几种解决方法

起源

现在基本所有的程序中都会用到数据库,而数据库其实就是对所有业务逻辑处理结果的保存,所以不论在什么情况下数据的丢失都不被允许的,最坏的情况也要最小化数据的丢失程度,所以一般情况下,数据源都会至少配有两个节点,一个业务处理使用的节点,一个甚至多个从节点,这些从节点就是我们常说的冷备,业务处理节点(主节点)和备份节点一定的时间间隔内进行数据同步,从而来保证当一个数据源坏掉之后,数据也不会丢失,或着丢失很少(主要看同步的时间间隔)。但是为了提高资源的使用效率,所以有人就提出了,可不可以让冷备也被利用起来,替主节点分担部分压力,所以就提出了读写分离的方案。

读写分离

这里写图片描述
读写分离提高了资源的利用效率的同时也引出了一个问题,就是由于延时(网络传输,操作)而引起的数据库主从不一致的问题,对于这个问题,给一下集中解决方案。


1-半同步复制

主从不一致的原因是延时引起的,所以要消除这个延时的影响,可以从主库进行CUD操作时进行规避,办法就是等主从同步完成之后,主库上的写请求再返回,就是大家常说的“半同步复制”semi-sync。

请求请求主库主库从库从库CUD操作开始同步同步完成CUD操作完成
  • 方案优点:利用数据库原生功能,比较简单
  • 方案缺点:主库的写请求时延会增长,吞吐量会降低

2-数据库中间件

CUD操作

请求请求中间件中间件主库主库从库从库CUD操作路由同步

R操作

请求请求中间件中间件主库主库从库从库R操作同步未完成同步完成
  • 方案优点:能保证绝对一致
  • 方案缺点:数据库中间件的成本比较高

3-缓存记录写key法

CUD操作

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

R操作

(1)先到cache里查看,对应库的对应key有没有相关数据
(2)如果cache hit,有相关数据,说明这个key上刚发生过写操作,此时需要将请求路由到主库读最新的数据
(3)如果cache miss,说明这个key上近期没有发生过写操作,此时将请求路由到从库,继续读写分离

  • 方案优点:相对数据库中间件,成本较低
  • 方案缺点:方案缺点:为了保证“一致性”,引入了一个cache组件,并且读写数据库时都多了一步cache操作





  1. 存在问题

 

主从复制架构多次出现复制停滞问题如1032错误和1062错误,其中,1032错误是在主库成功执行后在从库updatedelete时发现从库上找不到这条记录,1062错误是在主库insert完成后在从库执行时出现主键冲突无法成功insert,这些问题可通过跳过错误和前面的复制数据校验修复来解决,但是这些问题产生的直接原因都是主从库数据不一致。这种不一致除了逻辑复制本身可能出现的数据不一致,还有个原因是业务侧或开发人员违规在备库上直接进行增删改操作导致的。

在主从复制架构中,主从库通过VIP绑定实现指定库作为主库,提供读写,从库起backup的作用,当主库出现问题时,VIP切换到从库,从库提供读写,否则从库只是backup正常情况下,我们不允许开发人员直接通过固定IP登录从库操作,但实际工作中往往又难以规避,那么如何从技术角度去避免开发人员在备库操作呢?又如何在避免的同时不影响高可用架构的正常运行和故障切换呢?

 

2.架构配置优化

 

1)直接解决办法

解决上述问题的直接办法是考虑进行架构配置优化,即将从库可读写的状态配置为只读状态。

MySQL官网关于只读有下列描述:

1.Whentheread_only system variable is enabled, the server permits no client updatesexcept from users who havetheSUPER privilege.只读情况下,super权限可读写。

2.Updates performed byslave threads, if theserver is a replication slave. In replication setups, it can be useful toenableread_only on slave servers to ensure that slaves accept updates only from themaster server and not from clients.不影响主从复制线程的读写。

开启只读后,除了super权限账户和复制线程等不受影响外,业务侧开发人员和其它人员即使登录备库也无法操作备库数据。

MySQL [db1]> show global variables like'read_only%';

+---------------+-------+

| Variable_name | Value |

+---------------+-------+

| read_only     | ON   |

+---------------+-------+

1 row in set (0.00 sec)

 

MySQL [test]> insert child values('1','12');

ERROR 1290 (HY000): The MySQL server is running withthe--read-only option so it cannot execute thisstatement

 

    2)配置为只读后如何进行完美故障切换?

 

   从库只读可避免违规操作,但面临的问题是如果主库发生问题,VIP切换到从库上,但这时候从库只读会导致数据库对外服务不可用,因此在切换时需要实现取消从库只读同时设置主库只读的功能。

     KeepalivedMySQL双主(主从)架构为例,正常运行时,VIPMaster1上,Master1为可读写状态,Master2readonly状态,一旦Master1发生问题,VIP要自动切换至Master2,切换前要完成两个步骤:1.Master1置为readonly2.取消Master2readonly

 

3.自动化实现思路

对于一主一从架构,故障切换需要手工进行,因此上述两步也可以手工操作;但KeepalivedMySQL双主(主从)架构中,已实现故障的自动监测和VIP自动切换,上述两个步骤也应该植入脚本中实现自动化。

我们主要需在自动监测和切换脚本中植入对数据库开启readonly和关闭readonly的函数,主要写入语句“set global read_only=ON”和“set globalread_only=OFF”,同时注意在设置状态之前先判断现有状态,shell调用语句“show variables like 'read_only';”得到读写状态,确认读写状态后再设置readonly参数为所需状态即可,注意这些状态设置的触发定制在监测到故障并执行切换之前。

上述思路现已完成自动化转换,亲测成功,说明思路正确。


0 0
原创粉丝点击