2.3 读写分离

3.20.10.0版本dble支持单纯的读写分离,可以和分库分表功能分开单独使用。3.20.10.0之前的版本,分库分表也支持读写分离,兼容该功能。

2.3.1 读写分离配置

2.3.1.1 单纯使用读写分离功能的配置

若想启用dble的读写分离,仅需在 user.xml 文件中配置 rwSplitUser并指定对应的dbGroup即可。dbGroup的配置参考db.xml的章节。这里需要注意的是三种用户配置的顺序是固定的。user.xml的配置请参考user.xml章节。

<dble:user xmlns:dble="http://dble.cloud/" version="4.0">
    <managerUser name="man1" password="654321" maxCon="100"/>
    <shardingUser name="root" password="123456" schemas="testdb" readOnly="false" maxCon="20"/>
    <rwSplitUser name="rwsu1" password="123456" dbGroup="rwGroup" maxCon="20"/>
</dble:user>

配置注意事项:

  1. 当user.xml文件中不配置shardingUser,dble不再加载sharding.xml配置文件(即dble不具备分表分库),包括集群情况下出现sharding.xml不一致,均属于已知现象。
  2. 当同时开启dble读写分离和分库分表的功能,分库分表引用的dbGroup和读写分离引用的dbGroup必须相互独立。rwSplitUser引用的dbGroup,仅需在db.xml中定义即可。shardingUser引用的dbGroup,需要被配置的schemas对应的sharding.xml中的shardingNode所引用。
  3. 多个rwSplitUser可以引用同一个dbGroup。
  4. 被读写分离或者分库分表使用的dbGroup内的instance才会有心跳和连接池;未被有效使用的dbGroup内的instance只有心跳,不会初始化连接池。

2.3.1.2 分库分表中读写分离的配置

分库分表中的读写分离,配置好db.xml和sharding.xml即可,具体参考db.xml和sharding.xml的章节

2.3.2 负载均衡

dble通过配置多个dbInstance为读操作提供负载均衡,注意的是rwSplitMode配置不为0,详细请参见db.xml章节。负载均衡规则如下:

  1. 确定参与读写分离的dbInstance集合
  2. 负载均衡算法

2.3.2.1 确定参与读写分离的dbInstance集合

该算法在每次连接获取时提供可用的dbInstances实例集。可用的dbInstance是指心跳正常的dbInstance,这里需要注意的是show slave status和其他心跳语句是有区别的,以该语句作为心跳语句,心跳正常只是基本前提。dble会根据最近一次的心跳返回结果判断读库和主库的延迟,如果延迟超过delayThreshold配置,则不会将此节点加入到dbInstances实例集中,如果delayThreshold=-1那么不会进行延迟检测。

  • 写节点(primary="true")可用
    • rwSplitMod配置为2,则写节点有资格参到读写分离,将写节点加入到dbInstances实例集
    • 读节点(primary没配置或者 primary="false")
      • 节点可用且需要进行延迟检测,检查延迟是否在阈值内再决定是否加入到dbInstances实例集
      • 节点可用且不需要进行延迟检测,直接加入到dbInstances实例集
  • 写节点异常
    • 检查读节点是否可用,与上面读节点的检测机制一致

2.3.2.2 负载均衡算法

该算法在dbInstance集合中选择一个dbInstance实例来获取连接。

  • dbInstance集合为空,前端报错。
  • dbInstance集合非空
    • 每个dbInstance有权重设置(readWeight参数), 但不都是等值权重, 依权重随机选择。
    • 每个dbInstance无权重设置或所有权重等值, 则等权随机选择。此种情况只是上面情况的特例。

2.3.2.3 写节点是否参与均衡与dbGroup的rwSplitMode属性有关,具体见下图

rwSplitMode

2.3.3 读写分离支持语句类型

在事务中所有语句都会发主,在非事务中则根据语句类型进行负载均衡。

2.3.3.1 纯读写分离支持的语句类型

  1. ddl
  2. dml
  3. prepared statement协议
  4. 函数,存储过程

2.3.3.2 分库分表支持的语句类型

  1. 可进行负载均衡的SQL语句为 select 或者 show。

2.3.4 读写分离功能限制

  1. druid 解析器限制 - 不支持set语句中存在特殊字符;
  2. druid 解析器限制 - set session transaction read write, isolation level repeatable read中,逗号后的语句不生效;
  3. 只读事务(在 >= dble 3.21.06.x版本中支持,之前的版本不支持此功能)
  4. 不支持set transaction read write;
  5. select 语句现在的逻辑是都进行负载,还没有进行细节的区分,比如有些语句需要强制发主,如系统函数,系统表,系统变量;
  6. select ... into 或者 load data中存在用户变量,通过dble再次查询该变量,变量值不对;
  7. 在会话中,删除正在使用的库,mysql会将当前库置为null,dble会依然保留正在使用的库;
  8. set 语句目前只支持会话级别系统变量和用户变量的设置,若需要设置密码等可以使用hint的方式设置或去后端节点去设置;
  9. 读写分离会打破原先的隔离级别的原有语义,对此有严格要求的需要酌情考虑;
  10. 创建临时表后,之后所有的语句都发往主,因为临时表不支持主从复制。直到你删除了所有临时表后,原先的负载均衡策略恢复;
  11. 部分客户端,比如 在设置了 allowMultiQueries=true (默认为 false) 的 jdbc,此时客户端可以一次性发送 multi-queries , dble 对此情况不做拆分,全部发往主。MySQL Command-Line client 会在客户端拆分语句,一次只发送一条语句,故不会有该条限制 ;

2.3.5 读写分离后端实例的粘滞性

rwStickyTime参数

功能背景

读写分离非事务场景下, 写完立刻读, 读会发到从机上可能存在主从延迟从而导致读不到数据.

粘滞性

执行当前读SQL的时间,距离上一次写SQL执行的时间段,没有超过rwStickyTime时间段时,则当前读SQL将会下发至后端主(写)实例.
特例:Hint SQL不参与实例的粘滞性

特性

此粘滞性功能,优先于db.xml中的rwSplitMode配置

举例说明

假设,rwStickyTime=1000,表示粘滞时间段为1000ms;操作如下:

Step Time Line SQL InstanceDB of backend 说明
0 50ms Hint_SQL_1(如:/*master*/ sql) master 下发到主实例;不参与粘滞,不更新时间点timeA
1 100ms 写SQL_1 master 下发到主实例;更新时间点timeA=100ms
2 500ms 读SQL_2 master 原本应该下发到从实例,但满足rwStickyTime>0且(500ms-timeA)<=rwStickyTime,因此SQL最终下发到主实例
3 600ms Hint_SQL_2(如:/*slave*/ sql) slave 依旧下发到从实例;不参与粘滞
4 900ms 读SQL_3 master 原本应该下发到从实例,但满足rwStickyTime>0且(900ms-timeA)<=rwStickyTime,因此SQL最终下发到主实例
5 2000ms 读SQL_4 slave 下发到从实例;(并不满足rwStickyTime>0&&(2000ms-timeA)<=rwStickyTime)

补充:在读写分离中,读SQL和写SQL的定义较为简明:select...show ... 语句为读SQL,其他语句即为写SQL.

2.3.6 读写分离本地读

功能背景

读写分离本地读场景下,dble实例的配置与instance实例的配置一致,就可以认定该instance为本地实例,读流量会优先下发到本地实例,如果本地实例存在异常或者不可用,按照策略下发到其他实例

2.3.6.1 使用读写分离本地读的的配置

若想启用dble的读写分离本地读功能,需要在bootstrap.cnf和db.xml文件中配置
bootstrap.cnf

-Ddistrict=district1
-DdataCenter=dataCenterA

db.xml

<?xml version="1.0"?>
<dble:db xmlns:dble="http://dble.cloud/">

    <dbGroup name="dbGroup1" rwSplitMode="1" delayThreshold="100">
        <heartbeat errorRetryCount="1" timeout="10" keepAlive="60" >show slave status</heartbeat>
        <dbInstance name="instanceM1" url="ip4:3306" user="your_user" password="your_psw" maxCon="200" minCon="50" dbDistrict="district1" dbDataCenter="dataCenterA" primary="true">
        </dbInstance>
        <!-- can have multi read instances -->
        <dbInstance name="instanceS1" url="ip5:3306" user="your_user" password="your_psw" maxCon="200" minCon="50" dbDistrict="district1" dbDataCenter="dataCenterA" primary="false">
        </dbInstance>
        <dbInstance name="instanceS2" url="ip6:3306" user="your_user" password="your_psw" maxCon="200" minCon="50" dbDistrict="district1" dbDataCenter="dataCenterA" primary="false">
        </dbInstance>
           <dbInstance name="instanceS3" url="ip7:3306" user="your_user" password="your_psw" maxCon="200" minCon="50" dbDistrict="district1" dbDataCenter="dataCenterB" primary="false">
        </dbInstance>
        <dbInstance name="instanceS4" url="ip8:3306" user="your_user" password="your_psw" maxCon="200" minCon="50" dbDistrict="district2" dbDataCenter="dataCenterC" primary="false">
        </dbInstance>
    </dbGroup>
</dble:db>

配置注意事项:

  1. 只有select语句生效
  2. rwSplitMode具有更高优先级
  3. 使用该功能至少需要bootstrap.cnf中配置district参数,对应的dbinstance配置dbDistrict参数
  4. 本地读匹配优先级
    4.1 从district标签和dataCenter标签都符合的instance中挑选下发语句
    4.2 找不到符合4.1中的条件或者符合4.1中条件的instance都处于异常状态,从只符合district标签匹配的instance中挑选下发语句
    4.3 找不到符合4.2中的条件或者符合4.2中条件的instance都处于异常状态,从剩余的instance中挑选下发语句
  5. hint语句按照hint的写法下发

举例说明: dble使用如上配置,使用dbGroup1的读写分离用户下发一条select语句

localread

results matching ""

    No results matching ""