DB version: 8.0.25 - 阿里RDS
监控收到一条告警信息,于是连上DB查看Processlist
发现一条慢查询,USER字段为root账号,HOST字段是%,觉得很诡异:
1.root账号密码只有本人持有,应用连接是另外一个单独账号
2.HOST字段来源IP是%,正常情况下应该是IP地址才对
3.此SQL执行为何这么久?
针对以上第3个问题,排查到为SQL中调用了一个函数,如果函数的入参为NULL则会导致执行死循环,也正是调用了函数,才会出现USER=‘yd_root’和HOST=‘%’的情况。
后面在阿里云 RDS 文档找到一篇关于%的说明,在最下面常见问题,链接:https://help.aliyun.com/document_detail/94842.html?spm=5176.2020520104.0.0.1155709akPIYwv 文章中提到调用存储过程可能会出现,经测试,发现调用存过,函数,Event的时候都会出现类似情况,其他场景暂没想到。
测试前先创建一个临时账号:
create user test_user@'%' identified by "test_user";
grant all on *.* to test_user@'%' ;
1.测试调用存过
-- session1: 登录root账号
# 创建存储过程,其中 DEFINER=`root`@`%`
USE test;
DELIMITER $$
DROP PROCEDURE IF EXISTS `das` $$
CREATE DEFINER=`root`@`%` PROCEDURE `das`()
BEGIN
SELECT * FROM information_schema.processlist WHERE Id = CONNECTION_ID();
END $$
DELIMITER;
# session2: 登录test_user账号执行存储过程,得到预期结果的USER和HOST
USE test;
CALL das();
ID USER HOST DB COMMAND TIME STATE INFO
178616 root %:52958 test Query 0 executing SELECT * FROM information_schema.processlist WHERE Id = CONNECTION_ID()
# session3: 用root账号执行存过会得到正确的HOST
结果略
2.测试调用函数
-- session1: 登录root账号
# 创建函数,其中 DEFINER=`root`@`%`
USE test;
DELIMITER $$
DROP FUNCTION IF EXISTS `das` $$
CREATE DEFINER=`root`@`%` FUNCTION `das`(cid int) RETURNS VARCHAR(100)
BEGIN
declare v_user VARCHAR(50) ;
declare v_host VARCHAR(50) ;
SELECT user,host into v_user,v_host FROM information_schema.processlist WHERE Id = cid;
return concat('USER:',v_user,' ','HOST:',v_host);
END $$
DELIMITER;
# session2: 登录test_user账号执行函数,得到预期结果的USER和HOST
USE test;
select das(CONNECTION_ID()) as res ;
res
USER:root HOST:%:52958
# session3: 用root账号执行函数会得到正确的HOST
结果略
3.测试调用event
event不涉及 存过 或者 函数 的时候是不会出现HOST字段%的情况的
#模拟下event调用存过出现`%`的场景:
# 登录root账号,创建表及存储过程
use test ;
create table t_event(id int auto_increment PRIMARY key , name VARCHAR(10)) ;
# 创建存储过程,其中 DEFINER=`root`@`%`
use test;
DELIMITER $$
DROP PROCEDURE IF EXISTS `das` $$
CREATE DEFINER=`root`@`%` PROCEDURE `das`()
BEGIN
insert into t_event (name) select concat(sleep(2),'ccc');
END $$
DELIMITER;
# 创建event
use test;
CREATE DEFINER=`root`@`%` EVENT IF NOT EXISTS `test`.`t_event`
ON SCHEDULE
EVERY '2' SECOND
DO call test.das();
# 查看processlist
SELECT *from information_schema.`PROCESSLIST` where id <>CONNECTION_ID() and info <> '' ;
ID USER HOST DB COMMAND TIME STATE INFO
1487 root % test Connect 1 User sleep insert into t_event (name) select concat(sleep(2),'ccc')
模拟下event调用函数出现%的场景:
略