MySQL Connector/J 支持服务器故障转移。当底层活动连接发生与连接相关的错误时,就会发生故障转移。默认情况下,连接错误会传播到客户端,客户端必须通过(例如)重新创建工作对象(Statement
、ResultSet
等)并重新启动进程来处理这些错误。有时,驱动程序最终可能会在客户端应用程序继续运行之前自动回退到原始主机,在这种情况下,主机切换是透明的,客户端应用程序甚至不会注意到它。
使用故障转移支持的连接的工作方式与标准连接完全相同:客户端在故障转移过程中不会遇到任何中断。这意味着客户端可以依赖相同的连接实例,即使两个连续的语句可能在两个不同的物理主机上执行。但是,这并不意味着客户端不必处理触发服务器切换的异常。
故障转移是在连接 URL 的服务器连接的初始设置阶段配置的(有关其格式的说明,请参阅此处)。
jdbc:mysql://[primary host][:port],[secondary host 1][:port][,[secondary host 2][:port]]...[/[database]]»
[?propertyName1=propertyValue1[&propertyName2=propertyValue2]...]
连接 URL 中的主机列表包含两种类型的主机,主主机和辅助主机。在启动新的连接时,驱动程序始终尝试首先连接到主主机,如果需要,当遇到通信问题时,驱动程序会依次故障转移到列表中的辅助主机。即使初始连接到主主机失败,驱动程序连接到辅助主机,主主机也不会失去其特殊状态:例如,它可以使用与辅助主机不同的访问模式配置,并且当在故障转移过程中选择主机时,它可以具有更高的优先级。
故障转移支持通过以下连接属性配置(它们的函数将在下面的段落中解释)。
failOverReadOnly
secondsBeforeRetrySource
queriesBeforeRetrySource
retriesAllDown
autoReconnect
autoReconnectForPools
配置连接访问模式
与任何标准连接一样,对主主机的初始连接处于读写模式。但是,如果驱动程序无法建立与主主机的初始连接,并且它自动切换到列表中的下一个主机,则访问模式现在取决于属性 failOverReadOnly
的值,该属性默认值为 “true”。如果驱动程序最初连接到主主机,并且由于某些连接错误而故障转移到辅助主机,则也会发生这种情况。每次连接回退到主主机时,它的访问模式都将是读写模式,无论主主机是否以前连接过。连接访问模式可以在运行时通过调用方法 Connection.setReadOnly(boolean)
随时更改,该方法部分覆盖属性 failOverReadOnly
。当 failOverReadOnly=false
并且访问模式明确设置为 true 或 false 时,它将成为主机切换后每个连接的模式,无论连接到哪种主机类型;但是,如果 failOverReadOnly=true
,则仅当驱动程序连接到主主机时,才能将访问模式更改为读写模式;但是,即使当前连接的访问模式无法更改,驱动程序也会记住客户端的最后意图,并在回退到主主机时使用该模式,否则该模式将是读写模式。为了说明,请查看以下具有两个主机连接的事件顺序。
-
顺序 A,带有
failOverReadOnly=true
以读写模式连接到主主机
设置
Connection.setReadOnly(true)
;主主机现在处于只读模式故障转移事件;以只读模式连接到辅助主机
设置
Connection.setReadOnly(false)
;辅助主机保持只读模式回退到主主机;连接现在处于读写模式
-
顺序 B,带有
failOverReadOnly=false
以读写模式连接到主主机
设置
Connection.setReadOnly(true)
;主主机现在处于只读模式故障转移事件;以只读模式连接到辅助主机
设置
Connection.setReadOnly(false)
;对辅助主机的连接切换到读写模式回退到主主机;连接现在处于读写模式
这两个场景之间的区别在于步骤 4:顺序 A 中辅助主机的访问模式在该步骤中不会改变,但是驱动程序会记住并在回退到主主机时使用设置的模式,否则该模式将是只读模式;但在顺序 B 中,辅助主机的访问模式会立即更改。
配置回退到主主机
如前所述,主主机在故障转移安排中是特殊的,因为它涉及主机的访问模式。此外,驱动程序默认情况下会尽快尝试回退到主主机,即使没有发生通信异常。两个属性 secondsBeforeRetrySource
和 queriesBeforeRetrySource
决定驱动程序何时准备尝试重新连接到主主机(属性名称中的 Source
代表我们的连接 URL 的主主机,它不一定是复制设置中的源主机)。
secondsBeforeRetrySource
决定驱动程序在尝试回退到主主机之前等待的时间queriesBeforeRetrySource
决定在驱动程序尝试回退到主主机之前执行的查询数量。请注意,对于驱动程序而言,对Statement.execute*()
方法的每次调用都会增加查询执行计数器;因此,当调用Statement.executeBatch()
或者启用allowMultiQueries
或rewriteBatchStatements
时,驱动程序可能无法准确地统计服务器上执行的实际查询数量。此外,驱动程序在几个情况下会在内部调用Statement.execute*()
方法。所有这些意味着您只能将queriesBeforeRetrySource
用作何时回退到主主机的粗略规范。
通常,当满足两个属性指定的至少一个条件时,就会尝试回退到主主机,并且尝试始终在事务边界处进行。但是,如果关闭了自动提交,则检查仅在调用方法 Connection.commit()
或 Connection.rollback()
时才会发生。通过同时将 secondsBeforeRetrySource
和 queriesBeforeRetrySource
设置为 “0” 可以关闭自动回退到主主机。仅将其中一个属性设置为 “0” 只会禁用检查的一部分。
配置重新连接尝试
在建立新的连接或发生故障转移事件时,驱动程序会尝试依次连接到主机列表中的下一个候选主机。当列表末尾到达时,它会从列表开头重新开始,但是,如果以下条件满足,则会跳过主主机:(a) 并非所有辅助主机都至少测试过一次,并且 (b) secondsBeforeRetrySource
和 queriesBeforeRetrySource
定义的回退条件尚未满足。每次遍历整个主机列表(不一定在主机列表末尾结束)都被视为一次连接尝试。驱动程序尝试的连接尝试次数由属性 retriesAllDown
的值指定。
无缝重新连接
虽然不建议这样做,但您可以通过将参数 autoReconnect
或 autoReconnectForPools
设置为 true
来使驱动程序执行故障转移,而无需使活动 Statement
或 ResultSet
实例失效。这允许客户端在发生故障转移事件后继续使用相同的对象实例,无需采取任何特殊措施。但是,这可能会导致意外结果:例如,如果驱动程序以读写访问模式连接到主主机,并且它故障转移到只读模式的辅助主机,则进一步尝试发出数据更改查询会导致错误,并且客户端将不会意识到这一点。此限制在使用数据流时尤其重要:故障转移后,ResultSet
似乎没有问题,但底层连接可能已经更改,并且不再有支持的游标可用。
使用 JDBC 和 DNS SRV 配置服务器故障转移
有关详细信息,请参阅 第 6.14 节,“支持 DNS SRV 记录”。