08 深入专题:运维工具与部署
这一篇聚焦 MySQL 运维工具链与部署:安装升级流程、MySQL Shell/utilities、Orchestrator、pt-toolkit、systemd 与容器化部署、多实例管理。内容整理自爱可生开源社区《大智小技》系列(2019/2020 两册)技术文章精选。
MySQL 各字符集相关参数(cs_client/cs_results/cs_filesystem/cs_connection)分别控制什么?
字符集(character set)决定编码,校验集(collation)决定比较/排序。可设字符集+校验集的参数(cs_connection/cs_server/cs_database)用于字符串比较(如 WHERE 比较、存储内排序);仅能设字符集的参数都与外部系统相关:cs_client/cs_results 与 MySQL client 交互,cs_filesystem 与服务器文件系统交互(SELECT…INTO OUTFILE 的文件名按 cs_filesystem 写入)。client 按 mysql.client.charset 读取 SQL 文件,发往 server 按 cs_client,server 把字符串常量转 cs_connection、文件名转 cs_filesystem、再转存储层字符集。存储层库/表/列可分别指定字符集,子级可继承父级。
SET NAMES 与 SET CHARSET 对 MySQL 字符集参数的影响有何不同?导入乱码与之有关吗?
三组字符集+校验集参数:cs_connection/cs_server/cs_database(已废弃);四组仅字符集:cs_client/cs_results/cs_filesystem/cs_system(固定 utf8)。常见设置方式:连接握手 –default-character-set、SET NAMES、SET CHARSET。关键差异:SET NAMES 不影响客户端解析 SQL 文件的 mysql.client.charset(文档未介绍但会影响 client 读文件);SET CHARSET 会把 cs_connection 设成 cs_database 的值而非设置的字符集。本例 set names gbk 导入 gbk 文件,因 client 仍按默认 utf8 解析,导致 ‘璡’(ad5c,5c 为反斜杠) 被误读为转义单引号,SQL 无法正确切分。
用 source 导入 gbk SQL 时,‘璡’ 字为何导致后续 SQL 被打包、无法切分?
故障现象:set names gbk 后 source 一个大 gbk SQL 文件,遇到 INSERT … VALUES(‘璡’) 之后所有数据被打成一个大数据包发往 MySQL(>16M 走大数据包协议)。根因:SET NAMES 不改变 mysql.client.charset,client 仍用默认 utf8 解析文件。‘璡’ 的二进制编码为 ad5c,其中 5c 对应字符反斜杠,于是 ‘(璡)(单引号)’ 被误读为 ‘(前驱字节 ad 对应的字符)(被转义的单引号)’,单引号被转义,后续 SQL 因单引号不封闭被当成字符串,client 无法正确以分号切分 SQL,直到数据累积成大包。解决:用 –default-character-set=gbk 在握手时指定,或确保 client 解析字符集与文件一致。
InnoDB 数据字典表 SYS_TABLES/SYS_INDEXES/SYS_COLUMNS/SYS_FIELDS 如何用于恢复?
这四张字典表保存表定义信息(恢复表结构要用):SYS_TABLES(表名/表id/表空间id)、SYS_INDEXES(表id/索引id/root page id)、SYS_COLUMNS(表id/字段位置/名称/类型/长度)、SYS_FIELDS(索引id/字段列)。dict0boot.h 定义每张字典表的 index id,对应 id 的 page 存字典数据(SYS_TABLES=页1、SYS_COLUMNS=页2、SYS_INDEXES=页3、SYS_FIELDS=页4)。恢复时先 stream_parser 解析 ibdata1,再用 c_parser -4f pages-…/000000000000000N.page -t dictionary/xxx.sql 提取各字典,导入 recovered 库后 ./sys_parser 读取表结构。
InnoDB 表损坏、innodb_force_recovery=6 仍无法启动,如何提取数据并过滤坏记录?
损坏场景(如 page corruption on disk):先取故障表主键 index id(select t.name,t.table_id,i.index_id,i.page_no from INNODB_SYS_TABLES t join INNODB_SYS_INDEXES i …)。用 c_parser 从独立表空间对应 page 提取记录,坏记录需过滤:在 table.sql 的字段上加 /!FILTER int_min_val:1 int_max_val:300/ 注释,按范围筛掉坏数据;或先提取全部再 SQL 筛。提取后:innodb_force_recovery=6 启动 MySQL→删元数据→建新表导入恢复数据。丢失记录数 = page 期望记录数 - 实际恢复数(输出 Found records / Lost records 可见)。磁盘损坏则用 dd if=/dev/sdb of=img conv=noerror(或 nc 远程传)先保护现场。
MGR 节点掉线/需重启集群时,MySQL Shell 有哪些关键运维操作?
节点掉线:cluster.rescan() 发现后 cluster.rejoinInstance(‘host:port’) 重新加入;移除/加入用 cluster.removeInstance / addInstance。整集群断电:mysqlsh 里 dba.rebootClusterFromCompleteOutage(),按需把各实例 rejoin(可选 clone 或 incremental 恢复)。mysqlrouter –bootstrap root@主节点 –user=mysqlrouter 生成路由配置,读写端口 6446、只读 6447(X 协议 64460/64470)。主节点停服后集群自动选新主;读端口连从节点会报 –read-only 无法写。这些操作让组复制日常运维大幅简化。
OGG 从 Oracle 迁 MySQL 有哪些表结构/数据限制?无主键表怎么处理?
限制:①Oracle 大量 varchar(4000) 迁 MySQL 超出行限制(16K 页至少存两行,单行≤65535 字节),需收缩列或转 text(有性能代价);②InnoDB 索引前缀 767 字节,DYNAMIC/COMPRESSED+innodb_large_prefix 下 3072 字节,utf8mb4 最多对 varchar(768) 建索引;③全量初始化有外键时批量导入顺序不定易失败,建议 set global foreign_key_checks=off 禁用主外键约束,迁完再开。无主键表:MySQL 不推荐无主键(易主从延迟),OGG 默认把所有列拼成唯一键仍可能重复,官方建议对无主键表加 GUID 列(参考 MOS 1271578.1)。
OGG 全量与增量如何衔接?HANDLECOLLISIONS 起什么作用?版本怎么选?
HANDLECOLLISIONS 是关键:全量抽取前先开增量 extract 抓全量期间的 redo,全量应用完再开增量 replicat 应用期间增量。其逻辑:目标端缺的 delete 忽略;丢失的 update(主键则转 insert,非主键忽略);重复 insert 转 update 现有主键行。版本选择:客户 Oracle 11.2.0.4 先用 11 版,trail 文件到 2G 左右报错中断(RMTFILE 默认限 2G),换 12.3 用 MAXFILES 控制多文件、replicat 自动轮转解决;若 Oracle 跑 Linux 5 则最高只能用 OGG 12.2。报错 OGG-01201 需源/目标 MGR 加 ACCESSRULE 允许远程启动 replicat;OGG-01192 因 LOB/CLOB>4k 不支持 RMTTASK,改 RMTFILE 先抽文件再导入。
OGG 的 MGR/Extract/Pump/Replicat/defgen/checkpoint 各进程职责是什么?
Manager(MGR):管理进程,启停其他进程、分配端口。Extract:运行在源端,从 redo/表抽取数据,用 checkpoint 机制记录读写位置写本地 trail 文件,崩溃可断点续传。Pump:源端特殊 Extract,把本地 trail 经 TCP/IP 发往目标端(需目标端 MGR 先起,否则连接拒绝);不用 trail 时 Extract 直接投递。Replicat:目标端最后一站,读 trail 解析为 DML 应用到 MySQL,需 checkpoint 表保障不丢数据(类似 GTID/position)。defgen:生成异构表结构定义文件 cms.def,拷到目标端 dirdef,同构库不需要。checkpointtable:记录日志回放点。全量另用 SOURCEISTABLE 的 extract + SPECIALRUN 的 replicat。
dbdeployer 的常用管理与实例组操作命令有哪些?
查看支持版本/能力:dbdeployer admin capabilities [mysql|percona];按版本查信息:dbdeployer downloads get-by-version 5.7 –newest –dry-run;查看已装:dbdeployer sandboxes –full-info;查看运行:dbdeployer global status;批量停:dbdeployer global stop;删实例:dbdeployer delete msb_8_0_17(运行先停再清)。实例组目录(如 ~/sandboxes/rsandbox_8_0_17)含一键脚本:status_all 看状态、restart_al 重启全组、进某实例目录 ./restart 单启、./use 登录。可 dbdeployer admin lock <组> 加锁防误删,unlock 解锁。配置文件 sandbox-binary 指定解压目录,各架构有独立 base-port(主从 11000 起等)。
如何用 dbdeployer 一键部署单节点、主从、单主/多主 MGR 测试环境?
dbdeployer 不支持 Windows,Mac/Linux 下载单文件解压到 /usr/local/bin 即可。先下载 MySQL 包:dbdeployer downloads get-unpack mysql-8.0.17-macos10.14-x86_64.tar.gz(或 dbdeployer unpack 自解压)。部署:单节点 dbdeployer deploy single 8.0.17 –gtid –my-cnf-options=“character_set_server=utf8mb4”;主从(默认1主2从)dbdeployer deploy replication 8.0.17 –repl-crash-safe –gtid;单主 MGR dbdeployer deploy –topology=group replication 8.0.17 –single-primary;多主 MGR dbdeployer deploy –topology=all-masters replication 8.0.17。默认自动启动,–skip-start 只初始化不启。
用 MySQL Shell 搭建 MGR(InnoDB Cluster)需要哪些先决参数?
先关防火墙/selinux/firewalld。配置文件关键项:master-info-repository=table、relay-log-info-repository=table、gtid_mode=ON、enforce_gtid_consistency=ON、binlog_checksum=NONE、log_slave_updates=ON、binlog_format=ROW、transaction_write_set_extraction=XXHASH64。配好 /etc/hosts 与 report_host(用 SELECT coalesce(@@report_host,@@hostname) 验证)。建管理员用户后,mysqlsh 里 dba.checkInstanceConfiguration 检查各节点,dba.createCluster(‘ytt_mgr’) 建集群,cluster.addInstance 加节点。集群默认 Single-Primary,可容忍一个节点故障。
用 OGG 做 Oracle→MySQL 迁移,源端 Oracle 需要哪些前置配置?
OGG 抓取完整日志需:①开启归档模式(shutdown immediate→startup mount→alter database archivelog→open,需重启);②开启附加(最小)补充日志 alter database add supplemental log data 与强制日志 alter database force logging;③启用 OGG 支持 alter system set enable_goldengate_replication=true(11g 需 SYS 参数);④创建 OGG 用户并授权(connect/resource/unlimited tablespace、select any dictionary/table、alter any table、flashback any table、select any transaction、sysdba、dbms_goldengate_auth.grant_admin_privilege 等)。表级还需 add trandata 开启补全日志,否则 redolog 信息不全。
误 drop table 且没有备份,如何用 undrop-for-innodb 抢救数据?innodb_file_per_table 开/关有区别吗?
立即停 MySQL,勿重启;file_per_table=ON 时最好只读挂载文件系统防覆盖,可从块设备扫描:./stream_parser -f /dev/sda1 -t 1000000k。步骤:①stream_parser 解析表空间取 page;②c_parser 从 SYS_TABLES(页1)/SYS_COLUMNS(页2)/SYS_INDEXES(页3)/SYS_FIELDS(页4) 提取字典,./sys_parser 恢复表结构(5.x 会丢 AUTO_INCREMENT/二级索引/外键/DECIMAL 精度);③用 table_id→主键 index_id 在对应 page 提取数据。file_per_table=OFF(共享表空间)数据在 ibdata1,直接 stream_parser -f ibdata1 提取。5.5 若 frm 被删可在原目录 touch 同名 frm 恢复;只有 frm 用 mysqlfrm –diagnostic 读取。
DBLE rule.xml 中 PatternRange 分片算法如何工作?连续分片与离散分片区别?
rule.xml 定义实际拆分算法。以 PatternRange 为例:schema.xml 中
DBLE schema.xml 由哪三大节点组成?如何配置分片表与全局表?
schema.xml 是 DBLE 分片最核心配置,由三层节点组成:SCHEMA(逻辑库)、DATANODE(分片节点,关联 dataHost 与后端 database)、DATAHOST(节点主机,含 writeHost/readHost、心跳、连接数、balance、switchType)。举例:(全局表,各节点全量)
DBLE server.xml 的 system/user/firewall 三段如何配置?reload @@config 有何限制?
server.xml 分三段:
DBLE 用户 DML 权限与黑白名单如何配置?
用户权限:
DBLE+ZK 集群中,视图存在哪里?节点故障是否影响服务?
验证结论:通过 DBLE 节点建的视图只存 ZK 不存 MySQL。zkCli 下 ls /dble/cluster-1/view 可见 schema1:view_test,但直连后端 MySQL 的 show tables 只有基表、无视图,说明视图元数据在 ZK 并同步到所有 DBLE 节点。高可用验证:手动停掉 DBLE-A,连 DBLE-C 改 test_global 表结构(alter table add column),再连 DBLE-B 查 desc 已同步——集群中某节点掉线/故障不影响其他节点对外服务。这正是 ZK 协调带来的状态/元数据一致性与服务连续性,适合生产高可用部署。
如何用 ZooKeeper 集群管理 DBLE 集群?reload @@config_all 如何同步配置?
架构:ZK 集群(≥3 台,3.4.12)管理多台 DBLE(2.19.05.0)。步骤:装 JDK1.8+;配 zoo.cfg(tickTime=2000, initLimit=10, syncLimit=5, clientPort=2181, server.1/2/3=ip:2888:3888)并建 myid 文件;启 ZK(zkServer.sh start,一 Leader 两 Follower)。DBLE 侧:conf/myid.properties 设 cluster=zk、ipAddress=zk_ip:2181(可多 IP 逗号分隔)、clusterId=cluster-1、myid 各节点不同;./dble start。验证:zkCli.sh 下 ls /dble/cluster-1/online 看到所有节点。改 A 节点 schema.xml 加全局表后,A 执行 reload @@config_all,B/C 自动同步——配置经 ZK 下推全集群。
如何用 docker-compose 快速启动 DBLE 体验环境?服务/管理端口与用户?
安装 docker + docker-compose + MySQL 客户端,下载官方 docker-compose.yml(actiontech/dble 仓库),docker-compose up -d 拉镜像启动。默认创建 3 容器:两个 MySQL(端口映射宿主机 33061/33062),dble-server(业务 8066、管理 9066 映射到宿主机同端口)。连接:业务端口 mysql -P8066 -u root -p123456 -h 127.0.0.1;管理端口 mysql -P9066 -u man1 -p654321 -h 127.0.0.1(默认用户 man1/654321)。清理用 docker-compose stop/down。可连 33061/33062 直连后端 MySQL 验证。适合快速 quick start。
如何用自定义配置(volumes + 初始化脚本)启动 DBLE 容器?
默认 docker_init_start.sh 流程:启 dble→等 8066→管理端口 create database @@dataNode=‘dn1..dn4’→source 初始化 SQL。自定义时:①本地准备 schema.xml/rule.xml/server.xml/init.sql/customized_script.sh;②在 dble-server 的 volumes 把本地目录挂到容器(如 ./:/opt/init/),command 改为 [wait-for-it.sh, backend-mysql1:3306, –, /opt/init/customized_script.sh];③脚本里 cp 三个 xml 到 /opt/dble/conf/,sh dble start,wait-for-it 等 8066,管理端口建库,业务端口 source /opt/init/init.sql。这样用非默认配置快速起 DBLE 集群做验证。
MySQL Shell 管理 MGR 日常运维有哪些内置方法(get_cluster/set_primary/switch 模式/status/dissolve)?
MySQL Shell(Py)管理 MGR 的内置方法:c1=dba.get_cluster() 获取集群对象;c1.describe() 看拓扑、c1.status()(extended 0/1/2/3,分别默认/元数据/重放线程事务/各节点详情)看运行状态;c1.set_primary_instance(’node_b:port’) 提升从为主;c1.switch_to_multi_primary_mode()/switch_to_single_primary_mode() 切换多主/单主;c1.set_option 改集群参数(如强一致性)、set_instance_option 改单节点(如 label);c1.list_routers() 看路由;c1.dissolve() 解散集群(删元数据与组复制配置,但保留用户数据)。这些方法极大简化组复制运维。
MySQL 如何安全地给数据库改名?有哪些可行方案?
MySQL 已取消 RENAME DATABASE 命令(实现不完备)。方案:①mysqldump 导出旧库再导入新库(最慢但最稳,含表/视图/触发器/事件/存储过程,2002 表 826M 约 12 分);②改整库表名:先把视图/触发器/存储过程/存储函数/事件用 mysqldump -t -d -n –triggers –routines –events 等导出并删除,再用 SELECT CONCAT(‘rename table ‘,GROUP_CONCAT(…)) 拼 rename table old.t to new.t 批量改名(55 秒),最后导入其他对象——比方案①快很多;③历史方案:从机配 replicate-rewrite-db=old->new 追 binlog 后提升,局限性大不推荐。数据量巨大建议用 ETL/解析 binlog。
用 rename table 批量把旧库表迁到新库时,如何一并迁移视图/触发器/存储过程/事件?
rename table 只搬磁盘表,其他对象需单独处理。步骤:①导出非表对象:mysqldump –triggers –routines –events(视图按 information_schema.views 查出单独导);②逐类删除旧库对象(DROP FUNCTION/PROCEDURE/TRIGGER/VIEW/EVENT,用 information_schema 拼语句);③set group_concat_max_len=18446744073709551615 后用 GROUP_CONCAT 拼出 rename table old.t1 to new.t1, … 并 prepare/execute 批量改名;④把导出的其他对象 source 进新库。最后校验表数、触发器、存储过程、函数、事件数量是否一致。这样可在分钟级完成大库改名且保留全部对象。
MySQL 启动报 io_setup() failed with EAGAIN,fs.aio-max-nr 该怎么配?
MySQL 默认启用 innodb_use_native_aio,启动分配 aio slot 超过系统 fs.aio-max-nr 则报错无法启动(单机多实例尤易触发)。单实例申请量公式:fs.aio-nr = (innodb_read_io_threads + innodb_write_io_threads + log thread + insert buffer thread) × 256 + 101(实测约 4709 = 18×256+101,其中 256 是每 IO 线程 event 数)。配置建议:单实例部署 fs.aio-max-nr 至少 > 单实例 fs.aio-nr;多实例部署至少 > 本机实例数 × 每实例 fs.aio-nr。可用 strace -fe trace=io_setup 观测实际分配。调大 /proc/sys/fs/aio-max-nr 即可解决 EAGAIN。
MariaDB 审计插件的记录格式与输出方式是什么?
审计记录格式为逗号分隔:[timestamp],[serverhost],[username],[host],[connectionid],[queryid],[operation],[database],[object],[retcode],例如 ‘20200820 11:04:04,infokist,superuser,localhost,23,4759,QUERY,ds_db,‘select count(*) from vm_zfs_storage’,0’。输出:server_audit_output_type=file 时写 datadir 下 server_audit.log(默认),到 server_audit_file_rotate_size 自动切换,server_audit_file_rotations 控制保留份数;设为 syslog 则经 syslog.h API 发本地 syslogd。可用 SET GLOBAL server_audit_file_rotate_now=on 强制切换文件。格式简单、便于后续采集分析。
社区版 MySQL 没有审计插件,如何安装 MariaDB 审计插件?关键参数?
Oracle MySQL 社区版不含 Audit Plugin,可用 GPL 的 MariaDB 审计插件。MariaDB 10.1 对应 MySQL 5.7,下载 mariadb-10.1.46-linux-x86_64.tar,取出 lib/plugin/server_audit.so 拷到 MySQL 插件目录(如 /usr/lib/mysql/plugin/),执行 INSTALL PLUGIN server_audit SONAME ‘server_audit.so’。关键参数:server_audit_logging=ON 开启审计;server_audit_events=‘connect,query’ 记录连接与查询;server_audit_file_rotate_size(单文件大小)、server_audit_file_rotations(文件数,默认 9,到顶覆盖首个)、server_audit_output_type(file 或 syslog)、server_audit_query_log_limit=1024。配置写 [server] 段重启生效。
MGR 节点因网络抖动被驱逐,group_replication_member_expel_timeout 参数如何配置?
8.0.13 引入 group_replication_member_expel_timeout,指定产生怀疑后、从组排除可疑成员的等待秒数(最初 5 秒检测期不计入)。≤8.0.20 默认 0(检测 5 秒后立即驱逐);≥8.0.21 默认 5(检测 5 秒后仍不正常再等 5 秒才驱逐)。测试用 tc qdisc add dev eth0 root netem delay 10s 模拟延迟,设该参数为 5 时,mgr2 在检测期+5 秒周期内与其他节点失联被踢;网络恢复后 auto-rejoin 机制尝试重加并通过 binlog 恢复。若长时间未恢复则节点变 ERROR,需重启组复制恢复。调大该值可降低短时网络抖动导致的误驱逐。
JDBC 连接 MySQL 时 useSSL 与 verifyServerCertificate 应如何正确配置?
MySQL 5.5.45+/5.6.26+/5.7.6+ 起,未显式设置时默认要求建立 SSL 连接。三种正确姿势:①不需要 SSL:显式 useSSL=false;②需要 SSL 且做证书校验:useSSL=true 并提供 truststore(verifyServerCertificate 默认 true,要验证服务器证书);③不验证证书:useSSL=true&verifyServerCertificate=false(仅加密不验证,不安全)。本血案中连接串 useSSL=true 但无 truststore 导致握手失败;改为 useSSL=false 即恢复。注意 5.7.28 默认生成证书并开启 SSL,旧版(yassl、无证书)会静默降级,这正是升级后行为突变的原因。
MySQL 从 5.7.27 升级到 5.7.28 后应用报 Bad handshake / SSL 连接失败,根因是什么?
根因不是 bug,而是 5.7.28 起 Only OpenSSL(移除 yassl),且新增 auto-generate-certs(默认 ON):启动时在数据目录自动生成 ca.pem/server-cert.pem 等 SSL 证书文件,默认开启 SSL 支持。5.7.27 默认 yassl 编译、不生成证书、实际不支持 SSL。应用 JDBC 串误配 useSSL=true,在 5.7.27 因服务端不支持 SSL 而降级用非 SSL(正常);在 5.7.28 服务端支持 SSL 且需证书校验(verifyServerCertificate 默认 true),应用无 truststore 故 SSLHandshakeException 失败,错误日志记 ‘Bad handshake’。回退 5.7.27 仍未解决是因为数据目录的 pem 文件残留,mysql_upgrade 不删它们,导致 5.7.27 也实际开启 SSL。
升级 5.7.28 引发 Bad handshake 后,回退仍未解决,如何正确修复?
因 5.7.28 自动生成的 pem 文件残留,回退后 5.7.27 仍实际开启 SSL,故误配 useSSL=true 的应用依旧失败。修复思路:①删全部 pem 文件重启(5.7.27 可行,但升级回 5.7.28 又会重生,不行);②删部分文件(如 ca.pem)使 SSL disabled 且不重生,但 Xtrabackup 物理备不备 pem,重做后会被重新生成,不稳;③配 auto_generate_certs=off 让不生成 cert、默认 SSL disabled;④最推荐:为保持升级前后一致,在 [mysqld] 加 skip_ssl,忽略 SSL 证书文件、不启用 SSL。应用侧则应明确 useSSL=false 或提供 truststore。升级前务必对比参数、别只信 release notes。