社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  DATABASE

MySQL能不能双主?有没有一致性问题?(第46讲)

架构师之路 • 7 月前 • 95 次点击  

《架构师之路:架构设计中的100个知识点》

46.MySQL双主一致性架构优化

MySQL能不能使用双主架构?

可以。


MySQL为什么要使用双主架构?

MySQL最常见的集群架构,是一主多从,主从同步,读写分离,但此时写库仍然是单点。


为了保证MySQL写库的高可用,可以在一个MySQL数据库集群中可以设置两个主库,并设置双向同步,以冗余写库的方式,来保证写库的高可用


MySQL双主架构,会存在什么问题?

如果MySQL双主架构,同时提供服务,可能会引发数据的一致性问题。因为数据的同步有一个时间差,并发的写入可能导致数据同步失败,引起数据丢失


举个栗子:

图片

如上图所述,假设主库使用了auto increment来作为自增主键:

1. 两个MySQL主库设置双向同步来保证主库的高可用;

2. 数据库中现存的记录主键是1,2,3;

3. 主库1插入了一条记录,主键为4,并向主库2同步数据;

4. 数据同步成功之前,主库2也插入了一条记录,由于数据还没有同步成功,插入记录生成的主键也为4,并向主库1也同步数据;

5. 主库1和主库2都插入了主键为4的记录,双主同步失败,数据不一致


能否在MySQL层面,保证两个主库生成的主键一定不冲突呢?

可以的,只需要为两个主库的自增ID:

1. 设置不同的初始值

2. 设置相同的增长步长

图片

如上图所示:

1. 两个MySQL主库设置双向同步来保证主库的高可用;

2. 库1的自增初始值是1,库2的自增初始值是2,增长步长都为2;

3. 库1中插入数据主键为1/3/5/7,库2中插入数据主键为2/4/6/8,不冲突;

4. 数据双向同步后,两个主库会包含全部数据


图片

如上图所示,两个主库最终都将包含1/2/3/4/5/6/7/8所有数据,即使有一个主库挂了,另一个主库也能够保证写库的高可用


上述方案,依赖与数据库的配置,能不能由应用程序,来保证数据的一致性呢?

答案是肯定的,应用程序使用统一的ID生成器,可以保证ID的生成不冲突。

图片

如上图所示,调用方插入数据时,带入全局唯一ID,而不依赖于数据库的auto increment,也能解决这个问题。 


引发不一致的根本原因,是保证高可用的两个主库都对外提供服务,如果只有一个主库对外提供服务,另一个主库平时不提供服务,仅仅在主库挂了的时候提供服务,能否消除上述数据不一致呢?

答案是悲观的,仍然不行。


使用虚IP+keepalived的方式保证数据库主库的高可用,平时只有一台主库提供服务,也可能出现数据不一致。

图片

如上图所示:

1. 两个MySQL主库设置双向同步来保证主库的高可用;

2. 只有主库1对外提供写入服务;

3. 两个主库设置相同的虚IP,在主库1挂掉或者网络异常的时候,虚IP自动漂移,备用主库顶上,保证主库的高可用;


切换过程中,由于虚IP没有变化,所以切换过程对调用方是透明的,但在极限的情况下,仍可能引发数据不一致。

图片

如上图所示:

1. 两个MySQL主库设置双向同步,来保证主库的高可用,并设置了相同的虚IP;

2. 网络抖动前,主库1对上游提供写入服务,插入了一条记录,主键为4,并向备用主库2同步数据;

3. 突然主库1网络异常,keepalived检测出异常后,实施虚IP漂移,备用主库2开始提供服务

4. 在主键4的数据同步成功之前,主库2插入了一条记录,也生成了主键为4的记录,结果导致数据不一致


有没有办法缓解上述问题呢?

虚IP漂移,双主同步延时导致的数据不一致,本质上,需要在双主同步完数据之后,再实施虚IP偏移


使用内网DNS探测,缓解上述问题:

1. 使用内网域名连接数据库,例如:db.kg.org

2. 主库1和主库2设置双主同步,不使用相同虚IP,而是分别使用ip1和ip2;

3. 一开始db.kg.org指向ip1;

4. 用一个小脚本轮询探测ip1主库的连通性;

5. 当ip1主库发生异常时,脚本delay一个x秒的延时,等待主库2同步完数据之后,再将db.kg.org解析到ip2;

6. 应用程序以内网域名进行重连,即可自动连接到ip2主库,并保证了数据的一致性;

画外音:本质上,这是一个可用性与一致性的折衷。


总结

MySQL主库高可用,主库一致性,一些小技巧:

1. 双主同步是一种常见的保证写库高可用的方式;

2. 设置相同步长,不同初始值,可以避免auto increment生成冲突主键;

3. 不依赖数据库,业务调用方自己生成全局唯一ID是一个好方法;

4. 双主保证写库高可用,只有一个写库提供服务,并不能完全保证一致性;

5. 内网DNS探测,可以实现在主库1出现问题后,延时一个时间,再进行主库切换,以保证数据一致性,但牺牲了几秒钟的高可用;


知其然,知其所以然。
思路比结论更重要。

==全文完==

附录,近5年系列内容:
1. 架构篇,已完结:《80个经典架构问题!
2. IM篇,已完结关于即时通讯架构的一切!
3. 架构篇,进行中《架构设计中100个知识点》
4. AI进行中《deepseek原理应用与实践》
5. 知行合一篇规划中 1743天,299万...

讲技术的宝藏号,日更
点赞,转发,再看,感激不尽!

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/180382