我目前正在通过AWS RDS使用MySQL 5.5,并将node.js用于服务器。我们有几个使用中央服务器的web应用程序,auth是基于令牌的,类似于oauth。登录时,您将获得一个身份验证代码并将其交换为访问和刷新令牌。然后,每隔一段时间,刷新令牌用于获取新的访问和刷新令牌。所有三个令牌都有一个到期日,当前我们创建新令牌时,我们有一个DELETE查询,它将删除过期的令牌。以下是此示例:
DELETE FROM tokens WHERE expires <= NOW() LIMIT 50;
INSERT INTO tokens (type, ...) VALUES ('access', ...);
INSERT INTO tokens (type, ...) VALUES ('refresh', ...);
这3个语句作为单个事务发送到数据库服务器,不会单独查询它们。令牌表如下所示:
CREATE TABLE `tokens` (
`type` varchar(10) NOT NULL,
`system` varchar(45) NOT NULL,
`userid` int(10) NOT NULL,
`key` varchar(45) NOT NULL,
`token` varchar(45) NOT NULL,
`created` datetime NOT NULL,
`expires` datetime NOT NULL,
`scopes` longtext,
PRIMARY KEY (`token`,`expires`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
这已经工作了几年,99%的时间都很有效。随机地,服务器挂起,不再接受任何连接或查询。查看进程列表,有一堆挂起的DELETE查询。似乎行是锁定的,因为我有一个WHERE并且INSERT正在尝试执行并且事情被破坏了。 DELETE最多只能选择50行来删除,所以我很好奇为什么会随机出现这种情况?
我们正在尝试采取其他措施解决此问题,例如删除较小的块并减少频繁使用(扩展访问令牌到期时间)。
有没有更好的方法来清理过期的令牌?
答案 0 :(得分:1)
您应该在expires
上添加索引。复合索引(token, expires)
只能用于自己搜索token
和expires
或token
的查询(因为它是复合索引的前缀)
然后DELETE
查询将能够使用该索引,并且在查找已过期的令牌时不会锁定其扫描的表中的所有其他行。
根据您执行的其他查询,可能只需交换现有索引中列的顺序,即将其更改为PRIMARY KEY (expires, token)
。