关于我是如何解决刚上线几天的系统宕机

96 阅读2分钟

如往常一样下班准备6点准时跑路,刚回到家准备躺着刷无脑短视频。霸道总裁爱上我之类的爽文男主角。突然电话一直响个不停,公司那头炸雷了,要求我立马赶回公司处理问题。表现现象是所有的用户登录不见了,直接登录报错。

直接先连vpn连上公司网络,打开k8s容器查看日志发现,大量的数据库死锁日志,第一想法就是先杀掉死锁的连接。发现根本行不通。

报错日志如下

UPDATE `rbac_user` t SET t.`login_count` = 0, `pwd_expire_day` = 90, `last_login_time` = TIMESTAMP '2024-10-25 10:39:08.000', `status` = '0', `update_user` = 'rbac_user_superuser', `update_date` = TIMESTAMP '2024-10-25 10:39:08.625' WHERE t.id IN ('03xqnu2hykkzt')
2024-10-25 10:39:18.685 [pool-8-thread-1] ERROR c.s.snest.engine.db.relationdb.RelationDBAccessor -数据源:main,执行SQL失败:Lock wait timeout exceeded; try restarting transaction 

观察报错日志文件我们可以看到

Lock wait timeout exceeded; try restarting transaction 

登录用户直接报错,锁事物超时。

  1. 首先第一想到的是是不是并发登录,导致长事物了。因为登录的时候会修改修改用户登录时间

​编辑

直接 100 线程开测。但是服务器容器日志中并没有发现事物死锁问题。

经过排查mysql 连接工具看到一条业务 sql很是奇怪

String sql="replace
            into
                test_user (
            id,
                name,
                age,
                `password`,
                create_user,
                create_date,
                update_user,
                update_date
            )
            select
                d.id,
                d.name,
                d.age,
                d.tenant_id,
                u1.name,
                d.create_date,
                u2.name,
                d.update_date
            from
                edo_user d,
                rbac_user u1,
                rbac_user u2
            where
                u1.id = d.create_user
                and u2.id = d.update_user";

replace into

————-chat GPT ——-

是的,REPLACE INTO 语句在 MySQL 中确实可能导致死锁,尤其是在高并发环境下。以下是一些导致死锁的常见原因和解决方案:

死锁原因 唯一键冲突:REPLACE INTO 操作会尝试插入新记录,如果发现唯一键冲突,则会删除旧记录并插入新记录。这一过程中涉及到多个锁操作,可能会导致死锁 。 锁的类型和顺序:REPLACE INTO 操作需要获取多个锁,包括行锁、间隙锁和插入意向锁。在高并发环境下,不同事务获取锁的顺序不同,可能导致死锁 。 锁等待:当一个事务持有锁并等待另一个事务释放锁,而另一个事务也在等待第一个事务释放锁时,就会发生死锁 。 解决方案 使用 INSERT … ON DUPLICATE KEY UPDATE:这种方式在处理唯一键冲突时,只会更新现有记录,而不会删除再插入,减少了锁操作的复杂性 。

sql


INSERT INTO table_name (column1, column2)
VALUES (value1, value2)
ON DUPLICATE KEY UPDATE column2 = value2;