为内部 AI 工具平台集成统一的模型调用与权限管理
2026/4/30 19:19:34
-- 脏页 = 内存中被修改但未写入磁盘的数据页-- 在内存中的版本(新)≠ 在磁盘中的版本(旧)┌─────────────────────────────────────────────────────┐ │ 脏页生命周期 │ ├─────────────────────────────────────────────────────┤ │ 1. 从磁盘读取干净页到缓冲池 │ │ 2. 应用程序修改页内数据 │ │ 3. 标记为"脏页"(内存 vs 磁盘不一致) │ │ 4. Page Cleaner 将脏页写入磁盘 │ │ 5. 标记为"干净页"(内存和磁盘一致) │ └─────────────────────────────────────────────────────┘# 查看脏页统计mysql -e" SELECT '缓冲池总页数' AS 指标, VARIABLE_VALUE AS 值, '页' AS 单位 FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_pages_total' UNION ALL SELECT '当前脏页数量', VARIABLE_VALUE, '页' FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_pages_dirty' UNION ALL SELECT '脏页比例', CONCAT(ROUND( (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_pages_dirty') / (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_pages_total') * 100, 2), '%'), '' ORDER BY 1; "-- 1. DML 操作(INSERT/UPDATE/DELETE)UPDATEusersSETlast_login=NOW()WHEREid=1;-- ↑ 修改内存中的页,标记为脏页-- 2. 索引变更ALTERTABLEordersADDINDEXidx_created(created_at);-- ↑ 构建索引时产生大量脏页-- 3. 批量数据操作INSERTINTOlog_tableSELECT*FROMhuge_table;-- ↑ 大规模数据插入产生大量脏页-- 4. 隐式产生-- 行格式转换、空间回收等内部操作也会产生脏页#!/bin/bash# monitor-dirty-page-generation.shecho"=== 脏页生成监控 ==="echo"时间戳,总页数,脏页数,每秒新增脏页,刷新页数,未决刷新">/tmp/dirty_page_log.csvLAST_DIRTY=0LAST_FLUSHED=0whiletrue;do# 获取当前状态CURRENT=$(mysql -Nse " SELECT(SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Innodb_buffer_pool_pages_total'),(SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Innodb_buffer_pool_pages_dirty'),(SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Innodb_buffer_pool_pages_flushed'),(SELECT SUM(VARIABLE_VALUE)FROM performance_schema.global_status WHERE VARIABLE_NAME LIKE'Innodb_buffer_pool_pending_flushes_%')" 2>/dev/null || echo "0000") TOTAL=$(echo$CURRENT|awk'{print $1}')DIRTY=$(echo$CURRENT|awk'{print $2}')FLUSHED=$(echo$CURRENT|awk'{print $3}')PENDING=$(echo$CURRENT|awk'{print $4}')# 计算速率 TIMESTAMP=$(date+%s)DIRTY_DELTA=$((DIRTY-LAST_DIRTY))FLUSH_DELTA=$((FLUSHED-LAST_FLUSHED))# 输出 echo "$TIMESTAMP,$TOTAL,$DIRTY,$DIRTY_DELTA,$FLUSH_DELTA,$PENDING" | \ tee -a /tmp/dirty_page_log.csv # 更新上一次的值 LAST_DIRTY=$DIRTYLAST_FLUSHED=$FLUSHED# 检查阈值 if [$DIRTY-gt$((TOTAL*75/100))]; then echo "警告: 脏页比例超过75%!当前:$((DIRTY*100/TOTAL))%"fisleep1done-- Page Cleaner 是多线程架构-- 每个线程负责一部分缓冲池实例的刷新-- 工作流程:-- 1. 扫描 LRU 列表寻找旧脏页-- 2. 扫描 Flush 列表寻找检查点脏页-- 3. 批量写入到 doublewrite buffer-- 4. 写入到数据文件-- 三种触发方式:-- 1. 自适应刷新(Adaptive Flushing)-- 基于redo日志生成速率和当前脏页比例-- 2. 同步刷新(Sync Flushing)-- 当脏页比例达到 innodb_max_dirty_pages_pct_lwm 时触发-- 3. 检查点刷新(Checkpoint Flushing)-- 保证redo日志空间可循环使用-- 刷新顺序(优先级从高到低):-- 1. 最近最少使用(LRU)的脏页-- 2. 最老的脏页(从Flush列表)-- 3. 随机脏页(当压力大时)# 深度监控 Page Cleanermysql -e" -- 查看刷新统计 SELECT 'LRU 列表刷新' AS 刷新类型, VARIABLE_VALUE AS 刷新页数 FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_pages_made_not_young' UNION ALL SELECT 'Flush 列表刷新', VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_pages_flushed' UNION ALL SELECT '每秒刷新速率', ROUND(VARIABLE_VALUE / (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Uptime'), 2) FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_pages_flushed'; "# /etc/my.cnf [mysqld] # 1. Page Cleaner 线程数(等于或少于缓冲池实例数) innodb_page_cleaners = 8 # 2. 缓冲池实例数(提高并发刷新) innodb_buffer_pool_instances = 8 # 3. 缓冲池大小(足够大可减少频繁刷新) innodb_buffer_pool_size = 64G # 4. 日志文件大小(大日志减少检查点压力) innodb_log_file_size = 4G innodb_log_files_in_group = 3 # 5. 使用 O_DIRECT 绕过 OS 缓存 innodb_flush_method = O_DIRECT-- 在线优化刷新效率SETGLOBALinnodb_io_capacity=4000;-- 根据磁盘性能设置SETGLOBALinnodb_io_capacity_max=8000;-- 峰值 I/O 能力SETGLOBALinnodb_lru_scan_depth=1024;-- LRU 扫描深度SETGLOBALinnodb_max_dirty_pages_pct=75;-- 最大脏页比例SETGLOBALinnodb_max_dirty_pages_pct_lwm=50;-- 低水位线SETGLOBALinnodb_adaptive_flushing=ON;-- 启用自适应刷新SETGLOBALinnodb_adaptive_flushing_lwm=10;-- 自适应刷新低水位SETGLOBALinnodb_flush_neighbors=0;-- SSD 设为 0# 1. 使用高性能存储# NVMe SSD > SATA SSD > HDD# 2. 配置 RAID(如果使用 HDD)# RAID 10 提供最佳性能和冗余# 3. 文件系统优化# 使用 XFS 或 ext4 with noatime,nodiratimemount|grep/var/lib/mysql# 理想选项:noatime,nodiratime,barrier=0,data=ordered# 4. I/O 调度器优化echo"deadline">/sys/block/sda/queue/scheduler# 数据库负载# 或使用 noop(SSD)#!/bin/bash# monitor-disk-io-for-page-cleaner.shecho"=== 磁盘 I/O 性能监控(Page Cleaner 相关)==="# 监控写入延迟(关键指标!)iostat -dx25|awk' BEGIN {print "设备,使用率%,平均等待(ms),平均服务(ms),每秒写入"} NR>3 && $1 ~ /^sd|^nvme/ { printf "%s,%.1f,%.1f,%.1f,%.1f\n", $1, $14, $10, $11, $5 }'# 查看 InnoDB 相关的 I/O 统计mysql -e" SELECT VARIABLE_NAME, VARIABLE_VALUE, CASE WHEN VARIABLE_NAME LIKE '%write%' THEN '写入' WHEN VARIABLE_NAME LIKE '%read%' THEN '读取' WHEN VARIABLE_NAME LIKE '%sync%' THEN '同步' ELSE '其他' END AS 类型 FROM performance_schema.global_status WHERE VARIABLE_NAME LIKE 'Innodb_data_%' OR VARIABLE_NAME LIKE 'Innodb_os_log_%' ORDER BY 类型, VARIABLE_NAME; "-- 1. 批量提交事务STARTTRANSACTION;-- 多条更新语句UPDATEtable1SET...;UPDATEtable2SET...;COMMIT;-- 一次产生一组脏页-- 2. 合理使用事务大小-- 避免超大事务(产生大量脏页)-- 3. 优化 UPDATE/DELETE 模式-- 使用 LIMIT 分批更新UPDATElarge_tableSETstatus='processed'WHEREstatus='pending'LIMIT1000;-- 4. 使用合适的数据类型-- 避免不必要的大字段更新#!/bin/bash# monitor-transaction-pattern.shecho"=== 事务模式分析(脏页生成相关)==="# 监控长事务和大事务mysql -e" SELECT trx_id, trx_started, TIMESTAMPDIFF(SECOND, trx_started, NOW()) AS duration_sec, trx_state, trx_operation_state, trx_tables_in_use, trx_tables_locked, trx_rows_locked, trx_rows_modified FROM information_schema.INNODB_TRX ORDER BY trx_rows_modified DESC LIMIT 10; "# 监控脏页生成率mysql -e" SELECT '当前脏页' AS metric, VARIABLE_VALUE AS value FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_pages_dirty' UNION ALL SELECT '每分钟脏页生成', ROUND( (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_pages_data') / (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Uptime') * 60, 0 ) UNION ALL SELECT '每分钟页面修改', ROUND( (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_pages_modified') / (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Uptime') * 60, 0 ); "# /etc/sysctl.conf# 虚拟内存优化vm.swappiness=1# 减少 swap 使用vm.dirty_ratio=10# 系统脏页比例阈值vm.dirty_background_ratio=5# 后台刷新阈值vm.dirty_expire_centisecs=3000# 脏页超时时间(30秒)vm.dirty_writeback_centisecs=500# 后台刷新间隔(5秒)# I/O 调度和队列vm.vfs_cache_pressure=1000# 回收 page cache 的倾向fs.aio-max-nr=1048576# 增加异步 I/O 限制# 应用配置sysctl -p# 检查 NUMA 配置numactl --hardware# 如果启用 NUMA,绑定 MySQL 到特定节点# 方法1:启动时绑定numactl --cpunodebind=0--membind=0mysqld# 方法2:在配置中设置[mysqld]innodb_numa_interleave=ON-- 1. 启用激进刷新模式(高写入负载时)SETGLOBALinnodb_flushing_avg_loops=10;-- 减少平均值计算周期SETGLOBALinnodb_adaptive_max_sleep_delay=150000;-- 最大睡眠延迟-- 2. 监控并调整自适应刷新-- 查看当前的刷新压力SELECTVARIABLE_NAME,VARIABLE_VALUEAS当前值,CASEWHENVARIABLE_NAME='Innodb_buffer_pool_pages_dirty'ANDVARIABLE_VALUE>(SELECTVARIABLE_VALUEFROMperformance_schema.global_statusWHEREVARIABLE_NAME='Innodb_buffer_pool_pages_total')*0.7THEN'建议增加 innodb_io_capacity'WHENVARIABLE_NAME='Innodb_buffer_pool_wait_free'ANDVARIABLE_VALUE>1000THEN'刷新速度跟不上'ELSE'正常'ENDAS建议FROMperformance_schema.global_statusWHEREVARIABLE_NAMEIN('Innodb_buffer_pool_pages_dirty','Innodb_buffer_pool_wait_free','Innodb_log_waits');-- 分析 Page Cleaner 工作模式SELECTevent_name,count_star,sum_timer_wait/1000000000astotal_sec,avg_timer_wait/1000000000asavg_secFROMperformance_schema.events_waits_summary_global_by_event_nameWHEREevent_nameLIKE'%innodb/page%cleaner%'ORevent_nameLIKE'%innodb/buf%flush%'ORDERBYsum_timer_waitDESC;-- 查看刷新延迟分布SELECT'刷新延迟分析'as分析,MIN_TIMER_WAIT/1000000asmin_ms,AVG_TIMER_WAIT/1000000asavg_ms,MAX_TIMER_WAIT/1000000asmax_msFROMperformance_schema.events_waits_summary_global_by_event_nameWHEREevent_name='wait/io/file/innodb/innodb_data_file';#!/bin/bash# emergency-dirty-page-flush.shecho"=== 脏页积压应急处理 ==="# 1. 检查紧急程度DIRTY_PCT=$(mysql -Nse " SELECT ROUND((SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Innodb_buffer_pool_pages_dirty')/(SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Innodb_buffer_pool_pages_total')*100,2)" 2>/dev/null || echo 0) echo "当前脏页比例:${DIRTY_PCT}%" if [$(echo"$DIRTY_PCT> 90"|bc)-eq 1 ]; then echo "🚨 紧急: 脏页超过90%,立即处理!" # 2. 临时提高 I/O 容量 mysql -e "SET GLOBAL innodb_io_capacity=8000;" mysql -e "SET GLOBAL innodb_io_capacity_max=16000;" # 3. 降低脏页阈值,强制刷新 mysql -e "SET GLOBAL innodb_max_dirty_pages_pct=50;" mysql -e "SET GLOBAL innodb_max_dirty_pages_pct_lwm=30;" # 4. 减少负载(如果可能) echo "考虑:" echo "- 暂停批量作业" echo "- 分流读流量" echo "- 降低写入速率" # 5. 监控恢复 watch -n 1 ' echo "脏页变化:" mysql -Nse "SELECT VARIABLE_NAME, VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME=\"Innodb_buffer_pool_pages_dirty\"" 2>/dev/null echo -e "\n磁盘 I/O:" iostat -dx11|grep-A1\"Device\" 'fi#!/bin/bash# page-cleaner-dashboard.shecho"================================================"echo" Page Cleaner 性能仪表板"echo"================================================"whiletrue;doclear# 获取数据DATA=$(mysql -Nse" SELECT -- 缓冲池状态 (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_pages_total'), (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_pages_dirty'), (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_pages_flushed'), -- I/O 统计 (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_data_writes'), (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_data_fsyncs'), -- 性能指标 (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_wait_free'), (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_log_waits') "2>/dev/null||echo"0 0 0 0 0 0 0")TOTAL=$(echo$DATA|awk'{print $1}')DIRTY=$(echo$DATA|awk'{print $2}')FLUSHED=$(echo$DATA|awk'{print $3}')WRITES=$(echo$DATA|awk'{print $4}')FSYNCS=$(echo$DATA|awk'{print $5}')WAIT_FREE=$(echo$DATA|awk'{print $6}')LOG_WAITS=$(echo$DATA|awk'{print $7}')# 计算比例DIRTY_PCT=$((DIRTY*100/TOTAL))# 显示仪表板echo"刷新时间:$(date'+%Y-%m-%d %H:%M:%S')"echo"------------------------------------------------"printf"缓冲池使用: %'d / %'d 页\n"$DIRTY$TOTALprintf"脏页比例: %d%%\n"$DIRTY_PCTecho""# 进度条显示echo-n"脏页比例: ["foriin$(seq150);doif[$i-le$((DIRTY_PCT/2))];thenecho-n"█"elseecho-n"░"fidoneecho"]"echo""# 刷新统计echo"刷新统计:"printf" 累计刷新: %'d 页\n"$FLUSHEDprintf" 数据写入: %'d 次\n"$WRITESprintf" Fsync调用: %'d 次\n"$FSYNCSecho""# 等待统计echo"等待统计(越低越好):"printf" 缓冲池等待空闲: %'d\n"$WAIT_FREEprintf" 日志等待: %'d\n"$LOG_WAITSecho""# 建议echo"建议:"if[$DIRTY_PCT-gt80];thenecho" 🚨 脏页过多,考虑增加 innodb_io_capacity"elif[$WAIT_FREE-gt100];thenecho" ⚠️ 刷新跟不上,检查磁盘性能"elif[$LOG_WAITS-gt10];thenecho" ⚠️ 日志文件可能太小"elseecho" ✅ 状态良好"fiecho"------------------------------------------------"echo"按 Ctrl+C 退出监控"sleep2done-- 配置优化优先级:1.磁盘性能(最快的可用存储)2.innodb_io_capacity(匹配磁盘性能)3.innodb_page_cleaners(匹配CPU核心数)4.innodb_buffer_pool_size(足够大)5.innodb_log_file_size(减少检查点)-- 应用优化:1.合理事务大小2.批量操作3.避免热点更新记住:优化是一个持续的过程,需要根据实际负载不断调整和监控。