事务数据库和防止死锁

时间:2015-06-26 01:51:43

标签: mysql database innodb rsync database-deadlocks

我正在开发云服务,其中将本地数据库(采用POS系统的订单)同步到中央远程数据库。我们的远程数据库运行最新版本的mysql 5.6,每个表都有innoDB表引擎。基本上它充当了一个事务性数据库,它经历了许多主要写入的事务(即INSERT和UPDATE),有时候在查看报告时经历了阅读等。我们不可避免地经历了第一次数据库死锁(请注意这是在升级mysql 5.6之前发生的) ),我对死锁原因的理解可能是有两个连接尝试同时读取或写入一行的地方。我也理解死锁是常见的,并且需要正确的代码来尝试/捕获死锁,我相信我已经设法完成了。 为了减轻死锁,我正在考虑建立两个彼此镜像的数据库 A)写入的数据库 b)读取的数据库

基本上从本地到远程的同步将写入数据库A,并且在后台使用rsync会将数据库A镜像到B,因为rsync不使用数据库,所以数据库B将用于读取和查询报告用于读取数据以进行同步的连接。

我的问题是,此结构是否可以缓解死锁并在服务器上出现任何重大性能问题?

我希望我的问题在我想要实现的目标中有意义。

提前致谢。

3 个答案:

答案 0 :(得分:1)

死锁不是两个连接尝试同时写入同一行的结果。它只是比这复杂一点。

会产生死锁的那种场景就像这样:

有两种资源(可以是表中的两行,两个表,两个文件等,我们将其标识为“A”和“B”)。

  1. 连接#1锁定资源“A”
  2. 连接#2锁定资源“B”
  3. 连接#1继续尝试锁定“B”(同时仍将其锁定在“A”上)。由于连接#2已锁定“B”,因此连接#1等待锁定被释放
  4. 连接#2(仍然锁定“B”)尝试锁定“A”。由于连接#1已锁定“A”,因此连接#2等待释放该锁。
  5. 两个连接现在处于一种状态,每个连接都在等待另一个连接以释放其锁定;他们陷入僵局。死锁只能通过一个连接中断其动作来解除锁定,允许另一个完成。

    这种事情可能发生在数据库中从行到页面到表的任何粒度级别,并且可能发生在数据或索引中。将它留给数据库引擎进行自己的乐观锁定通常可以提供最佳性能,但可能导致死锁。您可能需要在可序列化的转换中执行一些插入/更新(尽管这会带来性能损失)。考虑将多个表作为死锁场景中的潜在参与者的事务。

答案 1 :(得分:0)

数据库复制有助于提高性能和可用性。但是,在开始复制数据库之前,您可能需要查看各个方面。

我假设你已经打开旋钮来记录慢查询。我建议分析并查看是否有机会优化导致查询的问题。 另一件事是,尽管重新建模数据并不总是那么容易,但它有时会有所帮助。 验证您的报告查询是否正在使用索引。 您也可以查看数据分区。

在某些时候,根据您的数据量和报告要求,您可以考虑将NoSQL数据库用于分析数据。

答案 2 :(得分:0)

放弃完全消除死锁。专注于"减轻"它们。

每当实际操作时,按照规范顺序触摸表格和行。一个简单的例子是对IN子句中的元素进行排序。我认为以下可能导致死锁:

UPDATE ... WHERE id IN (3,7) -- in one connection
UPDATE ... WHERE id IN (7,3) -- in another connection

但是如果你在所有事务中对id进行排序,那么最糟糕的是一个连接会等待另一个连接释放行锁。 (这是innodb_lock_wait_timeout发挥作用的地方。)

另一个例子涉及

BEGIN;
SELECT ... FROM table1  FOR UPDATE;
SELECT ... FROM table2  FOR UPDATE;
...
COMMIT;

当然,可能会出现无法预测事务中需要哪些ID或表的情况,因此您无法进行简单的排序。这就是为什么你必须准备好抓住僵局的原因。

当您遇到死锁时,只需重播该事务。好吧,如果您在事务中散布其他代码,可能并不简单。