MariaDB Galera集群:INSERT ...... SELECT锁断了?

时间:2016-11-15 10:53:02

标签: mysql transactions mariadb isolation-level galera

我发现常规MariaDB安装和MariaDB Galera集群之间的行为不一致。对于使用Galera集群的INSERT ... SELECT语句,锁定无法正常工作。这会导致我们的应用程序中出现重复的ID。

所有连接都使用隔离级别REPEATABLE-READ(默认值),使用此查询进行验证:

SELECT * FROM information_schema.session_variables WHERE variable_name = 'tx_isolation';

测试设置:

CREATE TABLE `TestTab` (`id` int(10) unsigned NOT NULL, `name` varchar(100) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8;

预期行为:两个并行连接应该在' id'中创建两个具有两个不同值的记录。字段。

使用常规MariaDB安装(非群集)演示预期行为的命令序列:

Connection 1                                                         Connection 2

SET autocommit=0;
START TRANSACTION;
INSERT INTO TestTab (`id`, `name`)
  SELECT IFNULL(max(id)+1, 1), 'insert 1' FROM TestTab Limit 0,1;


                                                                     SET autocommit=0;
                                                                     START TRANSACTION;
                                                                     INSERT INTO TestTab (`id`, `name`)
                                                                       SELECT IFNULL(max(id)+1, 1), 'insert 2' FROM TestTab Limit 0,1;
                                                                     -- *** GOOD *** INSERT blocks (ensures repeatable read for the SELECT)
COMMIT;
                                                                     -- only now connection 2 completes the the INSERT
                                                                     COMMIT;
SELECT * FROM TestTab;
                                                                     SELECT * FROM TestTab;


                                                    +----+----------+
                                                    | id | name     |
                                                    +----+----------+
                                                    |  1 | insert 1 |
                                                    |  2 | insert 2 |
                                                    +----+----------+

演示MariaDB Galera集群问题的命令序列:

Connection 1                                                         Connection 2

SET autocommit=0;
START TRANSACTION;
INSERT INTO TestTab (`id`, `name`)
  SELECT IFNULL(max(id)+1, 1), 'insert 1' FROM TestTab Limit 0,1;


                                                                     SET autocommit=0;
                                                                     START TRANSACTION;
                                                                     INSERT INTO TestTab (`id`, `name`)
                                                                       SELECT IFNULL(max(id)+1, 1), 'insert 2' FROM TestTab Limit 0,1;
                                                                     -- *** BAD *** INSERT completes immediately, ignoring connection 1
COMMIT;
                                                                     COMMIT;
SELECT * FROM TestTab;
                                                                     SELECT * FROM TestTab;

                                                                     SELECT * FROM TestTab;

                                                    +----+----------+
                                                    | id | name     |
                                                    +----+----------+
                                                    |  1 | insert 1 |
                                                    |  1 | insert 2 | -- !!! same id for both records !!! --
                                                    +----+----------+    

显然,Galera群集的问题在于两个记录在' id'中都有相同的值。字段。在Galera集群上,INSERT ... SELECT模式用于生成唯一ID。

对我而言,这看起来像是一个错误,或者至少是非常不受欢迎和意外的行为。

是否可以使用不同的Galera群集配置修复此内容?

我尝试将两个会话的隔离级别提高到SERIALIZABLE并修复了问题。但这是一个非常不受欢迎的解决方法,性能在这里对我们很重要。而且似乎我还是幸运的是: SERIALIZABLE隔离级别仅在同一节点上发布的事务之间得到尊重,因此应该避免。quote from the Galera Cluster documentation

您能想到哪些更好的解决方法?

我应该尝试将此报告为MariaDB的错误吗?

1 个答案:

答案 0 :(得分:1)

请注意,Galera在COMMIT时间之前不会检入其他节点。与此同时,MAX(id)很高兴获得了旧的价值,并且无法阻止其他人查看MAX(id)

可能的解决方案(我没有测试过任何这些,也没有检查相同的问题和解决方案是否可以在没有 Galera的单个服务器上发生。) :

  • UNIQUE(id) - 这会导致COMMIT中止。
  • 使用READ-COMMITTED查看最新的MAX(id)
  • SELECT移出INSERT并使用FOR UPDATE