PolarDB PostgreSQL版(兼容Oracle)提供了两种一致性级别(一致性是指ACID特性中的Consistency特性):最终一致性、会话一致性,满足您在不同场景下对一致性级别的要求。

问题与解决方案

PolarDB具有主从复制简单易用的特点,通过把主库的WAL异步地传输到备库并实时应用,一方面可以实现高可用,另一方面备库也可以提供查询,来减轻对主库的压力。虽然备库可以提供查询,但存在以下问题:

  • 问题1:主库和备库一般提供两个不同的访问地址,在访问不同库时,需要在应用程序上修改成对应库的地址,对应用有侵入。
  • 问题2:数据的复制是异步的。客户端提交commit并且成功之后,数据可能还没有同步到只读节点。因此备库的数据并不是最新的而是有延迟的,无法保证查询的一致性。

为了解决第一个问题,PolarDB引入了读写分离代理功能。一般的实现是,代理会伪造成PolarDB与应用程序建立好连接,解析发送进来的每一条SQL,如果是UPDATE、DELETE、INSERT、CREATE等写操作则直接发往主库,如果是SELECT则发送到备库。

3

但读写分离还是无法解决由于延迟导致的查询不一致问题。当数据库负载很高时,例如对大表执行DDL(如加字段)操作或大批量插入数据的时候,延迟会非常严重,从而导致无法从只读节点中读取最新数据。

PolarDB采用了异步物理复制方式实现了主节点和只读节点间的数据同步。主节点的数据更新后,相关的更新会应用到只读节点,具体的延迟时间与写入压力有关(一般在毫秒级别),通过异步复制的方式确保了主节点和只读节点间数据的最终一致。PolarDB提供了如下两种一致性级别,满足您在不同场景下对一致性级别的要求:

说明 如何修改一致性级别,请参见配置数据库代理

最终一致性

  • 功能介绍
    PolarDB是读写分离的架构,传统的读写分离只提供最终一致性的保证,主从复制延迟会导致从不同节点查询到的结果不同,例如在一个会话内连续执行如下查询,最后的SELECT结果可能会不同(具体的访问结果由主从复制的延迟决定)。
    INSERT INTO t1(id, price) VALUES(111, 96);
    UPDATE t1 SET price = 100 WHERE id=111;
    SELECT price FROM t1;
  • 适用场景

    若需要减轻主节点压力,让尽量多的读请求路由到只读节点,您可以选择最终一致性。

会话一致性

  • 功能介绍

    针对最终一致性导致查询结果不同的问题,通常需要将业务进行拆分,将一致性要求高的请求直接发往主节点,而可以接受最终一致性的请求则通过读写分离发往只读节点。这既增加了主节点的压力,影响读写分离的效果,又增加了应用开发的负担。

    为解决上述问题,PolarDB提供了会话一致性(也称因果一致性)。会话一致性保证了同一个会话内,一定能够查询到读请求执行前已更新的数据,确保了数据单调性。

    PolarDB的链路中间层做读写分离的同时,中间层会追踪各个节点已经应用的Redo日志位点,即日志序号(Log Sequence Number,简称LSN)。同时每次数据更新时PolarDB会记录此次更新的位点为Session LSN。当有新请求到来时,PolarDB会比较Session LSN和当前各个节点的LSN,仅将请求发往LSN大于或等于Session LSN的节点,从而保证了会话一致性。表面上看该方案可能导致主节点压力大,但是因为PolarDB是物理复制,速度极快。

    4

    在上述场景中,当更新完成后,返回客户端结果时复制就同步在进行,而当下一个读请求到来时,主节点和只读节点之间的数据复制极有可能已经完成。且大多数应用场景都是读多写少,所以经验证在该机制下既保证了会话一致性,又保证了读写分离负载均衡的效果。

  • 适用场景

    PolarDB的一致性级别越高,对主库的压力越大,集群性能也越低。推荐使用会话一致性,该级别对性能影响很小而且能满足绝大多数应用场景的需求。

一致性级别选择最佳实践

  • PolarDB一致性级别越高,集群性能越低。推荐使用会话一致性,该级别对性能影响很小而且能满足绝大多数应用场景的需求。
  • 若对不同会话间的一致性需求较高,可以选择如下方案:
    使用HINT将特定查询强制发送至主节点执行。
    /*FORCE_MASTER*/ select * from user;
    说明
    • 若您需要通过MySQL官方命令行执行上述Hint语句,请在命令行中加上-c参数,否则该Hint会被MySQL官方命令行过滤导致Hint失效,具体请参见MySQL官方命令行
    • Hint的路由优先级最高,不受一致性级别和事务拆分的约束,使用前请进行评估。
    • Hint语句里不要有改变环境变量的语句,例如/*FORCE_SLAVE*/ set names utf8;等,这类语句可能导致后续的业务出错。