Mysql 的主从延迟 指的是 主库受写入 后 到这个写入能体现在 从库上 的这段时间
Mysql 的主从延迟 有两个原因:
1. 写操作 已经在 主库中执行了,但是 binlog 还没有发送出去, 后者还在路上,没有被 从库收到
2. 虽然 binlog 已经被 从库接收到了,但是仍然是以 relay log 存在,还没有被从库消化
对于消费之后要马上显示余额这种对数据一致性强的金融业务,无奈的办法是读和写都打到 主库上。这就需要拆库拆表,分散压力。
如果实时性不强,比如说评论,点赞之类的,可以先使用 前端的 Ajax 直接在用户的界面上 显示出对应的操作结果,不必读刚刚提交的评论或点赞,用户可能刷新界面,刷新界面才是真正的去读取
此时大概率写入的数据已经在从库中了(前提是机器工作正常)
要消除 1 的影响的话,就要在主从间采取类似 request - ack 方式的 问答式交互,类似于 HDFS 的 客户端和流水线的问答方式。但是 Mysql 只支持 一主一从
Mysql 5.5 的 semi-sync 支持这种功能。
要消除 2 的影响的话,可以让从库等待 seconds_behind_master = 0 , 表示消耗完主库发来的 binlog,但是只能精确到秒级,真正地要精确到语句的话,要等待本库消耗的位点等待
也就是不用 GTID 的情况下,要保证执行完的 binlog 的位点 要达到 收到的 binlog 的位点
如果是采用GTID 的情况下,要保证执行完的 binlog 的 GTID 的集合 要 到达收到的 GTID 集合
但是,上面两种消除,都是不必要的,因为都是在等待主从的整个状态 完全一致,追求的是 主从数据库之间完全没有延迟,可能我们写入 A ,想读取 A, 只用A 同步到 从库就行了。
但是如果 后来 写库上又有写语句,并且不能及时同步到从库。那么根据上面的消除策略,就一直读不到 A ,即使 A 已经在从库上了。
于是我们想要 得到 写入的 A 在日志中的位点,或者 GTID 。
要去从库读取 A 的时候,可以等待 A 同步到 从库再开始读,Mysql 官方给出了对应的两种实现:两种原理都差不多
1.不使用 GTID :
先在主库上使用 show master status 得到写入A后 ,主库的最新 binlog 的位点
然后在从库上使用 select master_pos_wait(File, Position, 1); 表示等待 binlog 文件 File , 并且等待这个 binlog 文件的 Position 位点 同步到从库,1表示超时时间
2.使用 GTID:
获得 A 对应的 GTID 有两种方式,一种和上面一样,使用 show master status。二是使用官方的 API ,具体是 C 实现,对于 Java 可以用 JNI 嵌入到 JVM 中去,官方的 API 允许执行后直接返回 这条语句对应 的 GTID。
然后在从库上使用 select wait_for_executed_gtid_set(gtid1, 1);表示等待 gtid1 同步到 从库,超时时间1 秒
有时候 JDBC 的数据库链接长时间不用之后 会断开,是因为两个过期参数:
interactive_timeout,wait_timeout
这两个参数 都是控制 数据库客户端 和 数据库 不交互多久之后 断开连接
只不过前一个是 在指定了 对应的参数的时候才用的。一般使用 后面的?需要试验证实
https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_interactive_timeout
https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_wait_timeout