数据库 2025-07-09 841

利用gh-ost实现无锁表DDL变更

老张

资深系统架构师

在生产环境中执行DDL操作时,锁表问题一直是DBA和开发人员的噩梦。今天我要分享的是如何使用gh-ost工具实现无锁表的DDL变更,这是我最近在生产环境中的实战经验。

gh-ost简介

gh-ost(GitHub's Online Schema Transmogrifier/Transfigurator/Transformer/Thingy)是GitHub开源的一款MySQL在线DDL工具,可以实现无锁表的表结构变更。

工作原理

gh-ost通过以下步骤实现无锁表DDL变更:

  1. 在主库中创建镜像表(_tablename_gho)和心跳表(_tablename_ghc)
  2. 向心跳表中写入DDL进度和时间信息
  3. 在镜像表上执行ALTER操作
  4. 连接到从库获取binlog信息
  5. 从源表拷贝数据到镜像表
  6. 根据binlog同步增量变更
  7. 源表加锁(短暂时间)
  8. 确认数据完全同步
  9. 用镜像表替换源表

安装gh-ost

以Ubuntu系统为例:

wget https://github.com/github/gh-ost/releases/download/v1.1.7/gh-ost_1.1.7_amd64.deb
sudo dpkg -i gh-ost_1.1.7_amd64.deb

验证安装:

gh-ost --version

准备工作

1. 创建测试表

CREATE TABLE w_content (
    id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    content TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

2. 创建专用账号

CREATE USER 'gh-ost_user'@'%' IDENTIFIED BY 'password';
GRANT ALTER, CREATE, DELETE, DROP, INDEX, INSERT, LOCK TABLES, SELECT, TRIGGER, UPDATE ON *.* TO 'gh-ost_user'@'%';
GRANT SUPER, REPLICATION SLAVE ON *.* TO 'gh-ost_user'@'%';
FLUSH PRIVILEGES;

实战演示

我们需要在w_content表中新增一个read_counts字段,记录文章阅读量:

-- 传统方式(会锁表)
ALTER TABLE w_content ADD COLUMN read_counts INT DEFAULT 0;

使用gh-ost实现无锁变更:

gh-ost \
    --max-load=Threads_running=20 \
    --critical-load=Threads_running=50 \
    --critical-load-interval-millis=5000 \
    --allow-on-master \
    --chunk-size=10000 \
    --user="gh-ost_user" \
    --password="password" \
    --host="192.168.5.246" \
    --port=3306 \
    --database="content" \
    --table="w_content" \
    --verbose \
    --alter="ALTER TABLE w_content ADD COLUMN read_counts INT DEFAULT 0;" \
    --assume-rbr \
    --cut-over=default \
    --cut-over-lock-timeout-seconds=3 \
    --dml-batch-size=10 \
    --concurrent-rowcount \
    --default-retries=10 \
    --heartbeat-interval-millis=2000 \
    --max-lag-millis=10000 \
    --timestamp-old-table \
    --initially-drop-socket-file \
    --execute

关键参数说明

参数 说明 示例值
--max-load 当Threads_running超过20时暂停操作 Threads_running=20
--critical-load 当Threads_running超过50时中断操作 Threads_running=50
--chunk-size 每次同步处理的行数 10000
--cut-over 数据同步完成后自动切换表 default
--timestamp-old-table 使用时间戳命名旧表 N/A

执行过程

执行gh-ost后,会在数据库中创建两张临时表:

  1. _w_content_gho:镜像表,用于执行DDL操作
  2. _w_content_ghc:心跳表,记录操作进度

操作完成后,gh-ost会自动清理临时表,并将原表重命名为_w_content_del,新表使用原表名。

注意事项

  • 确保磁盘空间充足,gh-ost会创建表的副本
  • 表必须有主键或非空唯一索引
  • 避免在表名中使用大小写混合
  • 大表操作建议在业务低峰期进行
  • 删除旧表数据时建议分批删除

总结

gh-ost是一款强大的在线DDL工具,可以有效避免锁表问题,特别适合在生产环境中使用。相比传统的ALTER TABLE方式,gh-ost提供了更细粒度的控制和更好的稳定性。

希望这篇文章能帮助大家更好地理解和使用gh-ost,如果有任何问题或建议,欢迎留言讨论。

分享: