# Mysql主从问题
# 在项目中你们的数据库是么部署的呢?为什么使用MySQL主从?
- 在高并发场景下,为了优化数据库性能和保证数据的高可用性,通常会采用MySQL主从架构进行部署。主从架构是指将数据库划分为主节点和从节点两个角色,主节点处理用户的写请求和更新请求,而从节点主要负责读请求和备份。
- 架构的扩展。业务量越来越大,I/O访问频率过高,单机无法满足,此时做多库的存储,降低磁盘I/O访问的频率,提高单个机器的I/O性能。
# 主从复制的原理?
- master服务器将数据的改变记录二进制binlog日志,当master上的数据发生改变时,则将其改变写入二进制日志中。
- slave服务器会在一定时间间隔内对master二进制日志进行探测其是否发生改变,如果发生改变,则开始一个I/OThread请求master二进制事件。
- 同时主节点为每个I/O线程启动一个dump线程,用于向其发送二进制事件,并保存至从节点本地的中继日志中,从节点将启动SQL线程从中继日志中读取二进制日志, 在本地重放,使得其数据和主节点的保持一致,最后I/OThread和SQLThread将进入睡眠状态,等待下一次被唤醒。
从库分实现原理
- 从库会生成两个线程,一个I/O线程,一个SQL线程;
- I/O线程会去请求主库的binlog,并将得到的binlog写到本地的relay-log(中继日志)文件中;
- 主库会生成一个log dump线程,用来给从库I/O线程传binlog;
- SQL线程,会读取relay log文件中的日志,并解析成sql语句逐一执行;
主从同步事件binlog模式有3种形式:statement、row、mixed。
- statement: 会将对数据库操作的 sql 语句写入到 binlog 中。
- row: 会将每一条数据的变化写入到 binlog 中。
- mixed: statement 与 row 的混合。MySQL决定什么时候写statement 格式的,什么时候写 row 格式的 binlog。
# 如何保证主从一致性?
读写分离提高了资源的利用效率的同时也出了一个问题,就是由于延时(网络传输,操作)而引起的数据库主从不一致的问题,常用相关的数据一致性解决方案。
半同步复制
- 介于异步复制和同步复制之间,主库在执行完客户端提交的事务后不会立即返回给客户端,而是至少要等到一个从库接收并写到redo log中,才会返回给客户端,相对于异步复制,半同步复制提高了数据的安全性
- 半同步复制原理。事务在主库写完binlog后,需要从库返回一个已接收,才能返回给客户端。确保事务提交后binlog至少传输到一个从库。不保证从库应用完这个事务的binlog。
- 优点:利用数据库原生功能,比较简单,缺点:主库的写请求时延会增长,吞吐量会降低。
数据库中间件
- 所有的读写请求都走数据库中间件,通常情况下写请求走主库,读请求走从库。记录所有路由到写库的key, 如果在主从同步的窗口内(假设500ms),有读请求过来了,此时从库有可能还是旧的数据,就需要将key上的读请求路由到主库访问,在主从同步时间过完后,对应key的读请求继续路由到从库
- 优点:能保证绝对一致,缺点:数据库中间件的成本较高
缓存记录写key法
- 写请求,如果key要发生写操作,记录到cache里,设置主从同步的缓存超时时间,比如500ms,然后修改主数据库,读请求,先到缓存里查,对应key有没有相关数据,如果有,说明缓存命中,这个key刚刚发生过写操作,此时需要将请求路由主库读取最新的数据,如果没有,说明缓存没有命中,说明这个key近期没有发生过写操作,此时将请求路由到从库,继续读写分离
- 优点:相对数据库中间件,成本较低 缺点:为了保证一致性,引入了cache组件,并且读写数据库时都多了缓存操作
# 有没有遇到过主从延迟问题?
- 从库机器性能:从库机器比主库的机器性能差,只需选择主从库一样规格的机器就好。
- 从库压力大:可以搞了一主多从的架构,还可以把binlog接入到Hadoop这类系统,让它们提供查询的能力。
- 从库过多: 要避免复制的从节点数量过多,从库数据一般以3-5个为宜。
- 大事务:如果一个事务执行就要10分钟,那么主库执行完后,给到从库执行,最后这个事务可能就会导致失败。
- 网络延迟:优化网络,比如带宽20M升级到I0OM。
- MySQL版本低:低版本的MySQL只支持单线程复制,如果主库并发高,来不及传送到从库,就会导致延迟,可以换用更高版本的MySQL,支持多线程复制。
# 怎么解决主从延迟?
- 使用缓存:我们在同步写数据库的同时,也把数据写到缓存,查询数据时,会先查询缓存,不过这种情况会带来MySQL和Redis 数据一致性问题。
- 查询主库:直接查询主库,这种情况会给主库太大压力,不建议这种方式。
- 数据冗余:对于一些异步处理的场景,如果传输数据ID,消费数据时,需要查询从库,我们可以把数据全部扔给消息队列,这样消费者就无需再查询从库。
# 如果主节点发生了故障怎么切换?
- 采用一主一从来实现故障切换
- 采用一主多从架构来实现故障切换