黄东旭解析 TiDB 的核心优势
718
2023-11-24
在pump 排查问题的时候(6.1.5版本),偶然发现一条错误日志, [ERROR] [server.go:635]drainers checkpoint is older than pump gc ts, some binlogs are purged,draine=drainerip:port,gc ts=2023-07-10 06:05,drainer checkpoint=2023-07-09 11:05(为了便于表达,直接将相应的ts转为了相应的时间) 第一眼看到这条日志的时候,正如日志所描述的以为drainer 要从pump 读取的数据已经被pump给gc了,但是详细看了下这条日志的上下文及结合代码的逻辑,发现drainer 要从pump 读取的数据 其实没有被pump gc了,那为什么会显示出这样的日志呢?
从日志来看,是在说drainer 要从pump 里面读取07-09 11:05之后的数据(下文简称drainer request ts),但是gc ts是07-10 06:05,看起来drainer request ts 小于gc ts,drainer 要从pump获取[07-09 11:05,07-10 06:05]这个区间的数据已经被pump gc给进行purge了,但是事实真的这样嘛?我翻了下pump 上下文的日志,通过grep -in request gc ts pump.log 可以看到最近一次pump的gc时间(pump 每小时gc一次),通过最近一次pump的gc的日志记录,可以看到pump当前的最大gc ts时间(当前时间-pump配置的gc参数)为07-09 10:05 ,也就是说07-09 10:05之前的数据被pump给gc了,但是drainer request ts 是2023-07-09 11:05,并不需要读取pump 07-09 10:05之前的数据,那么日志显示的drainers checkpoint is older than pump gc ts, some binlogs are purged.....,这条日志就打印的有问题了,并且这个日志还是ERROR 级别,本着好奇的态度去翻了下pump相关的代码
日志里面显示关于这部分逻辑的代码在pump/server.go:635行detectDrainerCheckPoints方法里面,下面是相关代码
if drainer.MaxCommitTS < gcTS { log.Error("drainers checkpoint is older than pump gc ts, some binlogs are purged", zap.String("drainer", drainer.NodeID), zap.Int64("gc ts", gcTS), zap.Int64("drainer checkpoint", drainer.MaxCommitTS), ) // will add test when binlog have failpoint detectedDrainerBinlogPurged.WithLabelValues(drainer.NodeID).Inc() }这个代码的逻辑还是比较简单的,如果drainer.MaxCommitTS < gcTS,就会打印错误日志"drainers checkpoint is older than pump gc ts, some binlogs are purged"....,drainer.MaxCommitTS 这个变量的值其实就是drainer 同步pump数据到哪个tso了(就是drainer savepoint里面的commitTS),那么关键是gcTS 变量是怎么求出来的,gcTSs是该方法的传入的参数,而detectDrainerCheckPoints方法 被pump/server.go:546行被调用
gcTS := s.storage.GetGCTS() alertGCMS := earlyAlertGC.Nanoseconds() / 1000 / 1000 alertGCTS := gcTS + int64(storage.EncodeTSO(alertGCMS)) log.Info("use gc ts to detect drainer checkpoint", zap.Int64("gc ts", gcTS)) // detect whether the binlog before drainers checkpoint had been purged s.detectDrainerCheckPoints(s.ctx, alertGCTS)通过上面代码可以看到gcTS是通过alertGCTS这个参数变量传递进来的,alertGCTS的取值=gcTS +alertGCMS,gcTS的值是通过 s.storage.GetGCTS()该方法的来的,该方法返回的gcTS其实就是pump 最近一次gc的gc tso(当前时间-pump配置的gc参数,也就是说pump 已经把这个时间点以前的数据给gc了),这就是在日志里面看到的request gc ts的时间是07-09 10:05
[INFO] [server.go:592] ["send gc request to storage"] ["request gc ts"=07-09 10:05]
那么alertGCMS的值是多少呢?其实alertGCMS在代码里面写死了
earlyAlertGC = 20 * time.Hour //pump/server.go:56那也就是说在detectDrainerCheckPoints方法里面判断drainer请求的数据是否被pump给gc的时候,是和gcTS这个变量做比较,但是这个gcTS 是实际的 gcTS +20h,所以才会有上述的日志报错说drainer 请求的pump日志被purged,
了。
代码看到这里,其实我们知道这个报错的根本的原因就找到了,但是为什么要把gcTS+20h才去做判断呢?对于这一点,笔者提出猜想,这可能是一个历史遗留问题,可能是想让提醒用户drainer 归档binlog太慢了,需要读取的pump 数据有被gc的风险,一般出现这个错误日志的时候,drainer那边归档binlog的速度其实是比较慢的,在这种情况下,才会出现这个告警,但是具体为什么这么设计可能只有开发同学才知道了,在这里我们就不做过多的研究了,但是这条日志笔者还是认为不应该是ERROR级别,并且输出信息也应该改进下,不然容易导致用户的误解。
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。