spring.jpa.hibernate.ddl-auto=update造成删除索引的线上事故
- 事故背景
- 技术习惯
- 业务背景
- 事故回放
- 事故起因
- 事故起因
- 为什么Hibernate会执行删除索引再重建索引的操作?
- 事故结论
- 事故原因
- 事故结论
事故背景
技术习惯
- 公司技术习惯,无论是线上环境,还是预线上,测试环境,都习惯使用
Spring Data Jpa作为ORM工具 - 为了快速迭代,通常对于表的更新的DDL语句,都依赖JPA的自动更新机制,包括线上环境,即使用
spring.jpa.hibernate.ddl-auto=update配置
业务背景
- 重构项目,需要迁移数据,进行合库
- 重构项目的部分接口 QPS 峰值为5k级别 ,日查询流量上亿
- 重构项目涉及数据库,多个单表数据达百万,部分单表数据为千万级
- 区别于旧服务,新建一个新的服务,迁移接口,沿用旧数据库
事故回放
第一波
- 重构服务,新服务准备0流量上线,线上环境配置为
spring.jpa.hibernate.ddl-auto=update,数据库实体映射关系未修改 - 服务上线之后,旧服务高QPS接口出现抖动,接口可用率下滑,延迟攀升,出现服务告警。
- 简单查询后,发现是数据库使用率超百分百, 正常情况下CPU使用率为百分之10左右
- 相关人员排查问题,没有发现具体原因,后续没有发现原因,一段时间后,服务可用率自行恢复
- 当时没有想到跟
ddl-auto=update有关系, 因为实体映射关系没有改动,且新服务没有流量打入,理论上不会有什么关系,所以并没有跟新服务上线联想在一起
第二波
- 一段时间后,新服务修改代码后重新上线,服务再次告警, 数据库使用率再次百分百, 旧服务线上接口接近0可用率
- 查询
MySQL processlist, 发现在千万级的表上有drop/creator index的DDL语句操作 - 因为可用率已为0, 慌乱之中,只好kill掉processlist队列中阻塞的操作 (其中包括一个creator index操作 , 当时并没在意)
- 然而数据库使用率依然跑满,processlist充满了大量的select操作。排查一段时间后,怀疑有人drop了索引,导致千万数据的表的查询语句阻塞在队列中
- 宕机修复,造成线上服务停机十来分钟
事故解决
- 停止线上服务读写请求
- 删除唯一失效期间,插入的重复脏数据
- 重新生成索引
- 修改auto-ddl策略为none
- 重新启动线上服务,可用率恢复
事故起因
初步原因
初步原因排查结果
- 经过事故排查,是有人drop掉了某张千万级数据的表索引, 而造成了服务可用率下降,延迟攀升。同时在之后的修复过程中,因为kill掉了数据库create索引的操作,造成索引没有恢复,大量读请求没有走索引查询,造成队列阻塞
- 经过事故定位,发现drop索引的操作是由新服务发出了, 服务启动时,
Hibernate执行了drop索引再create索引两条DDL操作。同时新服务是集群部署,会执行多次ddl-auto操作, 重复的大表DDL操作,加重了阻塞程度 - 在Hibernate执行drop索引和create索引的间隙,旧服务还有大量的写请求进入相关数据表,在该unique索引失效期间,插入了重复数据,也导致了后续create表语句失效。unique索引再建失败
综上,初步原因是
- 重复大表DDL语句阻塞SQL队列,同时索引失效,大量读请求透过缓存层打到数据库,加重了SQL队列的阻塞
为什么Hibernate会执行删除索引再重建索引的操作?
(一) 为什么Hibernate为删除索引 ?
最有可能相关的配置就是spring.jpa.hibernate.ddl-auto=update , 但是按照理解,update配置不同于create, create-drop 等配置,是不会删除数据库已有的关系的。
- none
不配置- validate
加载 Hibernate 时,验证创建数据库表结构- create
每次加载 Hibernate,重新创建数据库表结构- create-drop
加载 Hibernate 时创建,退出是删除表结构- update
加载 Hibernate 时自动更新数据库结构
总之,我的简单理解如下
- 实体没有,数据库有,不修改
- 实体有,数据库没有,新增更新
总之我查阅了大量资料,也没有update配置删除索引的情况 (反正我是没查到,包括外网,如果有相关资料请告诉我,同时对自己的检索能力进行检讨),只有漫天的劝告,最好不要在线上环境使用spring.jpa.hibernate.ddl-auto配置
(二) 可能的Hibernate删除索引的原因 ?
- 服务上线时的配置写错了,并不是
update update配置没有生效, 并使用其他的模式,比如create等- 因为xxx异常导致执行了Herbinate其他底层潜在的逻辑, 或者说是触发了Herbinate的bug
原因嘛,我们要一个一个排查, 首先第一个,我经过重复检查,发现并不是这个问题。那看看是不是update配置没有生效或者被其他配置覆盖了。
所以我看了下Hiberna

探讨了在使用spring.jpa.hibernate.ddl-auto=update配置时,Hibernate执行删除和重建索引操作导致线上服务中断的事故。事故由数据库连接不稳定引起,导致Hibernate未能正确获取表元信息,执行了Drop索引操作。
最低0.47元/天 解锁文章
1558

被折叠的 条评论
为什么被折叠?



