关于美团:MySQL自治平台建设的内核原理及实践上

本文整顿自主题分享《美团数据库自治服务平台建设》,系超大规模数据库集群保稳系列的第四篇文章。本文作者在演讲后依据同学们的反馈,补充了很多技术细节,跟演讲(视频)相比,内容更加丰盛。文章分成上、下两篇,上篇将介绍数据库的异样发现跟诊断方面的内容,下篇将介绍内核可观测性建设、全量SQL、异样解决以及索引优化倡议与SQL治理方面的内容。心愿可能对大家有所帮忙或启发。

1 背景&指标

MySQL的故障与SQL的性能,是DBA跟研发同学每天都须要关注的两个重要问题,它们间接影响着数据库跟业务应用程序的稳定性。而当故障或者SQL性能问题产生时,如何疾速发现、剖析以及解决这些问题,使得数据库或者业务零碎疾速复原,是一项比拟大的挑战。

针对此问题,美团数据库自治平台通过多轮的迭代建设,在多个场景下曾经实现了异样的发现、剖析以及解决的端到端能力。本文将跟大家分享一下咱们平台建设的心路历程,同时提供一些教训、教训供同行参考,心愿可能起到“抛砖引玉”的作用。本文次要介绍以下主题:

  • 异样发现:基于数理统计形式的动静阀值策略,来发现数据库系统的指标异样。
  • 故障剖析:丰盛欠缺数据库要害信息,来做准确的数据库异样根因剖析;深刻开掘内核价值,来解决根因诊断方面的疑难杂症。
  • 故障解决:根据异样根因剖析的不同后果,通过自助化或自动化的形式来进行故障的复原解决。
  • 内核可观测性建设:如何跟数据库内核团队单干,从内核的角度来剖析SQL性能问题,通过内核团队大量的内核代码革新,力求将数据库的可观测性跟诊断做到极致。
  • 单SQL优化倡议:通过革新MySQL存储引擎,同时联合查问优化来打造基于Cost模式的索引优化倡议。
  • 基于workload索引优化倡议:基于整个DB或者实例的Workload策略的索引优化倡议,为实现数据库的索引自保护提供前置条件。
  • 基于SQL生命周期的治理:实现从SQL上线前、执行过程中、执行结束后几个环节,以期实现端到端的慢SQL治理。

2 平台演进策略

美团数据库自治平台从下到上总体分为四层,别离为接口与展现、平台性能层,计算与存储、数据采集层,平台的总体架构以及每一层的作用如下:

  • 数据库采集层:要进行数据库的诊断与剖析,须要依附要害的指标以及SQL文本数据,以后在每个数据库实例上部署一个数据采集程序(rds-agent)对立负责采集、上报要害数值指标以及SQL文本数据。
  • 数据计算与存储层:数据采集层上报上来的数据,依靠Kafka、Flink&Spark作为数据缓冲,对要害组件进行相干的数据处理,如SQL解析、SQL模版化、数据聚合等操作,再把解决的后果存入ES、Blade(美团自研的分布式数据库)、Hive等分布式数据库或者大数据平台,提供给下层的平台性能层应用。
  • 平台性能层:此层是整个零碎最为重要的局部,因为平台同时服务于DBA运维团队及研发团队,所以平台的建设分成了两条路:1)次要面向DBA用户,依照可观测性建设、异样发现、故障根因剖析、故障解决几个阶段来进行建设;2)次要面向研发同学,依照SQL优化倡议、危险SQL的发现、剖析与SQL治理等跟SQL相干的几个阶段来建设。当然,两者并没有严格界线,这些性能所有的用户都能够同时应用。
  • 接口与展现:平台性能层提供的外围性能会通过Portal来展现,同时为了让平台提供的性能更好地集成在用户本人的零碎中,咱们也通过OpenAPI的形式对外提供服务。

3 异样发现

数据库产生异样时须要尽早地发现,能力避免异样一提高放大,防止造成真正的故障。异样发现的次要形式是对数据库或者OS的要害数值指标进行监控,相干指标包含seconds_behind_master、slow_queries、thread_running、system load、Threads_connected等等,也能够是业务端研发关注的要害指标,如“应用程序拜访数据库的报错数量”、“SQL执行均匀耗时”等指标来进行监控。如果这些指标短时间内产生比拟大的稳定,那么数据库很可能呈现了一些异样,这就须要及时进行解决。

这些异样如何能力被发现呢?业界个别有基于动态阀值以及动静阀值的两种异样发现策略。前者很简略,如依据专家教训,人工设定seconds_behind_master或者Threads_connected的告警阀值,超过阀值就认为产生了异样。此形式尽管简略易用,但OLTP、OLAP等不同的业务场景,对于雷同指标的敏感度是不一样的,如果所有场景都应用对立的动态阀值来做异样发现,难免会有很多误告。而如果每个场景都去手工去调整,既不灵便,老本又太高,解决方案是基于不同场景的历史时序数据,应用数理统计的形式来别离建模,通过拟合出各自场景的模型来作为异样发现的策略。

3.1 数据分布法则与算法抉择

基于数理统计办法的异样发现,须要依据具体的场景应用特定的模型。一般来说,模型的抉择跟时序数据的散布状态有很大的关系,时序数据的散布并不总是都像正态分布一样都是对称的,而是有些是左偏的,有些是右偏的,当然也有对称散布的。下图就展现典型的三种不同的时序数据分布状态。

针对下面的三种不同时序数据的散布状态,以及每种异样检测算法本身的个性,咱们别离采纳不同的异样检测算法。

对于低偏态高对称散布抉择“相对中位差(MAD)”,中等偏态散布抉择“箱形图(Boxplot)”,高偏态散布抉择“极值实践(EVT)”。没有抉择3Sigma的次要起因是:它对异样容忍度较低(建模的时候,如果有乐音等异样点也不会对模型的状态产生很大的影响,则阐明异样容忍度很高),而相对中位差(MAD)从实践上而言具备更好的异样容忍度,所以在数据出现高对称散布时,通过相对中位差代替3Sigma来进行检测。

3.2 模型抉择

数据分布跟算法实用场景的剖析之后,对外部的时序数据进行查看,发现数据的法则次要出现漂移、周期和安稳三种状态,对样本先进行时序的漂移(如果检测存在漂移的场景,则须要依据检测取得的漂移点t来切割输出时序,应用漂移点后的时序样本作为后续建模流程的输出)。

之后同时进行平稳性剖析(如果输出时序S满足平稳性测验,则间接通过箱形图或相对中位差的形式来进行建模)以及周期剖析(存在周期性的状况下,将周期跨度记为T,将输出时序S依据跨度T进行切割,针对各个工夫索引j∈{0,1,⋯,T−1} 所组成的数据桶进行建模流程。不存在周期性的状况下,针对全副输出时序S作为数据桶进行建模流程),再对时序数据分布个性进行偏度的计算,最初再依据不同的偏度个性抉择不同的算法模型,具体如下:

在算法确定之后,先在离线环境针对不同的场景应用历史指标来训练模型,模型训练结束之后会存入数据库,在生产环境运行过程中,对于不同场景下的数值指标依据其个性来加载不同的模型,并且联合Flink实时计算框架来实时的发现指标的异样并进行告警。

4 异样诊断

发现指标异样后,须要疾速的给出异样的根因,咱们能够依据具体的根因来抉择不同的解决策略,而后进行主动或者手动的复原工作。根因剖析能够基于专家教训,也能够严格地依照内核代码的逻辑来进行剖析。

本文重点讲述后者,强调如何应用“内核思维”来解决专家教训很难或者无奈解决的诊断问题。本文将列举“内核代码路径分析”、”内核日志剖析”、“内核性能加强“、“内核Core Dump剖析”以及“内核埋点”等几种不同的范式,来阐明数据库根因诊断的思路。

4.1 主从提早(内核代码路径分析)

这里先介绍“内核代码路径分析”这个形式来诊断根因。对于数据一致性要求比拟高的应用程序,seconds_behind_master是一个非常重要的指标,如果其值过大就须要诊断其根因,避免应用程序读取到不统一的数据。依据专家教训,其值过大可能由“QPS突增”、“大事务”、“大表DDL”、“锁阻塞”、“表短少主键或者惟一健”、“低效执行打算”、“硬件资源有余”等因数造成,把这些专家经验总结成规定列表,当异样产生时一一迭代去验证是不是合乎某个规定,据此来诊断根因,然而此形式存在如下两大问题:

  1. 无奈枚举所有根因:教训因为其固有的局限性不可能思考到所有的故障场景,如何残缺的给出造成seconds_behind_master值异样的所有规定是一个挑战;另外,如果须要对一个全新的指标进行诊断,而在没有任何的专家教训状况下,如何能疾速地整顿出残缺的规定列表?
  2. 不足对根因的深层次了解:“QPS突增”、“大事务”、“大表DDL”、“锁阻塞”、“低效执行打算”、“硬件资源有余”等因素会造成seconds_behind_master指标值的异样,然而为什么这些因数会造成指标值的异样呢?如果不从内核源码角度来理解这些因素跟seconds_behind_master之间的逻辑计算关系,那么是无奈理解真正起因的。

4.1.1 内核代码路径分析

针对下面两个问题,具体策略是间接看seconds_behind_master这个变量在内核层面是如何计算的,只有这样能力残缺的枚举出所有影响seconds_behind_master值计算的因数。

从源码角度看,seconds_behind_master的值由①time(0)、②mi->rli->last_master_timestamp和③mi->clock_diff_with_master这三个变量来决定(代码层面seconds_behind_master的计算逻辑是:seconds_behind_master=((long)(time(0) – mi->rli->last_master_timestamp)- mi->clock_diff_with_master),其中time(0)是零碎以后工夫(用秒示意),clock_diff_with_master这个值的计算很简单、又很要害,会放到下一节具体进行阐明。

而针对mi->clock_diff_with_master的计算,这个变量从源码层面看就是主、从实例之间的时间差;依据以后的信息就可以看进去,从库的以后工夫以及主从库之间的时间差都会影响seconds_behind_master值的计算。seconds_behind_master的计算和事务在主从库执行的状况如下:

last_master_timestamp计算逻辑

从下面剖析能够晓得,last_master_timestamp值是影响seconds_behind_master值计算的要害变量,所以很有必要从源码角度剖析影响last_master_timestamp值的因数有哪些(从而间接获取了影响seconds_behind_master值的因素)。

last_master_timestamp的值来自于一个叫rli->gaq->head_queue()的成员变量new_ts(此处的rli->gaq->head_queue()是指代某个最新的曾经实现replay的事务对应的event group,event group是指一个事务在binlog文件里生成一组event来示意某个事务,这个event group里的event从主库传输到从库后进行replay操作来还原主库的事务)。new_ts值来源于rli->gaq->head_queue())->ts,而rli->gaq->head_queue())->ts的值是通过ptr_group->ts= common_header->when.tv_sec + (time_t) exec_time计算获取的。

再看一下when.tv_sec跟exec_time的含意,前者指代SQL在主库上的SQL执行的开始工夫,后者指代SQL在主库上的“执行时长”,“执行时长”又跟“锁阻塞”、“低效执行打算”、“硬件资源有余”等因素非亲非故。

值得注意的是,后面提到的rli->gaq->head_queue())->ts的计算跟slave_checkpoint_period以及sql_delay两个变量也有关系,依照这个思路层层迭代上来找出所有影响seconds_behind_master值的因素,这些因素都是潜在的主从提早异样的本源,这样也解决了后面说的“无奈枚举所有根因”跟“不足对根因的深层次了解”两大问题。

为了便于了解上诉的逻辑,放出要害的源代码:获取last_master_timestamp值的起源rli->gaq->head_queue()的成员变量new_ts。

bool mts_checkpoint_routine(Relay_log_info *rli, ulonglong period,
                            bool force, bool need_data_lock)
{
 do
  { 
    cnt= rli->gaq->move_queue_head(&rli->workers);
  } 
 .......................
  ts= rli->gaq->empty()
    ? 0
    : reinterpret_cast<Slave_job_group*>(rli->gaq->head_queue())->ts; //其中的ts来自上面的get_slave_worker函数;
  rli->reset_notified_checkpoint(cnt, ts, need_data_lock, true);
  //  社区版本的代码 rli->reset_notified_checkpoint(cnt, rli->gaq->lwm.ts, need_data_lock);
  /* end-of "Coordinator::"commit_positions" */
 ......................
}

获取Master实例上执行的SQL的开始跟执行时长信息tv_sec跟exec_time。

Slave_worker *Log_event::get_slave_worker(Relay_log_info *rli)
{
if (ends_group() || (!rli->curr_group_seen_begin && (get_type_code() == binary_log::QUERY_EVENT || !rli->curr_group_seen_gtid)))
  {
  ..............
    ptr_group->checkpoint_seqno= rli->checkpoint_seqno;
    ptr_group->ts= common_header->when.tv_sec + (time_t) exec_time; // Seconds_behind_master related
    rli->checkpoint_seqno++;
  }
} 

根因层叠图

如果进一步剖析内核代码,能够发现影响seconds_behind_master变量计算的因素还有很多,然而找出这些因素的思路是雷同的。这个思路的益处是:无论之前有没有相干专家教训,实践上这种剖析形式都能尽可能地枚举出所有的根因。

除了seconds_behind_master,其余的像thread_running、Threads_connected,slow_queries等指标异样的剖析也都能够套用这种思路。上面为依照上述思路整理出来的影响seconds_behind_master值的局部因素的层次结构图:

4.1.2 流程剖析

把影响seconds_behind_master值的相干因素确认后,能够画一个流程图把这些因素都体现在流程图中的具体位置。这样既能比拟形象地了解影响seconds_behind_master的因素在整个主从复制流程中的所处的地位,又便于对整体规定进行查漏补缺。

上面咱们应用一个具体的例子,来阐明一下下面剖析的因素是如何影响seconds_behind_master的。从下图能够看出在执行SQL的过程中影响seconds_behind_master计算的两个变量thd->start_time跟exec_time的计算在master实例。假如start_time的值为2023-07-03 00:00:00,SQL执行了60秒,所以exec_time为60,2023-07-03 00:01:00,SQL在主库上执行结束,在从库上replay这个SQL,能够看到seconds_behind_master值会从0开始并且逐步减少60秒,而后再返回0。

具体起因是:假如咱们疏忽binlog日志的传输工夫,那么从库开始执行replay这个SQL的开始工夫也是2023-07-03 00:01:00,所以依据seconds_behind_master=((long)(time(0) – mi->rli->last_master_timestamp)- mi->clock_diff_with_master)=2023-07-03 00:01:00 – 2023-07-03 00:00:00-60s,后果就是0,而后SQL的执行工夫是60秒,并且(long)(time(0)(以后工夫)的工夫一秒一秒的在减少,所以seconds_behind_master值会从0开始逐步减少至60秒。

再看一下其余的因数,协调器(Coordinator)会把Group放入一个叫做GAP Group的队列中,Coordinator会以slave_checkpoint_period值为周期来扫描GAP Group中的元素并且更新rli->gaq->head_queue())->ts值,所以果slave_checkpoint_period的值被设置的很大,那么rli->gaq->head_queue())->ts的值因为没有及时更新而变得比拟旧,从而引起seconds_behind_master值变大。

另外,每个Worker读取本人队列的Group元素,进行repaly操作,须要留神的是sql_delay这个变量,如果以后工夫还没有达到sql_delay规定的工夫(假如sql_delay被设置为100秒,那么SQL对应的binlog日志达到从库后须要期待100秒再执行),那么worker就不会进行repaly工作,这间接导致影响计算seconds_behind_master变量thd->start_time值比失常状况下小了100秒,所以当worker进行replay的时候,seconds_behind_master的值就会相应的减少100秒。

4.1.3 产品展现

上面的产品展现了因为流量突增跟MDL锁造成的主从提早的诊断剖析报告的产品页面。咱们能够看到,流量突增的具体SQL以及MDL锁的持有者,不便用户进行限流或者Kill掉阻塞者SQL。

4.2 大事务诊断剖析(内核性能加强)

大事务的存在,对整个数据库系统的稳定性与总体SQL的性能都会产生很大的挑战,如大事务长时间持有某个锁会造成大面积阻塞,或者更改过多的行数造成整个实例硬件资源的有余。咱们须要及时发现这些场景,并且将其信息发送给用户治理,但在实际过程中,往往面临如下的两大挑战:

第一个挑战:无奈失去大事务所蕴含的残缺的SQL列表,造成用户不分明大事务的全貌是什么,用户也就无奈辨认须要优化的大事务。

  • 解决方案:每个事务来MySQL会在内核层面生成一个惟一的事务ID:trx_id,如果事务蕴含的每条SQL,都给其附加一个事务ID trx_id字段,并且把这些SQL连同trx_id一起输入(通过全量SQL输入),问题就能够解决;不过这里还有一个挑战,这个事务ID到底是何时产生的呢?如何大家相熟内核内部事务的执行过程,就会晓得事务ID的只有在事务批改数据的时候才会通过trx_assign_id_for_rw这个办法被获取,这意味着就上面这个图上展现的事务而言,是无奈获取SQL4之前执行的读SQL语句列表,所以获取到的事务的SQL列表还是完好的,那么如何获取到残缺的SQL列表呢?解决方案也很简略,能够把事务ID的生成逻辑提前到在事务刚开始执行的时候生成就能够了。

第二个挑战:大事务的耗时组成不明确。数据库规定执行时长大于某个阀值的事务被定义为大事务,然而不分明耗时到底是SQL自身的执行工夫还是SQL执行之外的耗时,SQL执行之外的耗时可能是在执行高低两个SQL之间,业务端在解决一些跟数据库无关的业务逻辑,也可能是网络提早造成的。

  • 解决方案:上述问题能够通过在数据库内核内对SQL执行开始时、完结时别离埋点工夫戳来解决,这样整个大事务执行总工夫中有多少工夫是在执行SQL,有多少工夫是在Sleep就高深莫测;当然,这一块还能够做的更加的粗疏,比方两条SQL之间的Sleep工夫到底是网络提早还是应用程序端的提早等,能够进一步细分大事务造成的起因到底是在MySQL端、网络端还是用户本人的应用程序造成的期待;对于计算网络端的提早计算,能够参考MySQL外部的mysql_socket_send_time跟vio_socket_io_wait_time这2个要害指标的实现思路,下图是一个大事务的SQL列表以及耗时组成列表。

4.2.1 产品展现

内核团队通过内核革新,对事务中所蕴含的SQL都提供了trx_id后就能够依据trx_id把整个事务所有的SQL串起来。依据SQL执行的开始跟完结工夫,咱们也提供了所有SQL之间的Sleep工夫,胜利解决了下面的两个挑战,产品效果图如下:

4.3 MySQL Crash剖析(内核Core Dump剖析)

MySQL实例忽然Crash了怎么进行根因诊断?过程Crash的根因剖析,也是数据库故障中最难剖析的问题之一。本节提供一些思路尝试去剖析各种场景下的MySQL Crash的根因。

4.3.1 Crash的触发形式

在剖析Crash的根因之前,咱们能够先理解一下MySQL过程是如何被Crash的整个过程非常有必要。一般来说,触发Crash的起因分成两类:①MySQL过程本人触发了Crash(这里称之为MySQL他杀);②MySQL过程被OS杀死。

针对前者,比方MySQL发现某个要害数据产生了Data Corruption、磁盘空间有余、硬件谬误、期待内核锁工夫过长、MySQL 内核Bug等场景,都可能导致MySQL他杀。尤其是查看到MySQL内核里有些数据的状态不合乎预期时,是必要要让那个实例Crash也不能继续执行,否则可能会产生更加重大的数据不一致性问题;而后者,OS如果发现零碎内存严重不足或者空指针援用等状况,就会把包含MySQL在内相干的过程杀掉。

剖析一下MySQL本身触发Crash这个场景,在MySQL外部有很多中央通过ut_a(如果是ut_error的话,则间接触发Crash断言对程序的外部数据状态进行异样查看,如果发现数据状态不合乎预期,那么势必产生了Data Corruption,这个时候程序会调用ut_dbg_assertion_failed在过程Crash之前做一些要害信息(如thread id、产生Crash的文件名字跟code line等)的记录后,会持续调用abort()向过程发送SIGABRT信号量让过程Crash掉。

须要留神的是,从abort()的源码可知,这里调用了两次raise (SIGABRT),第一次调用raise (SIGABRT)触发处理函数handle_fatal_signal(此函数在MySQL实例初始化时通过sigaction的sa_handler注册)被调用,这个函数次要是打印一些重要的调试信息,便于做Core Dump剖析;第二次调用raise (SIGABRT)的目标,是为了让OS生成Core Dump文件(core Dump文件十分重要,因为所有引起MySQL Crash的现场信息都蕴含在Core Dump外面);如果是在MySQL他杀的状况下产生了Crash ,个别会在errorlog里会产生如下的一段跟Crash相干的现场信息,其中的“signal”、“触发Crash的线程堆栈”、“正在执行的SQL”等信息都是剖析Crash根因的要害信息。

下图为MySQL通过ut_a断言查看异样问题后再到OS触发过程Crash的整体流程图。总体来说,MySQL通过raise来发送SIGABRT信号到一个队列,OS内核解决这个队列的信号并调用MySQL的处理程序handle_fatal_signal来保留一些要害的现场信息。这里须要留神到的是,OS内核在__setup_rt_frame中执行“regs->ip = (unsigned long) ka->sa.sa_handler;”,这个步骤正是让MySQL的handle_fatal_signal办法被顺利的调用的起因。

4.3.2 依据Signal类型做根因剖析

剖析Crash根因的第一步就是看触发了什么类型的signal,常见类型有“signal 6”、“signal 7”、“signal 11”几种类型,当晓得了Signal类型后就有一个根因剖析的大方向。依据教训,咱们将常见的signal类型以及可能引起的起因大抵如下图所示,上面对于常见的signal类型以及引起的根因做一个简略的剖析。

(1) 如果是signal 6,个别是实例的磁盘空间有余或者磁盘只读,MySQL的数据产生了data corruption,内核层面latch锁的长时间的锁期待造成。不过这里的data corruption、长时间的锁期待可能是硬盘损坏或者MySQL的Bug造成的,判断逻辑如下:

  1. 磁盘空间有余或者磁盘只读

    • 磁盘写数据时,如果磁盘没有残余空间或者数据库被设置为read only就会造成实例的Crash,日志中有“Either disk is full or file system is read only while opening the binlog”的字样。
  2. data corruption

    • MySQL在运行过程中如果断言(比方这里ut_a(table != NULL)返回false,很可能是数据产生了corruption并且MySQL就会自行Crash掉;产生data corruption时个别在MySQL的error log中有“Database page corruption on disk or a failed file read of tablespace”的字样,所以查看日志来判断否有硬盘故障问题,如果没有硬件故障信息,则可能是MySQL Bug造成的data corruption,具体分析看上面 “MySQL Bug”那局部。
  3. 长时间无奈获取Latch锁

    • 如果MySQL长时间没有方法获取到Latch锁,那么MySQL认为零碎可能是Hang住了也会引起实例的Crash,并且日志中打印“We intentionally crash the server because it appears to be hung”字样,个别是硬件故障造成的性能问题或者MySQL本身的设计缺点造成的性能问题造成的,这次场景根因剖析比拟有挑战。
  4. MySQL Bug

    • 如果不属于下面任何一种状况,那么有可能是MySQL本身的Bug造成的Crash,比方MySQL对一些SQL解析或者执行时会产生Crash;这种场景个别先看一下Crash产生时正在执行的SQL是什么,这个SQL可能存在于Crash日志中(这个Crash日志中有个例子),能够先把SQL提取进去再次执行查看是否复现问题;如果在Crash日志中看不到SQL语句,就须要从core dump文件中提取SQL了,提取形式是MySQL每个链接对应的THD的成员变量m_query_string就蕴含了SQL文本,只须要关上Core Dump文件切换到某个蕴含THD实例的办法内,通过命令“p this->thd->m_query_string.str ”来打印,这里有个例子。
    • 再举个MySQL的Bug造成data corruption的例子,从Crash日志里“InnoDB: Assertion failure in thread 139605476095744 in file rem0rec.cc line 578”看出,从rec_get_offsets_func函数中触发ut_error而导致的Crash,之所以触发这个Crash是因为rec_get_offsets_func中的rec_get_status(rec)获取到的MySQL的记录类型不合乎预期(因为记录类型只有固定的REC_STATUS_ORDINARY、REC_STATUS_NODE_PTR,REC_STATUS_INFIMUM,REC_STATUS_SUPREMUM这4种类型),如果内核发现一个记录类型不属于这4种类型的任何一种,那么就是产生了data corruption,所以必须要把本人Crash掉。为了验证方才的论断,看一下Crash产生时的rec的类型是什么,从源码可知rec的类型是通过rec_get_status获取,并且其通过调用的rec_get_bit_field_1跟mach_read_from_1两个函数能够晓得rec的类型其实就是rec这个指针往前三个byte(通过#define REC_NEW_STATUS_MASK 0x7UL可知)代表的值。
    • 通过gdb加载core dump文件后,切换到抛出exception的线程,因为异样是在rec_get_offsets_func里抛出的,切换到rec_get_offsets_func对应的frame 7来验证rec的类型,看到rec的指针地址为0x7f14b7f5685d(相干剖析数据能够看此链接)。后面说过,rec的类型值在rec指针往前三个byte里,也就是指针0x7f14b7f5685a(0x7f14b7f5685d-3)那个地位的值,发现是0x1f,执行与计算(11111(1f)&00111(0x7UL)=00111=7 )失去的类型是7,而记录类型的范畴是(0~3),很显著这个指针指向的记录类型值信息产生了data corruption(剖析过程查看此链接),这里做了一个rec的类型在失常状况下跟本例异常情况下的类型值计算的比照表,发现失常状况下,rec的类型值就应该是3。
  • 这里有个重要问题是,为什么rec的类型是有效的呢?很可能是MySQL搜寻满足条件的记录的时候,rec指向的记录很可能被page_cleaner在后盾被清理掉了,所以rec指针指向的记录就是有效了。官网有个bugfix,解决方案就是把prev_rec设置为NULL(这里的prev_rec是persistent cursor指向的记录,这里说一下persistent cursor,它是MySQL从InnoDB 层取得记录后进入SQL层前在B-tree上的cursor会被临时存储到row_prebuilt_t::pcur中,当再次从InnoDB层拿数据时,如果对应的buf_block_t没有产生批改,则能够持续沿用之前存储的cursor,否则须要从新定位,如果没有persistent cursor则每次都须要从新定位则对性能有影响),这样prev_rec != NULL这个条件不满足,也就没有机会进入rec_get_offsets_g_func里去查看rec的类型值而引发Crash了。

(2) 如果为signal 7,那么大概率是内存硬件谬误,并且日志里个别有“mce: [Hardware Error]: Machine check events logged , mce: Uncorrected hardware memory error in user-access at xxx MCE xxx: Killing mysqld:xxx due to hardware memory corruption”等字样。

(3) 如果为signal 9,示意这个过程被Kill命令杀掉了。

(4) 如果为signal 11,示意是由MySQL的Bug造成的,这类问题较难剖析特地是MySQL Crash现场(通过core dump打印进去的堆栈信息)往往还不是第一现场,因为篇幅关系具体的例子剖析不在本文中给出,然而剖析的思路跟下面的“MySQL Bug”是相似的。

5 本文作者

裕锋,来自美团根底研发平台-根底技术部,负责美团数据库自治平台的相干工作。

6 参考

  • https://github.com/shenyufengdb/sql
  • https://github.com/percona/percona-server/blob/release-5.7.41-44
  • An Efficient, Cost-Driven Index Selection Tool for Microsoft SQL Server
  • plan-stitch-harnessing-the-best-of-many-plans-2
  • Random Sampling for Histogram Construction: How Much is Enough?
  • AutoAdmin “what-if” index analysis utility
  • What is a Self-Driving Database Management System?
  • https://www.microsoft.com/en-us/research/publication/self-tuning-database-systems-a-decade-of-progress/
  • Automatic Database Management System Tuning Through Large-scale Machine Learning
  • Query-based Workload Forecasting for Self-Driving Database Management Systems
  • The TSA Method
  • https://blog.langchain.dev/langchain-chat/
  • https://github.com/hwchase17/langchain
  • REAC T: SYNERGIZING REASONING AND ACTING IN LANGUAGE MODELS
  • Evaluating the Text-to-SQL Capabilities of Large Language Models
  • SQL-PALM: IMPROVED LARGE LANGUAGE MODEL ADAPTATION FOR TEXT-TO-SQL

浏览更多

| 在美团公众号菜单栏对话框回复【2022年货】、【2021年货】、【2020年货】、【2019年货】、【2018年货】、【2017年货】等关键词,可查看美团技术团队历年技术文章合集。

| 本文系美团技术团队出品,著作权归属美团。欢送出于分享和交换等非商业目标转载或应用本文内容,敬请注明“内容转载自美团技术团队”。本文未经许可,不得进行商业性转载或者应用。任何商用行为,请发送邮件至tech@meituan.com申请受权。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理