如何解决JDBC驱动方式连接DRDS异常问题
MySQL驱动( JDBC)通过Loadbalance方式连接DRDS,在某些场景下连接切换时会陷入死循环,最终导致栈溢出。
问题定位
- 查看APP日志,定位异常原因。
例如,从以下日志中分析出异常最终原因为栈溢出。
Caused by: java.lang.StackOverflowError
at java.nio.HeapByteBuffer.<init>(HeapByteBuffer.java:57)
at java.nio.ByteBuffer.allocate(ByteBuffer.java:335)
at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:795)
at java.nio.charset.Charset.encode(Charset.java:843)
at com.mysql.jdbc.StringUtils.getBytes(StringUtils.java:2362)
at com.mysql.jdbc.StringUtils.getBytes(StringUtils.java:2344)
at com.mysql.jdbc.StringUtils.getBytes(StringUtils.java:568)
at com.mysql.jdbc.StringUtils.getBytes(StringUtils.java:626)
at com.mysql.jdbc.Buffer.writeStringNoNull(Buffer.java:670)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2636)
- 分析溢出源。
例如,从以下日志可以分析出,溢出原因为驱动内部陷入死循环。
at
com.mysql.jdbc.LoadBalancedConnectionProxy.pickNewConnection(LoadBalancedConnectionProxy.java:344)
at
com.mysql.jdbc.LoadBalancedAutoCommitInterceptor.postProcess(LoadBalancedAutoCommitInterceptor.java:104)
at
com.mysql.jdbc.MysqlIO.invokeStatementInterceptorsPost(MysqlIO.java:2885)
at
com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2808)
at
com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2483)
at
com.mysql.jdbc.ConnectionImpl.setReadOnlyInternal(ConnectionImpl.java:4961)
at
com.mysql.jdbc.ConnectionImpl.setReadOnly(ConnectionImpl.java:4954)
at
com.mysql.jdbc.MultiHostConnectionProxy.syncSessionState(MultiHostConnectionProxy.java:381)
at
com.mysql.jdbc.MultiHostConnectionProxy.syncSessionState(MultiHostConnectionProxy.java:366)
at
com.mysql.jdbc.LoadBalancedConnectionProxy.pickNewConnection(LoadBalancedConnectionProxy.java:344)
- 查看使用的MySQL版本,为5.1.44。
查看该版本源代码,发现获取连接时,LoadBalance会根据负载均衡策略更新连接,并将老连接的配置复制给新连接,在新连接AutoCommit为 true ,新连接部分参数和老连接不一致,loadBalanceAutoCommitStatementThreshold参数没有配置的场景下,会陷入死循环,更新连接函数调用同步参数函数,同步参数又调用更新连接,最终导致栈溢出。
解决方法
在连接DRDS的URL添加**loadBalanceAutoCommitStatementThreshold=5&retriesAllDown=10**参数。
//使用负载均衡的连接示例
//jdbc:mysql:loadbalance://ip1:port1,ip2:port2..ipN:portN/{db_name}
String url = "jdbc:mysql:loadbalance://192.168.0.200:5066,192.168.0.201:5066/db_5133?loadBalanceAutoCommitStatementThreshold=5&retriesAllDown=10";
备注:
1、loadBalanceAutoCommitStatementThreshold:表示连接上执行多少个语句后会重新选择连接。
2、假设loadBalanceAutoCommitStatementThreshold设为5,则当执行5个sql后(Queries或者updates等),将会重新选择连接。若为0表示“粘性连接,不重新选择连接”。关闭自动提交时(autocommit=false)会等待事务完成再考虑是否重新选择连接。
使用mysqldump从MySQL导出数据非常缓慢的原因
mysqldump客户端的版本和DRDS所支持的MySQL版本不一致,可能会导致从MySQL导出数据非常缓慢。
建议版本保持一致。
导入数据到DRDS过程中出现主键重复
要避免导入数据到DRDS过程中出现主键重复的现象,需要在DRDS中创表时设置自增起始值。还要确保起始值大于导入数据自增键的最大值。
如何处理数据迁移过程中自增列报错:主键重复
重新设置自增主键的初始值为大于当前已有数据的最大值,执行如下语句:
ALTER SEQUENCE 库名.SEQ名 START WITH 新初始值
如何处理配置参数未超时却报错
如果发现配置参数未超时却报错的现象,建议可将参数SocketTimeOut值进行调整或者去掉。默认为0则不断开连接。
如何处理DRDS逻辑库与RDS实例的先后关系
DRDS逻辑库与关联的RDS强相关,不允许直接删除关联的RDS,这会导致业务不可用且逻辑库也会删除失败。如果需要删除,先删除逻辑库再删除RDS。
DRDS逻辑库删除后,数据节点里面残留着部分预留的DRDS数据库和一些DRDS的帐户,这些是否需要手动删除
如果不需要了,可以直接手动删除,释放空间。