对 Galera 集群进行大量写入 - 表被锁定,集群实际上不可用

对 Galera 集群进行大量写入 - 表被锁定,集群实际上不可用

我在 3 个节点上设置了 Galera 集群。它非常适合读取数据。我做了一些简单的应用程序来对集群进行一些测试。不幸的是,当我尝试进行一些写入时,集群完全失败了。也许可以进行不同的配置,或者我做错了什么?

我有一个简单的存储过程:

CREATE PROCEDURE testproc(IN p_idWorker INTEGER)
BEGIN
  DECLARE t_id INT DEFAULT -1;
  DECLARE t_counter INT ; 
  UPDATE test SET idWorker = p_idWorker WHERE counter = 0 AND idWorker IS NULL limit 1;
  SELECT id FROM test WHERE idWorker = p_idWorker LIMIT 1 INTO t_id;
  SELECT ABS(MAX(counter)/MIN(counter)) FROM TEST INTO t_counter;
  SELECT COUNT(*) FROM test WHERE counter = 0 INTO t_counter;
  IF t_id >= 0 THEN
    UPDATE test SET counter = counter + 1 WHERE id = t_id;
    UPDATE test SET idWorker = NULL WHERE id = t_id;
    SELECT t_counter AS res;
  ELSE
  SELECT 'end' AS res;
  END IF;
END $$

现在,我的简单 C# 应用程序在单独的线程中创建 3 个 MySQL 客户端,每个客户端每 100 毫秒执行一次该过程,直到没有列“counter”= 0 的记录。

不幸的是 - 大约 10 秒后,事情开始变得糟糕。服务器上有一个永不结束的进程“query_end”。之后 - 您无法对测试表进行更新,MySQL 返回:

错误 1205 (HY000):超过锁等待超时;尝试重新启动事务

。你甚至无法重启 mysql。你能做的就是重启服务器,有时是整个集群。当你进行大量并发写入/更新时,Galera Cluster 难道如此不可靠吗?难以置信。

答案1

我们遇到了几乎相同的问题 - 当我们更新时,它因锁定超时而失败。我们当前的策略是使用 1 个服务器进行后台进程和大量写入,并使用其他 2 个服务器作为实时 Web 服务器。

如果您使用 HAProxy,这非常简单 - 但我们也必须对代码进行一些更改。

到目前为止,它似乎运行得更好,但我们肯定会在几周后看看它是否运行良好(当我们不再遇到同样的问题时)。

根据我们的经验,我们得出以下几点结论:

几周后,我可以说这些变化确实带来了很大的不同。我认为最重要的变化是分析后台进程并对其进行调度,这样它们就不会重叠(或重叠程度不会太大)。

更改服务器,因此只有一台服务器主要用于写入,另外两台服务器用于读取,这在繁重的后台进程中改善了我们的用户体验。

我们采取的第三步是改进后台进程。在一次交易中,程序员删除了表并从头开始重建。我们将其改为先检查是否需要更改,然后更新行。这极大地提高了该进程的性能。

我们的经验是,在 Galera 集群中读取非常快,但写入可能非常慢,特别是当您执行大量写入操作时。我们一开始遇到了一些小问题,不得不重新导入整个表 - 这对数据库来说是一个很大的杀手。另一件导致我们的服务器两次崩溃的事情是 binlog 填满了服务器的磁盘,这导致服务器崩溃。还要确保将所有数据库更改为 Innodb 表,否则可能会丢失数据。我们的一名程序员将所有日志表设置为 MyISAM - 假设我们在此过程中丢失了一些日志。

但总而言之,我可以说 Galera 现在运行得很好。如果你需要更新数据库服务器或进行其他维护,它就特别好,因为如果你关闭一个节点进行维护,这不是什么大问题。

答案2

我知道已经很晚了,但我还是想在这里分享一下我在 Galera 集群上的经验。我们的应用程序每秒执行大约 160-200 次插入,并且执行同样多的读取。晚上要少得多,但白天这是我们的平均水平,并且可能会达到峰值。我们可能与您的应用程序不在同一环境中,但在我们从标准 MySQL 过渡到 Galera 时,帮助我们的是将我们的应用程序设置为自动提交每个事务,这立即消除了您在这个问题中描述的行为。

在 Python 中使用 PySQLPool 库时,我们必须在查询包装器中添加如下一行:

PySQLPool.getNewQuery(self.connection, commitOnEnd=True)

然后我们面临的另一个问题是它写入表格的速度不够快。我们发现一种让它足够快的方法是使用innodb_flush_log_at_trx_commit 选项。由于我们可以承受 1 秒的交易丢失,因此我们在 my.cnf 中进行了如下设置:

innodb_flush_log_at_trx_commit  = 0

通过这两个简单的设置,我们现在使用 Galera 进行了一年多的生产,并且 3 台服务器在我们的应用程序上运行良好。

最好的。

相关内容