9. JDBC 读写分离

JDBC读写分离功能是配合数据库读写分离集群使用的,使用读写分离功能需要开启数据库读写分离集群。JDBC读写分离主旨是通过JDBC驱动实现读写分离,并对应用透明。JDBC内部直接识别语句类型和事务读写状态,把读事务中的读语句分发给备机节点执行,以减轻主机的读语句负载,提高整体DB集群的处理能力。

9.1. 使用读写分离功能

JDBC 默认使用单机方式,如需开启读写分离功能,需指定连接参数 USEDISPATCH 为 true ,同时配置备机地址与备机端口,以及各节点的名称。配置读写分离的所有参数可在 JDBC连接属性 看到。

  1. 配置读写分离的基本参数

一般情况下,只需以下5个参数来控制:

#打开读写分离功能
USEDISPATCH=true
#备机地址
SLAVE_ADD=192.168.8.223,192.168.8.130
#备机端口
SLAVE_PORT=54321,54321
#指定各节点的名称,与主备机地址一一对应
nodeList=node1,node2,node3
#主机负载率,备机之间轮询平分
HOSTLOADRATE=33
  1. 读写分离语句分发策略

读语句分发,分两种情况:

(1)单语句事务,这种情况下每条语句都是一个独立的事务,所以读语句分发备机没有问题。

(2)多语句事务,这种情况下,读语句处于事务内,分发需要考虑事务隔离级别,KingbaseES V8.6 支持的三种隔离级别:可重复读(RP),读已提交(RC),序列化。严格意义上这三种都不允许读语句分发,因为可能出现'不可重复读'或者'读不到已提交'的内容。 但是如果事务内的语句就不分发的话,读写分离就失去了大半意义,因为无论是应用还是框架,基本上都是用事务控制的,所以JDBC提供一个分发策略参数TransactionDispatchStrategy控制。

TransactionDispatchStrategy可以选择分发策略(性能优先,默认是2):

1表示事务内的所有语句都只发主机,完全不分发备机;

2表示事务内遇到写语句之前的读语句,可以分发备机,遇到写语句之后就只发主机。

  1. 读写分离读语句可分发节点选择策略

readListStrategy可以选择可分发节点选择策略(性能优先,默认是1):

1表示所有节点均可分发:只看是不是可用的在线节点,是就可以分发,不考虑备机的数据延迟,最大化分发,负载效率最好,但可能出现备机数据延迟造成的主备读取数据不一致。属于弱一致性,适用不要求强一致的应用,比如历史数据分析。

2表示只发主机同步备机:异步备机只做HA,读语句可分发到主机和同步备机,最大化读取一致性,但是无法利用异步备机负载,性能有损耗,属于强一致性,适用要求强一致的应用。

  1. 读写分离对事务隔离性的影响

所有节点均可分发

只发主机、同步备机

事务内只发主

满足RP,不满足RC

满足RP,满足RC

事务内写前分发

都不满足

不满足RP,满足RC

  1. 读写分离对写后读一致性的影响

所有节点均可分发

只发主机、同步备机

事务内

满足

满足

事务间

不满足

满足

  1. 读写分离语句失败重发

JDBC支持切机本意就是指尽量让应用的语句不因为切机造成执行失败,让应用对切机无感知。对于单事务语句基本都可以重发成功,但并不是所有的语句都可以重发成功。 涉及连接会话上下文的以下几种情况会重发失败:

(1)游标:cursor,refcursor切机后全部丢失,重发不能成功。

(2)事务:切机后连接全部都断掉了,事务回退失败,不能重发。

(3)结果集遍历:和游标类似,重发不能成功。

(4)批量操作:批量操作只能全部重做,但有可能已经有部分数据执行成功,如果重发可能会导致重复执行,故不能重发。

9.2. 读写分离一些现象分析

  1. 集群状态正常,socketTimeout设置大于0时,为什么执行时间超长的事务会失败并导致jdbc重建连接?

    sockettimeout是控制底层socket超时返回的最长时间,默认是0,即没有超时。

    如果指定大于0的值,意思就是最多等待sockettimeout的时间,socket的receive操作就会返回。这主要是用来防止当server掉线时,client端socket的receive操作会一直等待。但是这会带来副作用,就是如果一条语句真的执行很长时间超过了sockettimeout的值时,会被认为是超时而中断receive返回超时错误。

    如果是在读写分离状态下,超时会造成重建连接重发语句,会导致超时语句重试达到最大重发次数才会报错返回。驱动有检测机器是否掉线的机制,不会出现一直等待的现象,所以无需配置socketTimeout,使用默认值0即可。

  2. 主备切换后,备机rewind,或者备机故障后,备机恢复时为什么备机的连接数是持续上升,而不是一次性全部建好?

    主备切换后,连接不是马上就全部建立起来的,而是应用确实调用到JDBC时,JDBC才会去判断集群是否切换了,重建连接,重发语句执行。所以连接数的恢复速度和应用操作JDBC负荷有关,通常是慢慢建立起来的,备机的连接会稍滞后于主机连接恢复速度,因为切机重发时,都是只要能找到新的主机就可以重发成功了,不会等到所有备机重启完成。只有等到下一次发送语句触发备机时,JDBC才会去检测备机是否已经起来了,如果未建起才会去重建备机连接。

  3. 主机切机后,应用第一次登陆WEB慢,JDBC等待时间分析。

    局域网内测试拔网线切机后的过程:

    1. 集群的新主机起来可连接后;

    2. 应用用户登录WEB;

    3. 使用连接池中已经有的JDBC连接(主机的连接都已经失效,备机的rewind之前都还在);

    4. 发送SQL;

    5. (I/O Error 20秒)收到错误返回;

    6. 重建JDBC连接(sleep 5秒);

    7. (在线0.1秒返回)+(不在线的需要10秒返回)。重建连接完成开始执行登陆SQL返回,总计35秒左右。

    其中 (不在线的需要10秒返回) 这个可以通过connectTimeout 参数控制connect超时时间,默认是10秒。 其中 (sleep 5秒) 这个可以通过RETRYINTERVAL参数控制重建连接的间隔时间,默认是5秒。 其中 (I/O Error 20秒) 这个可以通过socketTimeout参数控制receive的超时时间,默认是0,无限等待。

    备机的连接不是立刻断掉,而是在一段时间内都还可以使用,等到rewind时连接才会全部断掉。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐