在日常MySQL数据库维护中,随着业务增长,历史数据(如日志、过期订单、旧版记录)会不断累积,导致表体积膨胀、查询性能下降,甚至影响备份与恢复效率。Percona Toolkit中的pt-archiver工具,专为解决数据归档与清理需求设计,支持将数据迁移至归档实例或文件,同时可灵活控制是否保留原数据,是DBA日常工作中的核心工具之一。本文将从环境准备、核心用法到自动化脚本,完整讲解pt-archiver的实践流程。
一、准备工作:搭建基础环境
在使用pt-archiver前,需完成环境初始化,包括明确工具作用、创建权限用户及搭建测试场景,确保后续操作顺利进行。
1.1 pt-archiver的核心作用
pt-archiver本质是一款MySQL数据归档工具,基于Perl语言开发,核心能力包括:
- 数据清理:删除过期或无用的历史数据,减轻主库存储压力;
- 数据归档:将历史数据迁移至独立归档实例(或文件),既保留数据可追溯性,又不影响主库性能;
- 低影响操作:支持批量处理、事务控制,避免大事务对数据库锁表或性能的冲击。
1.2 创建数据库操作用户
为pt-archiver分配足够权限的数据库用户(避免直接使用root),确保工具能跨实例读写数据。以下命令在原实例(192.168.12.161) 和归档实例(192.168.12.163) 中分别执行:
sql
-- 创建dba用户,允许192.168网段访问
CREATE USER 'dba'@'192.168.%' IDENTIFIED WITH MYSQL_NATIVE_PASSWORD BY 'Id81Gdac_a';
-- 授予所有库表的操作权限(生产环境可根据实际需求缩小权限范围)
GRANT ALL ON *.* TO 'dba'@'192.168.%';
1.3 搭建测试环境
为验证pt-archiver效果,需创建源表、归档表及测试数据,具体如下:
步骤1:在原实例(192.168.12.161)创建测试库表
sql
-- 假设源库名为martin
USE martin;
-- 创建测试表archiver_test(含自增主键,模拟业务表结构)
CREATE TABLE archiver_test (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) COMMENT '姓名',
age INT COMMENT '年龄'
);
-- 插入测试数据
INSERT INTO archiver_test (name, age) VALUES
('John', 25),
('Alice', 30),
('Michael', 35),
('Emily', 28),
('David', 32);
步骤2:在归档实例(192.168.12.163)创建归档库表
需确保归档表结构与源表一致,且归档实例不能是原实例的从库(避免归档操作影响主从同步):
sql
-- 创建归档库archiver_db
CREATE DATABASE archiver_db;
USE archiver_db;
-- 创建与源表结构一致的归档表
CREATE TABLE archiver_test (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) COMMENT '姓名',
age INT COMMENT '年龄'
);
二、pt-archiver核心用法实践
pt-archiver的命令格式可概括为:pt-archiver --source [源库参数] --dest [目标库参数] [可选参数],以下针对不同业务场景给出具体示例,并解释关键参数含义。
2.1 场景1:全表归档(不删除原表数据)
适用于"需保留主库数据副本,同时归档备份"的场景(如历史订单归档但主库需临时查询):
bash
pt-archiver \
--source h=192.168.12.161,u=dba,p='Id81Gdac_a',D=martin,t=archiver_test \ # 源库信息(h=IP,u=用户,p=密码,D=库,t=表)
--dest h=192.168.12.163,u=dba,p='Id81Gdac_a',D=archiver_db,t=archiver_test \ # 归档库信息
--where '1=1' \ # 条件:全表(1=1表示所有数据)
--progress 10000 \ # 每处理10000行输出进度
--limit=10000 \ # 每次批量处理10000行(避免单次查询压力过大)
--txn-size=10000 \ # 每10000行提交一次事务(减少事务日志占用)
--no-safe-auto-increment \ # 禁用自增主键安全检查(避免归档表自增冲突)
--statistics \ # 输出操作统计信息(如处理行数、耗时)
--no-delete # 核心参数:不删除源表数据
2.2 场景2:全表归档(删除原表数据)
适用于"主库无需保留历史数据,仅需归档"的场景(如超过1年的日志数据):
bash
pt-archiver \
--source h=192.168.12.161,u=dba,p='Id81Gdac_a',D=martin,t=archiver_test \
--dest h=192.168.12.163,u=dba,p='Id81Gdac_a',D=archiver_db,t=archiver_test \
--where '1=1' \
--progress 10000 \
--limit=10000 \
--txn-size=10000 \
--no-safe-auto-increment \
--statistics \
--purge # 核心参数:归档后删除源表数据(替代--no-delete)
2.3 场景3:直接删除原表数据(不归档)
适用于"历史数据无保留价值,仅需清理"的场景(如测试数据、临时日志):
bash
pt-archiver \
--source h=192.168.12.161,u=dba,p='Id81Gdac_a',D=martin,t=archiver_test \
--where '1=1' \ # 可修改条件(如age>50)筛选特定数据删除
--progress 10000 \
--limit=10000 \
--txn-size=10000 \
--no-safe-auto-increment \
--statistics \
--purge # 仅删除源表数据,无需--dest参数
2.4 场景4:按条件归档部分数据
实际业务中最常用的场景(如归档年龄小于30的用户数据、超过30天的日志):
bash
# 1. 先清空归档表(避免重复数据,可选)
mysql -h192.168.12.163 -udba -p'Id81Gdac_a' -e "TRUNCATE TABLE archiver_db.archiver_test;"
# 2. 按条件归档(仅归档age<30的数据,并删除源表对应数据)
pt-archiver \
--source h=192.168.12.161,u=dba,p='Id81Gdac_a',D=martin,t=archiver_test \
--dest h=192.168.12.163,u=dba,p='Id81Gdac_a',D=archiver_db,t=archiver_test \
--where 'age<30' \ # 核心条件:筛选需归档的数据
--progress 10000 \
--limit=10000 \
--txn-size=10000 \
--no-safe-auto-increment \
--statistics \
--purge
2.5 场景5:归档数据到文件(而非数据库)
适用于"数据需长期离线存储"的场景(如归档至CSV文件,备份到云存储):
bash
# 1. 归档为SQL文件(默认格式)
pt-archiver \
--source h=192.168.152.70,u=dba,p='Id81Gdac_a',D=martin,t=archiver_test \
--where 'age<35' \
--progress 10000 \
--limit=10000 \
--txn-size=10000 \
--no-safe-auto-increment \
--statistics \
--purge \
--file=./archiver.sql # 输出文件路径(当前目录)
# 2. 归档为CSV格式(便于Excel分析或导入其他系统)
pt-archiver \
--source h=192.168.152.70,u=dba,p='Id81Gdac_a',D=martin,t=archiver_test \
--where '1=1' \
--progress 10000 \
--limit=10000 \
--txn-size=10000 \
--no-safe-auto-increment \
--statistics \
--purge \
--file=./archiver.csv \
--output-format=csv # 指定输出格式为CSV
三、自动化归档:编写Shell脚本(ChatGPT辅助)
手动执行pt-archiver命令无法满足"定时归档"需求(如每天凌晨归档前一天的日志),可通过Shell脚本封装逻辑,并结合Linux的crontab实现自动化。以下脚本基于ChatGPT辅助生成,适配日志表的定期归档场景。
3.1 步骤1:构造日志表测试环境
假设需归档"超过30天的日志数据",先在原实例和归档实例创建日志表:
原实例(192.168.152.70)创建日志表
sql
USE martin;
CREATE TABLE log_table (
id INT AUTO_INCREMENT PRIMARY KEY,
log_message TEXT NOT NULL COMMENT '日志内容',
log_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '日志时间'
);
-- 插入测试数据(含30天内/外的数据)
INSERT INTO log_table (log_message, log_time) VALUES
('超过30天的日志', '2023-07-01 10:00:00'),
('超过30天的日志1', '2023-07-02 10:00:00'),
('30天内的日志', '2023-08-02 15:30:00'),
('30天内的日志1', '2023-08-03 15:30:00');
归档实例(192.168.152.31)创建日志表
sql
CREATE DATABASE archiver_db;
USE archiver_db;
CREATE TABLE log_table (
id INT AUTO_INCREMENT PRIMARY KEY,
log_message TEXT NOT NULL COMMENT '日志内容',
log_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '日志时间'
);
3.2 步骤2:编写自动化归档脚本
脚本路径建议放在/data/script/下,命名为archiver_log.sh,内容如下:
bash
#!/bin/bash
# 日志表自动化归档脚本(基于pt-archiver)
# 功能:将原实例martin库log_table表中超过30天的数据归档至归档实例archiver_db库
# -------------------------- 1. 配置参数 --------------------------
# 源数据库信息
source_host="192.168.152.70"
source_db="martin"
source_table="log_table"
source_user="dba"
source_password="Id81Gdac_a"
# 归档数据库信息
dest_host="192.168.152.31"
dest_db="archiver_db"
dest_table="log_table"
dest_user="dba"
dest_password="Id81Gdac_a"
# 归档条件:超过30天的数据(依赖MySQL的DATE_SUB函数)
where_clause="log_time < DATE_SUB(NOW(), INTERVAL 30 DAY)"
# 日志输出路径(便于排查问题)
log_file="/var/log/pt_archiver/$(date +%Y%m%d)_archiver.log"
# -------------------------- 2. 初始化日志目录 --------------------------
if [ ! -d "/var/log/pt_archiver" ]; then
mkdir -p /var/log/pt_archiver
chmod 755 /var/log/pt_archiver
fi
# -------------------------- 3. 执行归档操作 --------------------------
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 开始执行归档..." >> $log_file
pt-archiver \
--source h=$source_host,D=$source_db,t=$source_table,u=$source_user,p=$source_password \
--dest h=$dest_host,D=$dest_db,t=$dest_table,u=$dest_user,p=$dest_password \
--where "$where_clause" \
--progress=10000 \ # 每处理10000行输出进度
--bulk-delete \ # 批量删除源表数据(比单条删除更高效)
--limit=1000 \ # 每次批量处理1000行(适配小内存场景)
--commit-each \ # 每处理一批提交一次(避免长事务)
--statistics >> $log_file # 将统计信息写入日志
# -------------------------- 4. 检查执行结果 --------------------------
if [ $? -eq 0 ]; then
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 归档执行成功!" >> $log_file
else
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 归档执行失败!" >> $log_file
exit 1 # 失败时退出,便于crontab告警
fi
3.3 步骤3:脚本权限与验证
-
赋予脚本执行权限:
bashchmod +x /data/script/archiver_log.sh -
手动执行脚本,验证效果:
bash/data/script/archiver_log.sh -
检查归档结果:
- 归档实例查询:
select * from archiver_db.log_table;(应显示2条超过30天的日志) - 原实例查询:
select * from martin.log_table;(仅保留30天内的2条日志) - 日志检查:
cat /var/log/pt_archiver/20230804_archiver.log(查看是否有报错)
- 归档实例查询:
3.4 步骤4:配置crontab定时执行
编辑crontab任务,设置每天凌晨2点执行(低峰期避免影响业务):
bash
# 编辑crontab
crontab -e
# 添加以下内容(每天2:00执行,日志输出到脚本指定路径)
0 2 * * * /data/script/archiver_log.sh
四、注意事项与最佳实践
- 操作前备份:归档/删除前务必备份关键数据,避免条件错误导致数据丢失;
- 测试环境验证:新脚本或命令需先在测试环境验证,确认参数正确后再推广到生产;
- 避免锁表 :批量处理时
--limit和--txn-size不宜过大(建议1000-10000行),防止长事务阻塞业务; - 权限最小化:生产环境中,dba用户权限可缩小至"仅操作源库和归档库",避免全库权限泄露;
- 监控与告警:结合crontab告警(如执行失败发送邮件),定期检查归档日志,确保脚本正常运行。
总结
pt-archiver作为MySQL数据归档的高效工具,通过灵活的参数配置可适配全表归档、条件归档、文件归档等多种场景,而自动化脚本+crontab的组合则能彻底解放手动操作,实现"无人值守"的定期数据清理。掌握本文中的环境搭建、核心用法与自动化流程,可有效解决MySQL历史数据膨胀问题,提升数据库长期运行的稳定性与性能。