【Spring错误笔记】spring.jpa.hibernate.ddl-auto=update造成删除索引的线上事故

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

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

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值