一则 MySQL 从节点 hung 死问题分析

作者通过 MySQL 从节点的一个 hung 问题,对数据库连接、日志、innodb status 输出等分析,再结合源码、堆栈等最终明确为由于 redo日志配置不合理导致 hung 死问题根本原因。

作者:李锡超,一个爱笑的江苏苏商银行 数据库工程师,主要负责数据库日常运维、自动化建设、DMP 平台运维。擅长 MySQL、Python、Oracle,爱好骑行、研究技术。

爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

本文约 3000 字,预计阅读需要 10 分钟。

近期,发现一个 MySQL 从节点提示同步异常。执行 show replica status 都被挂起。

重要信息
MySQL 版本8.0.27
架构主从模式
binlog_transaction_dependency_trackingWRITESET
replica_parallel_workers16

初步分析

1.1 连接情况

当前连接的线程情况

当前连接中,运行的 16 个 worker 线程。其中:

  • 4 个状态为 Waiting for preceding transaction to commit
  • 11 个状态为 Applying batch of row changes
  • 1 个状态为 Executing event

线程等待时间 137272 秒(38 小时左右)。

同时看到执行的 show replica statusflush logs 命令都被挂起。

1.2 InnoDB Status 输出

根据 innodb status 输出结果:检查 ROW OPERATIONSFILE I/O,未见几个典型的问题,比如 innodb_thread_concurrency 配置不合理导致无法进入 InnoDB。

1.3 负载情况

检查系统负载,线程模式查看所有线程的状态。发现 MySQL 的 ib_log_checkpt 线程 CPU 使用率一直处于 100% 的状态。其它线程都处于空闲状态。

1.4 错误日志

检查错误日志,未见相关的错误日志记录。

1.5 慢查询

检查慢查询日志,未见相关的慢查询记录。

1.6 分析小结

我们知道当前版本存在一些已知缺陷,根据主从线程的状态,首先想到可能是由于多线程复制(MTS)的缺陷(Bug 103636 :MySQL 8.0 MTS 定时炸弹)导致。

但根据之前发现的案例,如果是该缺陷导致,在Bug触发了这么久,worker线程的状态应该都是处于 Waiting for preceding transaction to commit 状态,与此处现象不相符。

结合源码进一步分析

结合源码对 MTS 相关的逻辑进行梳理。关键逻辑如下:

// STEP-1: 启动时,根据配置参数,分配 commit_order_mngr
|-handle_slave_sql (./sql/rpl_replica.cc:6812)|-Commit_order_manager *commit_order_mngr = nullptr|-if (opt_replica_preserve_commit_order && !rli->is_parallel_exec() && rli->opt_replica_parallel_workers > 1)|-commit_order_mngr = new Commit_order_manager(rli->opt_replica_parallel_workers)|-rli->set_commit_order_manager(commit_order_mngr) // 设置 commit_order_mngr
// STEP-2: 执行event时,分配提交请求的序列号
|-handle_slave_sql (./sql/rpl_replica.cc:7076)|-exec_relay_log_event (./sql/rpl_replica.cc:4905)|-apply_event_and_update_pos (./sql/rpl_replica.cc:4388)|-Log_event::apply_event (./sql/log_event.cc:3307)|-Log_event::get_slave_worker (./sql/log_event.cc:2770)|-Mts_submode_logical_clock::get_least_occupied_worker (./sql/rpl_mta_submode.cc:976)|-Commit_order_manager::register_trx (./sql/rpl_replica_commit_order_manager.cc:67)|-this->m_workers[worker->id].m_stage = cs::apply::Commit_order_queue::enum_worker_stage::REGISTERED|-this->m_workers.push(worker->id)// 此节点的 worker 正在处理的提交请求的序列号,其取值为每次从 m_commit_sequence_generator(提交序列号计数器) 加 1 后所得// m_commit_sequence_generator 应该是全局的// 每次 start slave 之后会重新初始化|-this->m_workers[index].m_commit_sequence_nr->store(this->m_commit_sequence_generator->fetch_add(1))// 将worker id 加入到 m_commit_queue 的尾部|-this->m_commit_queue << index
|-...
|-handle_slave_worker (./sql/rpl_replica.cc:5891)|-slave_worker_exec_job_group (./sql/rpl_rli_pdb.cc:2549)|-Slave_worker::slave_worker_exec_event (./sql/rpl_rli_pdb.cc:1760)|-Xid_apply_log_event::do_apply_event_worker (./sql/log_event.cc:6179)|-Xid_log_event::do_commit (./sql/log_event.cc:6084)|-trans_commit (./sql/transaction.cc:246)|-ha_commit_trans (./sql/handler.cc:1765)|-MYSQL_BIN_LOG::commit (./sql/binlog.cc:8170)// STEP-3: 提交事务前,判断worker队列状态和位置,使用MDL锁,等待释放事务锁|-MYSQL_BIN_LOG::ordered_commit (./sql/binlog.cc:8749)// 在该函数会控制,只有 slave 的worker 线程由于持有commit_order_manager, 才会在此处进行 mngr->wait|-Commit_order_manager::wait (./sql/rpl_replica_commit_order_manager.cc:375)|-if (has_commit_order_manager(thd)): // 确认有 commit_order_manager 对象,该对象只要在开启并行符合和从库提交顺序一致后,才不为nullptr|-Commit_order_manager::wait (./sql/rpl_replica_commit_order_manager.cc:153)|-Commit_order_manager::wait_on_graph (./sql/rpl_replica_commit_order_manager.cc:71)|-this->m_workers[worker->id].m_stage = cs::apply::Commit_order_queue::enum_worker_stage::FINISHED_APPLYING// Worker is first in the queue|-if (this->m_workers.front() != worker->id) {}// Worker is NOT first in the queue|-if (this->m_workers.front() != worker->id):|-this->m_workers[worker->id].m_stage = cs::apply::Commit_order_queue::enum_worker_stage::REQUESTED_GRANT|-set_timespec(&abs_timeout, LONG_TIMEOUT);  // Wait for a year// 等待 MDL 锁|-auto wait_status = worker_thd->mdl_context.m_wait.timed_wait(worker_thd, &abs_timeout,...)// STEP-4: 提交事务后,自增获取下一个 worker、sequence_number,然后释放对应的锁。//         释放了之后,其它worker就会在STEP-3中获取到锁,否则就会一直在STEP-3 等待|-MYSQL_BIN_LOG::ordered_commit (./sql/binlog.cc:8763)|-MYSQL_BIN_LOG::change_stage (./sql/binlog.cc:8483)|-Commit_stage_manager::enroll_for (./sql/rpl_commit_stage_manager.cc:209)|-Commit_order_manager::finish_one (./sql/rpl_replica_commit_order_manager.cc:454)|-Commit_order_manager::finish_one (./sql/rpl_replica_commit_order_manager.cc:300)// 获取 commit_queue 的第一个 worker 线程: next_worker|-auto next_worker = this->m_workers.front()// 确认 next_worker 线程的状态,并比对 m_commit_sequence_nr。// 如果满足,则设置 mdl 锁状态为 GRANTED,即唤醒 next_worker 执行 ordered_commit 的后续操作|-if (this->m_workers[next_worker].m_stage in (FINISHED_APPLYING,REQUESTED_GRANT) and/* 对比 next_worker 的 m_commit_sequence_nr 与 next_seq_nr:如果 m_commit_sequence_nr == next_seq_nr, 则 返回 true , 然后将 m_commit_sequence_nr = SEQUENCE_NR_FROZEN(1)如果 m_commit_sequence_nr != next_seq_nr, 则 返回 false*/this->m_workers[next_worker].freeze_commit_sequence_nr(next_seq_nr))// 如果 if 条件满足, 设置 next_worker 为授权状态|-this->m_workers[next_worker].m_mdl_context->m_wait.set_status(MDL_wait::GRANTED)/* 对比 next_worker的 m_commit_sequence_nr 与 next_seq_nr如果 m_commit_sequence_nr == 1, 则 返回 true , 然后将 m_commit_sequence_nr = next_seq_nr如果 m_commit_sequence_nr != 1, 则 返回 false*/|-this->m_workers[next_worker].unfreeze_commit_sequence_nr(next_seq_nr)|-this->m_workers[this_worker].m_mdl_context->m_wait.reset_status()// 标记当前状态为终态(FINISHED)|-this->m_workers[this_worker].m_stage = cs::apply::Commit_order_queue::enum_worker_stage::FINISHED

为便于下文说明,对于 MTS 的 16 个 worker 线程,分类如下:

  • A 类: 4 个 worker 线程的状态为 Waiting for preceding transaction to commit
  • B 类: 11 个 worker 线程的状态为 Applying batch of row changes
  • C 类: 1 个 worker 线程的状态为 Executing event

论点 1

假设是由于 Bug 103636 导致该问题,那么 worker 线程应该会在执行提交操作的时候,在 ordered_commit 函数执行的开始位置,由于无法获取 MDL 锁而进行等待,通过 show processlist 查看 worker 线程的状态应该为 Waiting for preceding transaction to commit

而且通过 debug 验证发现,一旦该问题被触发,那么所有的 worker(即使只有一个 worker 在执行事务),都会进入到 ordered_commit 函数,然后由于无法获取 MDL 锁,都会在相同的位置进行等待。即应该是所有 worker 线程处于 Waiting for preceding transaction to commit 状态。

因此,初步判断该问题现象和 bug 103636 不相符合。

论点 2

从因果关系来看:如果是由于 bug 103636 作为问题的原因,结合论点 1 的分析,无法完全说明问题现象。

但相对的,可能是由于其它原因,导致以上 B 类和 C 类的 worker 线程无法顺利执行事务,从而导致 A 类 worker 线程在提交的时候,由于具有较小的 commit_sequence 事务的 worker 线程还未提交执行操作,因此进行等待,导致其线程状态为 Waiting for preceding transaction to commit。如此更能合理的解释当前数据库的状态。

那又是什么原因,导致 B 类、C 类线程无法提交?根据采集信息,发现1个奇怪的症状:

根据的 CPU 使用情况,问题时段的 ib_log_checkpt 一直是处于 100% 的 CPU 在运行。

根因分析

3.1 ib_log_checkpt 堆栈分析

根据 top 的线程 ID、堆栈以及 perf report 信息:

结合 log_checkpoint 的实现,我们看到该线程,主要是执行 dirty page flush 操作。具体包括:

buf_pool_get_oldest_modification_approx 实现分析,一直在循环遍历,找 dirty page 的最小 LSN。然后根据该 LSN 进行异步 IO 刷 dirty page 操作。

由于 buf_pool_get_oldest_modification_approx 一直在跑,猜测可能是异步 IO 慢。导致检查点无法完成,一直在寻找最小的 LSN。为此,进一步分析系统 IO 压力。

3.2 系统 IO 负载情况

根据以上 IO 负载情况,发现问题时段服务器 IO 压力分析,与上述猜想不想符!那是因为什么原因导致该问题呢?难道是无法找到最小 LSN,或者寻找比较慢?

3.3 再次分析 InnoDB Status

根据以上分析结果,再次分析了相关采集数据。发现 innodb status 输出包含如下信息:

---
LOG
---
Log sequence number          54848990703166
Log buffer assigned up to    54848990703166
Log buffer completed up to   54848990703166
Log written up to            54848990703166
Log flushed up to            54848990703166
Added dirty pages up to      54848990703166
Pages flushed up to          54846113541560
Last checkpoint at           54846113541560
5166640859 log i/o's done, 0.00 log i/o's/second
----------------------

发现当前 InnoDB 中的 Redo 日志使用量=最新 lsn - checkpoint lsn=54848990703166-54846113541560=2,877,161,606=2.68GB。

而此时数据库的 InnoDB Redo Log 配置为:

  • innodb_log_file_size | 1073741824
  • innodb_log_files_in_group | 3

即总的日志大小=1073741824*3=3GB

根据 MySQL 官方说明,需要确保 Redo 日志使用量不超过 Redo 总大小的 75%,否则就会导致数据库出现性能问题。但问题时刻我们的日志使用率=2.68/3=89%,超过 Redo 日志使用率的建议值 14%。

问题总结与建议

4.1 问题总结

综合以上分析过程,导致此次故障的根本原因还是在于数据库的 Redo 配置参数过小,在问题时段从节点的压力下,Redo 的使用率过高,导致 InnoDB 无法完成检查点。并进一步导致从节点的 worker 线程在执行事务时,检查 Redo Log 是否存在有剩余 Log 文件时,而发生等待。当前一个 worker 线程执行事务挂起后,由于从节点采用 MTS,且 slave_preserve_commit_order=on,因此其它 worker 线程需要等待之前的事务提交,最终导致所有 worker 线程挂起。

4.2 解决建议

  • 增加 Redo Log 文件的大小
  • 升级到 MySQL 8.0 的最新版本,解决 Bug 103636 等关键 bug
  • 增加 innodb_buffer_pool_size 内存大小

4.3 复杂问题针对数据采集建议

针对以上所有问题数据的采集,分享针对 MySQL 复杂问题的问题采集命令。具体如下:

来自:李锡超 -- <未知问题重启前信息采集>su - mysql
currdt=`date +%Y%m%d_%H%M%S`
echo "$currdt" > /tmp/currdt_tmp.txt
mkdir /tmp/diag_info_`hostname -i`_$currdt
cd /tmp/diag_info_`hostname -i`_$currdt-- 1. mysql进程负载
su - 
cd /tmp/diag_info_`hostname -i`_`cat /tmp/currdt_tmp.txt`ps -ef | grep -w mysqld
mpid=`pidof mysqld`
echo $mpid-- b: 批量模式; n: 制定采集测试; d: 间隔时间; H: 线程模式; p: 指定进程号
echo $mpid
top -b -n 120 -d 1 -H -p $mpid > mysqld_top_`date +%Y%m%d_%H%M%S`.txt-- 2. 信息采集步骤--- 以下窗口,建议启动额外的窗口执行
mysql -uroot -h127.1 -ptee var-1.txt
show global variables;tee stat-1.txt
show global status;tee proclist-1.txt
show full processlist\G
show full processlist;tee slave_stat-1.txt
show slave status\Gtee threads-1.txt
select * from performance_schema.threads \Gtee innodb_trx-1.txt
select * from information_schema.innodb_trx \Gtee innodb_stat-1.txt
show engine innodb status\Gtee innodb_mutex-1.txt
SHOW ENGINE INNODB MUTEX;-- 锁与等待信息
tee data_locks-1.txt-- mysql8.0
select * from performance_schema.data_locks\G
select * from performance_schema.data_lock_waits\G-- mysql5.7
select * from information_schema.innodb_lock_waits \G
select * from information_schema.innodb_locks\G-- 3. 堆栈信息
su - 
cd /tmp/diag_info_`hostname -i`_`cat /tmp/currdt_tmp.txt`ps -ef | grep -w mysqld
mpid=`pidof mysqld`
echo $mpid-- 堆栈信息
echo $mpid
pstack $mpid > mysqld_stack_`date +%Y%m%d_%H%M%S`.txt-- 线程压力
echo $mpidperf top
echo $mpid
perf top -p $mpidperf record -a -g -F 1000 -p $mpid -o pdata_1.dat
perf report -i pdata_1.dat-- 4. 等待 30 秒
SELECT SLEEP(60);-- 5. 信息采集步骤--- 以下窗口,建议启动额外的窗口执行
mysql -uroot -h127.1 -ptee var-2.txt
show global variables;tee stat-2.txt
show global status;tee proclist-2.txt
show full processlist\G
show full processlist;tee slave_stat-2.txt
show slave status\Gtee threads-2.txt
select * from performance_schema.threads \Gtee innodb_trx-2.txt
select * from information_schema.innodb_trx \Gtee innodb_stat-2.txt
show engine innodb status\Gtee innodb_mutex-2.txt
SHOW ENGINE INNODB MUTEX;-- 锁与等待信息
tee data_locks-2.txt-- mysql8.0
select * from performance_schema.data_locks\G
select * from performance_schema.data_lock_waits\G-- mysql5.7
select * from information_schema.innodb_lock_waits \G
select * from information_schema.innodb_locks\G-- 6. 堆栈信息
su - 
cd /tmp/diag_info_`hostname -i`_`cat /tmp/currdt_tmp.txt`ps -ef | grep -w mysqld
mpid=`pidof mysqld`
echo $mpid-- 堆栈信息
echo $mpid
pstack $mpid > mysqld_stack_`date +%Y%m%d_%H%M%S`.txt-- 线程压力
echo $mpidperf top
echo $mpid
perf top -p $mpidperf record -a -g -F 1000 -p $mpid -o pdata_2.dat
perf report -i pdata_2.dat--- END --

以上信息仅供交流,作者水平有限,如有不足之处,欢迎在评论区交流。

更多技术文章,请访问:https://opensource.actionsky.com/

关于 SQLE

SQLE 是一款全方位的 SQL 质量管理平台,覆盖开发至生产环境的 SQL 审核和管理。支持主流的开源、商业、国产数据库,为开发和运维提供流程自动化能力,提升上线效率,提高数据质量。

SQLE 获取

类型地址
版本库https://github.com/actiontech/sqle
文档https://actiontech.github.io/sqle-docs/
发布信息https://github.com/actiontech/sqle/releases
数据审核插件开发文档https://actiontech.github.io/sqle-docs/docs/dev-manual/plugins/howtouse

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/299746.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024年最新版FL Studio21.2.3 Build 4004 for Mac 版激活下载和图文激活教程

FL studio21中文别名水果编曲软件&#xff0c;是一款全能的音乐制作软件&#xff0c;包括编曲、录音、剪辑和混音等诸多功能&#xff0c;让你的电脑编程一个全能的录音室&#xff0c;它为您提供了一个集成的开发环境&#xff0c;使用起来非常简单有效&#xff0c;您的工作会变得…

【多线程】Callable详解

Callable接口 先看看Callable接口的源码: Callable是一个函数式接口&#xff0c;此时就可以用lambda表达式更简洁地使用它。Callable是个泛型接口&#xff0c;只有一个方法call&#xff0c;该方法返回类型就是传递进来的V类型。call方法还支持抛出异常. 与Callable对应的是Ru…

openstack中windows虚拟机时间显示异常问题处理

文章目录 一、问题描述二、元数据信息总结 一、问题描述 openstack创建出windows虚拟机的时候&#xff0c;发现时间和当前时间相差8小时&#xff0c;用起来很难受。 参考&#xff1a;https://www.cnblogs.com/hraa0101/p/11365238.html 二、元数据信息 通过设置镜像的元数据…

java对象是怎么在jvm中new出来的,在内存中查看java对象成员变量字段属性值

java对象是怎么在jvm中new出来的 查看java对象字段属性在内存中的值 java 对象 创建 流程 附上java源码 public class MiDept {private int innerFiled999;public MiDept() {System.out.println("new MiDept--------------");}public String show(int data) {Sy…

极客时间: 用 Word2Vec, LangChain, Gemma 模拟全本地检索增强生成(RAG)

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

QT的安装

● 查找国内的镜像 ○ 中国科学技术大学&#xff1a;http://mirrors.ustc.edu.cn/qtproject/ ○ 清华大学&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/qt/ ○ 北京理工大学&#xff1a;http://mirror.bit.edu.cn/qtproject/ ○ 中国互联网络信息中心&#xff1a;https:/…

C语言——#define的使用

#define定义常量 基本语法 #define name stuff //&#xff08;#define&#xff09;&#xff08;变量名&#xff09;&#xff08;定义的数值&#xff09; 这里记得&#xff0c;是不加分号的 定义常量&#xff08;这里 就要涉及我们经常说的宏定义&#xff09; 定义常量的使…

网络安全 | 什么是威胁情报?

关注WX&#xff1a;CodingTechWork 威胁情报 威胁情报-介绍 威胁情报也称为“网络威胁情报”(CTI)&#xff0c;是详细描述针对组织的网络安全威胁的数据。威胁情报可帮助安全团队更加积极主动地采取由数据驱动的有效措施&#xff0c;在网络攻击发生之前就将其消弭于无形。威…

Linux-线程知识点

目录 线程与进程区别pthread库接口介绍pthread_createpthread_self和syscall(SYS_gettid);pthread_equal测试主线程的栈空间大概是多大pthread_setname_nppthread_exitpthread_join为什么要连接退出的线程 pthread_detach 线程与进程区别 进程是一个动态的实体&#xff0c;有自…

大数据实验三-HBase编程实践

目录 一&#xff0e;实验内容 二&#xff0e;实验目的 三&#xff0e;实验过程截图及说明 1、安装HBase 2、配置伪分布式模式&#xff1a; 3、使用hbase的shell命令来操作表&#xff1a; 4、使用hbase提供的javaAPI来编程实现类似操作&#xff1a; 5、实验总结及心得体会…

Linux文件IO(4):目录操作和文件属性获取

目录 1. 前言 2. 函数介绍 2.1 访问目录 – opendir 2.2 访问目录 – readdir 2.3 访问目录 – closedir 2.4 修改文件访问权限 – chmod/fchmod 2.5 获取文件属性 – stat/lstat/fstat 2.5.1 文件属性 – struct stat 2.6 文件类型 – st_mode 3. 代码练习 3.1 要求 3.2 代…

(十一)RabbitMQ及SpringAMQP

1.初识MQ 1.1.同步和异步通讯 微服务间通讯有同步和异步两种方式&#xff1a; 同步通讯&#xff1a;就像打电话&#xff0c;需要实时响应。 异步通讯&#xff1a;就像发邮件&#xff0c;不需要马上回复。 两种方式各有优劣&#xff0c;打电话可以立即得到响应&#xff0c;…

2024-04-03 NO.4 Quest3 手势追踪抓取物体

文章目录 1 手势抓取方式1.1 Hand Grab1.2 Touch Hand Grab1.3 Distance Hand Grab 2 HandGrabExamples 示例场景2.1 Interactor 对象2.2 Interactable 对象2.2.1 父子结构2.2.2 “Hand Grab lnteractable” 脚本2.2.3 “Move Towards Target Provider” 脚本2.2.4 其他 Moveme…

linux常用目录结构(目录命令)--6986字详谈

前面与大家讨论了linux的发展与由来&#xff08;这一块挺多的&#xff0c;小编还没有编写完成&#xff0c;希望大家理解&#xff09;&#xff0c;紧接着谈到了vmware安装及运行所存在的故障&#xff08;鉴定错误&#xff0c;虚拟机没有网&#xff0c;蓝屏等常见现象的总结及处理…

Day105:代码审计-PHP原生开发篇SQL注入数据库监控正则搜索文件定位静态分析

目录 代码审计-学前须知 Bluecms-CNVD-1Day-常规注入审计分析 emlog-CNVD-1Day-常规注入审计分析 emlog-CNVD-1Day-2次注入审计分析 知识点&#xff1a; 1、PHP审计-原生态开发-SQL注入&语句监控 2、PHP审计-原生态开发-SQL注入&正则搜索 3、PHP审计-原生态开发-SQ…

Java 接口提示500,但console并不报错。

因为习惯了C语言printf打印&#xff0c;且当时并不明白try catch意义所在 如图所示&#xff0c;下添加了行号打印 但只打印出了line 89&#xff0c;无line 91&#xff0c;也无报错 所以使用try catch 包裹Sql查询封装函数 e.printStackTrace(); 果真打印出了 查看Entity类&…

【C++初阶】String在OJ中的使用(一):仅仅反转字母、字符串中的第一个唯一字母、字符串最后一个单词的长度、验证回文串、字符串相加

前言&#xff1a; &#x1f3af;个人博客&#xff1a;Dream_Chaser &#x1f388;博客专栏&#xff1a;C &#x1f4da;本篇内容&#xff1a;仅仅反转字母、字符串中的第一个唯一字母、字符串最后一个单词的长度、验证回文串、字符串相加 目录 917.仅仅反转字母 题目描述&am…

docker基础学习指令

文章目录 [toc] docker基础常用指令一、docker 基础命令二、docker 镜像命令1. docker images2. docker search3. docker pull4. docker system df5. docker rmi1. Commit 命令 三、 docker 容器命令1. docker run2. docker logs3. docker top4. docker inspect5. docker cp6. …

语音特征的反应——语谱图

语谱图的横坐标为时间&#xff0c;纵坐标为对应时间点的频率。坐标中的每个点用不同颜色表示&#xff0c;颜色越亮表示频率越大&#xff0c;颜色越淡表示频率越小。可以说语谱图是一个在二维平面展示三维信息的图,既能够表示频率信息,又能够表示时间信息。 创建和绘制语谱图的…

相位导数方差计算-matlab

%% 下面计算 相位导数方差% 假设 phase_map 是你的相位图二维矩阵 % K 是窗口的大小 k 3; % 请使用实际的窗口大小替换% 计算 x 和 y 方向的偏导 [dx, dy] gradient(wrappedPhase); Ksq k^2; % 计算 K^2half_k floor(k / 2);% 初始化结果矩阵 result zeros(size(wrappedPh…