前述
最近在研究redis,redis中提到了主从同步,而我常用的mysql数据库中也有主从同步的概念。
故而这次对数据的主从同步进行了了解
为何要读写分离?
访问量大、访问量大、访问量大
我们现在很多技术解决方案,都是为了解决:随着用户量增长,访问量越来越大,而原本的服务架构不足以支撑如此的访问量
而往往读操作是越大部分。我们以往单数据库,一个数据库负责了所有读写操作
所以就提出了一种解决方案——读写分离——由master(主数据库)负责数据的写操作,而slave(从数据库,可多台)只负责读操作
为何要主从同步?
在出现了读写分离的数据库架构设计后,便引出一个问题,slave既然负责读操作,那数据哪里来?
自然是同步master内的数据。
所以我们便将slave从master同步数据,称之为主从同步
如何主从同步?
先大致说下同步原理:在master上,主从同步事件会被写到特殊的log文件中(binary-log);在slave机器上,slave读取主从同步事件,并根据读取的事件变化,在slave库上做相应的更改
先说说主从同步事件的形式:
- statement:会将对数据库操作的sql语句写入到binlog中。
- row:会将每一条数据的变化写入到binlog中。
- mixed:statement与row的混合。Mysql决定什么时候写statement格式的,什么时候写row格式的binlog。
在同步时执行操作
- master数据发生改变,改变事件(DDM、DML)会依次写入到binlog文件
- master会创建一条binlog dump线程,负责与slave联系,当binlog发生变化,dump线程通知slave,并将binlog信息发送给slave
- slave在开启主从同步后,会创建两条线程:
- I/O线程,负责与master的dump联系,接收binlog,并写入到本地的relaylog
- SQL线程,读取relaylog,根据relaylog操作slave数据库
主从同步引出的问题
延时——主从未同步
既然slave负责读,当master写操作后,在slave同步时,这中间必然存在时间间隔
那在这时间间隔中就存在了变数:
- 在slave同步时,用户去slave请求最新数据,却没有——主从不同步
- 在master写操作完成后成功返回,dump开始通知slave,但在这期间,如果master发生了crash,那slave便丢失了本次的写操作
- 在master写操作完成正在返回,且dump已通知slave,但这时,master发生了cash,那么主数据库回滚,但slave却保存了这次写操作
- ...
这该如何?
几种主从同步解决方案
1.异步同步
也是mysql默认的同步方式。
master在执行完客户端提交的事务后会立即将结果返给给客户端,并不关心从库是否已经接收并处理,
但这样就会发生上面所说的第二中情况
2.全同步
顾名思义:
就是master完成写操作事物后不立刻返回,等!等所有slave完成从同步,再返回事物。
这样确实可以保证主从数据一致,但问题也是很明显的
每次master的写操作时间增大!如果一次写操作的数据量巨大,那....。如果在执行某个slave出现的select锁竞争,又要等待,甚至slave出现了死锁...
所以全同步虽然保证了主从同步一致性,但代价也是非常巨大,要慎重
3.半同步
介于异步与全同步之间。master写操作完成后事物不立即返回,至少等待一个slave接收到并写到relay log中,才返回事物。
但也造成了一定的延迟,至少是一个tcp/ip往返时间,所以此方式最好在低延迟环境中执行
其他解决方案
中间件
所有读写操作走中间件,由中间件,写操作路由到master,读操作路由到slave
如本次请求为写操作,在中间件记录该写操作的key,在主从同步时间段,有读操作请求中间件内的该key,则让本次读操作master,主从同步时间段完成后,读请求走slave相关的中间件有:
- canal:是阿里巴巴旗下的一款开源项目,纯Java开发,基于数据库增量日志解析,提供增量数据订阅&消费,目前主要支持了MySQL
- otter:也是阿里开源的一个分布式数据库同步系统,尤其是在跨机房数据库同步方面,有很强大的功能。它是基于数据库增量日志解析,实时将数据同步到本机房或跨机房的mysql/oracle数据库
区别:
- otter目前嵌入式依赖canal,部署为同一个jvm,目前设计为不产生Relay Log。
- otter目前允许自定义同步逻辑,解决各类需求
这样便可保证主从同步,且效率还可以
但中间件嘛,数据库成本也摆在那了
缓存记录写key法
其作用与思路与缓存中间件很类似
写流程:
1)要发生写操作,将key记录在cache里,并设置“主从同步时间”的cache超时时间
2)然后master执行写操作,并执行主从同步
读流程:
1)先到缓存查找key(key设置了失效时间)
2)如有数据,则缓存命中,说明该key刚发生过写操作,此时需要将请求路由到主库读最新的数据。
3)如果缓存没有命中,说明这个key上近期没有发生过写操作,此时将请求路由到从库,继续读写分离。
优点:相对数据库中间件,自然成本较低
缺点:多了一层缓存中间件,那在业务实现时,就要考虑多一些了
总结
以上就是我对读写分离——主从同步的了解与思考,当然是借鉴了其他文章,以前对数据库的读写分离处于只知其名的阶段
本次还是因为要系统了解redis知识体系,所以对主从同步进行了较为深入的了解
希望多多交流,如有疑惑与不足请及时留言交流
知识总要有体系的去学习,这样便可以让自己在脑子里建模,对该知识有个系统的认识,也更便于理解。知识它是什么,为什么有它,它来解决什么技术问题。
参考文档:
https://www.toutiao.com/a6762107909095555592/
https://www.toutiao.com/a6699310878136730115/
https://www.toutiao.com/a6754000358118261251/