数据库代理的读写分离能力,会解析发送进来的每一条 SQL,如果是 UPDATE
、DELETE
、INSERT
、CREATE
等写操作则直接发往主节点,如果是 SELECT
读操作则发送到只读节点,从而实现读写分离。但是当数据库负载很高时,例如对大表执行 DDL(如加字段)操作或大批量插入数据的时候,数据同步延迟会非常高,从而导致无法从只读节点中读取到最新数据。读写分离代理功能无法解决由于延迟导致的查询不一致问题。
读写节点有数据写入后,相关的更新会同步到只读节点,其中数据同步的延迟时间与写入压力有关。云数据库 veDB MySQL 版通过提供不同的一致性级别,来保证业务访问数据库的数据一致性要求。
说明
一致性级别从最终一致性的调整到会话一致性或全局一致性,仅对新连接生效。从会话一致性或全局一致性调整到最终一致性,存量连接立即生效。操作步骤请参见编辑连接终端。
云数据库 veDB MySQL 版提供自动读写分离的能力,默认提供数据的最终一致性级别,从而保证只读节点最终都能读取到已更新的数据。但最终一致性不能保证立即读取到最新的数据,因为主从复制延迟会导致从不同节点查询到的结果不同,例如在一个会话内连续执行查询操作,最后 SELECT
的结果可能会不同。
对一致性要求不是很高的场景可以选择最终一致性,通过读写分离的能力,减轻主节点的压力,让读请求尽可能路由到只读节点。
由于最终一致性无法保证一个会话内连续执行查询的结果相同,因此无法满足对一致性要求高的场景。在这种情况下,就需要对业务进行拆分,对一致性要求高的业务,只访问读写节点,对一致性要求不高的业务可以采用读写分离模式。为了进一步降低业务改造的负担,veDB MySQL 提供会话一致性的能力。会话一致性保证了同一个会话内,一定能够查询到读请求执行前已更新的数据。在本会话更新后,到本会话或其他会话再次更新之前,读到的结果是稳定的。
在 veDB MySQL 的链路中,数据库代理提供读写分离的能力,会话一致性的实现主要是依赖于数据库代理。
数据库代理会记录每个节点已经应用的日志位点,即日志序号(Log Sequence Number,简称 LSN)。
每次读写事务提交时 veDB MySQL 会记录此次更新的位点为 Session LSN。
当有读请求到来时, 数据库代理会用 Session LSN 和当前各个节点的 LSN 做比较。
仅将请求发往 LSN 大于或等于 Session LSN 的读节点,从而保证了会话一致性。
由于数据库代理节点会比较只读节点 LSN 的推进位置,因此在主从节点延迟很大的情况下,业务无法一直等待,会影响整体性能。所以 veDB MySQL 支持配置超时时间阈值以及超时后的策略。
配置超时阈值:默认值为 10000us,取值范围为 1us~100000000us。
配置超时策略:
发送请求到主节点:如果主从延迟过大,配置的超时阈值较小,会将读请求发往主节点,增加主节点压力。
SQL 报错:如果主从延迟过大,超过阈值,则会直接返回报错:wait replication complete timeout, please retry
。
在上示例述场景中,当更新完成后,返回结果时,数据复制已经开始。所以当下一个读请求到来时,主节点和只读节点之间的数据复制极有可能已经完成,即只读节点可以提供最新的数据查询。所以在这种架构下既保证了会话一致性,又保证了读写分离负载均衡的效果。
适用于一致性要求较高的场景,该级别对性能影响很小而且能满足绝大多数应用场景的需求。
对于所有会话之间可能存在因果关系或依赖关系的场景,会话一致性将无法保证查询结果的一致性。因此 veDB MySQL 也提供了全局一致性的能力。当每个读请求到达数据库代理后,代理都会先去主节点确认当前最新的 COMMIT LSN 位点,然后找到一个合适的只读节点,再将读请求发送至该只读节点。这样就能保证该读请求能够读到至请求发起时刻为止,任意一条已完成更新的数据。
同样为了保证业务的正常使用,全局一致性也支持配置超时时间阈值和超时后的策略。
配置超时阈值:默认值为 10000us,取值范围为 1us~100000000us。
配置超时策略:
发送请求到主节点:如果主从延迟过大,配置的超时阈值较小,会将读请求发往主节点,增加主节点压力。
SQL 报错:如果主从延迟过大,超过阈值,则会直接返回报错:wait replication complete timeout, please retry
。
当主从延迟较高时,只读节点无法及时同步最新的数据,可能会导致更多的请求被路由到主节点,造成主节点压力增大。因此建议在读多写少的场景下选择全局一致性。