Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
调整MySQL配置以支持数百个锁定同一表的连接_Mysql_Design Patterns_Pool - Fatal编程技术网

调整MySQL配置以支持数百个锁定同一表的连接

调整MySQL配置以支持数百个锁定同一表的连接,mysql,design-patterns,pool,Mysql,Design Patterns,Pool,我有一个2000行的资源表。 引擎是innodb。有一个“free_at”字段(索引)。 在每个请求中,我需要锁定表,获取一个空闲资源(按“free_at”列排序),将该行更新为non free,然后释放锁 这是我一直在使用的一个基本池实现,在100-200个连接和不到1000行(池中的资源)的情况下运行良好 目前大约有800个进程不断地从表中请求资源(每10-15秒一次,因此平均高达80秒) 我的瓶颈是锁等待时间,每个请求的等待时间在30到60秒之间(!)。我肯定有一些配置我应该改变,使其锁定

我有一个2000行的资源表。 引擎是innodb。有一个“free_at”字段(索引)。 在每个请求中,我需要锁定表,获取一个空闲资源(按“free_at”列排序),将该行更新为non free,然后释放锁

这是我一直在使用的一个基本池实现,在100-200个连接和不到1000行(池中的资源)的情况下运行良好

目前大约有800个进程不断地从表中请求资源(每10-15秒一次,因此平均高达80秒)

我的瓶颈是锁等待时间,每个请求的等待时间在30到60秒之间(!)。我肯定有一些配置我应该改变,使其锁定和释放更快

我尝试将引擎类型更改为内存,但这并没有改善锁定等待时间

我是否应该寻找另一个不是基于MySQL的池解决方案,并且可以按优先级分配资源(在我的例子中是“free_at”字段)

编辑:

我用它来锁
LOCK TABLES\u name WRITE

然后选择
SELECT*FROM table_name,其中(free_at

更新“free_at”字段
updatetable\u name SET free\u at=NOW()+间隔5分钟,其中id=1234

最终解锁
解锁表格

表模式

`resources` ( `id` int(11) NOT NULL AUTO_INCREMENT, `free_at` datetime DEFAULT NULL, PRIMARY KEY (`id`), KEY `free_at` (`free_at`), ) ENGINE=InnoDB `资源`( `id`int(11)非空自动增量, `在`日期时间默认值为空, 主键(`id`), 键'free\u at`('free\u at`), )引擎=InnoDB
您需要锁定表中的行,而不是整个表。正如您所发现的那样,锁定整个表不会按比例放大

坚持使用InnoDB。内存和MyISAM访问方法不这样做

假设您的
资源
表有以下列(它可以有其他列):

假设您需要一个事务来获取最早的可用资源行(
free
=1),下面是您对每个需要资源的客户机所做的操作

 START TRANSACTION;

 SELECT resource_id
   FROM resource
  WHERE free = 1
  ORDER BY free_at ASC
  LIMIT 1
    FOR UPDATE;
此时,您的应用程序将获得一个单一的资源id(您可以分配该资源id),或者一个也不会得到。如果没有,这意味着它必须等待并重试

如果你有一个资源id,更新它以表明它正在使用中

 UPDATE resource
    SET free = 0,
        free_at = NOW()
  WHERE resource_id = 'the resource ID you just got';
然后,尽可能快地去做

 COMMIT;
要完成您启动的事务,请释放该行上的锁。这种分配资源的方式比锁定表更好,因为每个连接只需要锁定自己的行

如果您没有从
中获取资源id,请选择。。。对于更新
查询,您需要立即执行以下操作

 ROLLBACK;
取消您在该行开始的交易。然后你需要等待,然后再试一次。等待一段有意义的时间:至少等待应用程序使用某个资源并释放它所需的时间。如果您等待的时间较短,那么您的许多连接将在资源表上敲打,并使速度减慢。如果您需要更多资源,请添加一些

当您的软件使用分配的资源完成时,执行此操作以将其释放回池中。您可以在自动提交模式下执行此操作;这里不需要显式事务。但一定要确保你的客户为此打开了自动提交模式

 UPDATE resource
    SET free = 1
  WHERE resource_id = 'the resource ID you have been using';
请注意;我不太明白你是如何在
上使用
free\u的,所以我可能把这部分逻辑搞错了

SELECT
查找空闲资源的操作很可能会通过在


我设法通过内部缓冲资源来解决这个问题。我不是一次获取一个资源,而是获取其中的5个资源,从而将该表上的调用和锁的数量减少了5倍。

能否显示正在使用的表架构和SQL代码?您是锁定整个表还是使用
SELECT。。。对于更新
?使用
free_at为空
肯定会阻止在
SELECT
语句中使用索引。我以前尝试过使用SELECT FOR UPDATE,但遇到死锁异常。这就是为什么我改为使用整行锁定的原因。您提出了一个XY问题:您想要执行X,并且您认为Y是执行此操作的最佳方式。与其问X,不如问Y。我肯定会再次尝试建议的解决方案,只是设想有一种最佳实践方法,可以使用整个表锁创建一个池。实现该方法会延长锁的等待时间。当一行被锁定(在事务中),并且多个其他连接尝试对表进行排序并获取下一行时,会发生什么情况?这不是个问题吗?试着跳过订单,只做限制1。确保尽快提交事务。除非有什么原因你必须循环使用这些资源,只要抓住第一个符合条件的资源就行了。确保表中的可搜索列声明为非NULL,并且已从
WHERE
子句中删除
或col为NULL
 UPDATE resource
    SET free = 1
  WHERE resource_id = 'the resource ID you have been using';
 (free, free_at, resource_id)