我有一个流量很高的网站,每小时可能会插入 1000 条新记录。
这一错误使网站陷入瘫痪:
PDOException: SQLSTATE[40001]: Serialization failure: 1213
Deadlock found when trying to get lock;
try restarting transaction: INSERT INTO {location_instance}
(nid, vid, uid, genid, lid) VALUES (:db_insert_placeholder_0,
:db_insert_placeholder_1, :db_insert_placeholder_2,
:db_insert_placeholder_3, :db_insert_placeholder_4);
Array ( [:db_insert_placeholder_0] => 1059 [:db_insert_placeholder_1] =>
1059 [:db_insert_placeholder_2] => 0 [:db_insert_placeholder_3] =>
cck:field_item_location:1059 [:db_insert_placeholder_4] => 1000 )
如果 MySQL 不能处理这种类型的负载,我会感到非常惊讶。那么,我的问题是,这是一个数据库问题吗?如何配置 MySQL 来处理这么多的流量?
我在开发服务器上设置了我的网站副本,其中包含模拟添加到网站的内容负载的脚本。我正在运行具有 16GB RAM 的 Ubuntu、LAMP 堆栈。
诚然,我对数据库不是很了解。事实上,我是从“apt-get install”完成后附带的默认 my.cnf 开始的。表都是 Innodb。你会推荐什么起始配置设置和方法来开始解决这个问题?
让我知道您可能需要更多信息。
谢谢
您正在处理死锁,而不是性能瓶颈问题。
如果您每小时有 1000 条新记录,那么您离达到 MySQL 的限制还很远。MySQL 可以处理至少 50 倍的负载。
死锁是由应用程序代码引起的,不是数据库服务器的错。死锁不能在 MySQL 服务器端修复,除非在某些特定情况下。
InnoDB
可以通过SHOW ENGINE INNODB STATUS
在 MySQL 提示符下运行或使用mysql -uroot -p... -e "SHOW ENGINE INNODB STATUS"
.但是,这只显示最后发生的死锁,没有死锁日志。
值得庆幸的是,有一个工具pt-deadlock-logger可以解决该问题,它负责轮询
InnoDB
状态并在使用新死锁刷新之前保存所有详细的死锁信息。这可能就像运行事务的代码的一部分一样简单:
而您的代码的另一部分以不同的顺序修改相同的表:
如果这两个事务同时运行,可能会出现竞争条件:第一个事务无法修改
t2
,因为它被第二个事务锁定;而第二个事务同样被阻塞,因为t1
被第一个事务锁定。MySQL 选择一个事务作为 INSERT/UPDATE/DELETE 失败的“受害者”。应用程序需要捕获该错误,并重试该语句 - 可能在暂停之后,以便其他事务有时间完成。与容量限制无关,只是不幸的时间安排可能会因代码的排列方式而加剧。切换事务#2 中的DELETE 或事务#1 中的INSERT,然后就没有冲突了——每个事务都将等待访问它需要的表。在 MySQL 5.6 中,您可以在启用innodb_print_all_deadlocks选项的情况下运行,以在 MySQL 错误日志中收集有关所有死锁(不仅仅是最近的死锁)的信息。
[强制性免责声明:我是 Oracle 员工。以上为个人观点,非官方声明。]