MySQLオンラインDDL gh-ostの使用の概要

MySQLオンラインDDL gh-ostの使用の概要

背景:

DBA として、大規模なテーブルの DDL 変更のほとんどは、Percona の pt-online-schema-change を使用して行われます。この記事では、別のツールである gh-ost の使用について説明します。このツールは、スレーブをシミュレートし、行の binlog で増分変更を取得し、それをゴースト テーブルに非同期的に適用するため、トリガーに依存しません。 gh-ost を使用する前に、まず GitHub オープンソース MySQL オンライン スキーマ変更ツール [transfer] の記事または公式 Web サイトを読んで、その機能と原理を理解してください。この記事では使用方法のみを説明します。

例:

1) ダウンロードしてインストールします: https://github.com/github/gh-ost/tags

2) パラメータの説明: gh-ost --help

gh-ost の使用法:
 --aliyun-rds: Alibaba Cloud Database で実行するかどうか。真実
 --allow-master-master: gh-ost をデュアルマスター レプリケーション アーキテクチャで実行できるようにするかどうか。通常は、-assume-master-host パラメータと一緒に使用します。--allow-nullable-unique-key: gh-ost がデータ移行が依存する一意のキーを NULL にすることを許可します。デフォルトでは、NULL 一意のキーは許可されません。データ移行の対象となる一意のキーが NULL 値を許可する場合、不正確なデータが生成される可能性があります。注意して使用してください。
 --allow-on-master: gh-ost がマスター上で直接実行できるようにします。 gh-ost が接続するデフォルトのスレーブ。
 --alter 文字列:DDL ステートメント --approve-renamed-columns ALTER: 列の名前を変更すると、gh-ost はこれを認識し、列名の変更理由を尋ねます。デフォルトでは、--approve-renamed-columns ALTER を指定しない限り、gh-ost は続行しません。
 --ask-pass:MySQL パスワード --assume-master-host 文字列:「ip:port」または「hostname:port」の形式で、gh-ost のマスター データベースを指定します。これは、マスター-マスター アーキテクチャの場合、または gh-ost がマスターを見つけられない場合に役立ちます。
 --assume-rbr: gh-ost が接続されているデータベース インスタンスに binlog_format=ROW が設定されている場合は、-assume-rbr を指定できます。これにより、スレーブ上で stop slave と start slave が実行されなくなり、gh-ost ユーザーは実行に SUPER 権限を必要としなくなります。
 --チェックフラグ
 --chunk-size int: 各反復で処理する行数 (許容範囲: 100-100000)、デフォルト値は 1000 です。
 --concurrent-rowcount: このパラメータが True (デフォルト) の場合、行のコピー後、gh-ost は (explain select count(*) を使用して) 行数を推定し、ETA を調整します。それ以外の場合、gh-ost は最初に行数を推定してから行のコピーを開始します。
 --conf 文字列: gh-ost 構成ファイルのパス。
 --critical-load string: カンマで区切られた status-name=values のリスト。MySQL ステータスが対応する値を超えると、gh-ost は終了します。 -critical-load Threads_connected=20,Connections=1500 は、MySQL のステータス値が Threads_connected>20,Connections>1500 の場合、データベースの重大な負荷により gh-ost が停止して終了することを意味します。
  カンマ区切りの status-name=threshold、--max-load と同じ形式。ステータスがしきい値を超えると、アプリはパニックを起こして終了します。
 --critical-load-hibernate-seconds int : 臨界負荷に達すると、gh-ost は指定された時間休止状態になります。 どのサーバーからも何も読み書きしません。
 --critical-load-interval-millis int: 値が 0 の場合、gh-ost は臨界負荷に達するとすぐに終了します。値が 0 でない場合、gh-ost は -critical-load に達したときに -critical-load-interval-millis 秒後に再度チェックします。2 回目のチェック後も -critical-load に達した場合、gh-ost は終了します。
 --cut-over 文字列: カットオーバー タイプ (アトミック/ツーステップ) を選択します。アトミック (デフォルト) タイプのカットオーバーでは github アルゴリズムが使用され、ツーステップ タイプでは facebook-OSC アルゴリズムが使用されます。
 --カットオーバー指数バックオフ
 --cut-over-lock-timeout-seconds int: gh-ost のカットオーバー フェーズ中の最大ロック待機時間。ロックがタイムアウトすると、gh-ost はカットオーバーを再試行します。 (デフォルト: 3)
 --database 文字列: データベース名。
 --debug: デバッグモード。
 --default-retries int: パニックが発生する前にさまざまな操作を再試行する回数。 (デフォルトは60)
 --discard-foreign-keys: このパラメータは、外部キーを持つテーブル用です。gh-ost がゴースト テーブルを作成する場合、ゴースト テーブルの外部キーは作成されません。このパラメータは外部キーを削除する場合に便利ですが、それ以外の場合は注意して使用してください。
 --dml-batch-size int: 単一トランザクションで DML イベントを適用するためのバッチ サイズ (範囲 1 ~ 100) (デフォルト 10)
 --exact-rowcount: テーブルの行数を正確にカウントし (select count(*) を使用)、より正確な時間を推定します。
 --execute: 実際にテーブルの変更と移行を実行します。デフォルトは noop で、実行しないことを意味します。テストして終了するだけです。ALTER TABLE ステートメントを実際にデータベースに実装したい場合は、-execute を明示的に指定する必要があります。
 --指数バックオフ最大間隔 int
 --force-named-cut-over: true の場合、'unpostpone | cut-over' 対話型コマンドは移行されたテーブルに名前を付ける必要があります --force-table-names 文字列: 一時テーブルで使用するテーブル名のプレフィックス --heartbeat-interval-millis int: gh-ost ハートビートの頻度の値、デフォルトは 500
  - ヘルプ
 --hooks-hint 文字列: GH_OST_HOOKS_HINT を介してフックに挿入される任意のメッセージ --hooks-path 文字列: フック ファイルが保存されるディレクトリ (デフォルトは空、つまりフックは無効)。フックは、このディレクトリ内で同じ命名規則を持つフック ファイルを検索して実行します。
 --host 文字列:MySQL IP/ホスト名
 --initially-drop-ghost-table: gh-ost 操作の前に既存のゴースト テーブルをチェックして削除します。このパラメータは推奨されません。既存のゴースト テーブルを手動で処理してください。デフォルトでは、このパラメータは有効になっていないため、gh-ost は操作を終了します。
 --initially-drop-old-table: gh-ost 操作の前に、既存の古いテーブルをチェックして削除します。このパラメータは推奨されません。既存のゴースト テーブルを手動で処理してください。デフォルトでは、このパラメータは有効になっていないため、gh-ost は操作を終了します。
 --initially-drop-socket-file:gh-ost は既存のソケット ファイルを強制的に削除します。このパラメータは推奨されません。実行中の gh-ost プログラムが削除され、DDL 障害が発生する可能性があります。
 --master-password string:MySQL マスター パスワード --master-user string:MySQL マスター アカウント --max-lag-millis int:マスター スレーブ レプリケーションの最大遅延時間。マスター スレーブ レプリケーションの遅延時間がこの値を超えると、gh-ost はスロットル対策を講じます。デフォルト値: 1500 秒。
 --max-load 文字列: カンマ区切りのステータス名 = しきい値、例: 'Threads_running=100,Threads_connected=500'。ステータスがしきい値を超えると、アプリは書き込みを制限します。
 --migrate-on-replica: gh-ost はマスターではなくレプリカ上で移行を実行します。 
 --nice-ratio float: 各チャンク期間のスリープ時間(範囲は [0.0…100.0])。 0: 各チャンク期間でスリープなし。つまり、1 つのチャンクが次々に実行されます。1: 行コピーごとにさらに 1 ミリ秒スリープします。0.7: 行コピーごとに 10 ミリ秒スリープします。
 --ok-to-drop-table: gh-ost 操作が完了すると、古いテーブルが削除されます。デフォルトでは、古いテーブルは削除されず、_tablename_del テーブルが存在します。
 --panic-flag-file 文字列: このファイルが作成されると、gh-ost は直ちに終了します。
 --password string : MySQL パスワード --port int : MySQL ポート (スレーブが望ましい) --postpone-cut-over-flag-file string : このファイルが存在する場合、gh-ost のカットオーバー フェーズは延期され、ファイルが削除されるまでデータは引き続き複製されます。
 --quiet: 静音モード。
 --replica-server-id uint : gh-ost の server_id
 --replication-lag-query 文字列: 非推奨 --serve-socket-file 文字列: gh-ost のソケット ファイルへの絶対パス。
 --serve-tcp-port int: gh-ost に使用するポート。デフォルトは閉じたポートです。
 --skip-foreign-key-checks: テーブルに外部キーがないことを確認して、gh-ost 検証をスキップする場合は、「true」に設定します。
 --skip-renamed-columns ALTER: 列の名前を変更すると (例: 列の変更)、gh-ost はこれを認識し、列名の変更理由を尋ねます。デフォルトでは、gh-ost はコマンドを続行しません。このパラメータは、gh-ost に列の移行をスキップし、名前が変更された列を don’t care 列として扱うように指示します。この操作は危険です。列内のすべての値が失われます。
 --stack: エラー スタック トレースを追加します。
 --switch-to-rbr: gh-ost に、スレーブ リポジトリの binlog_format を ROW 形式に自動的に切り替えるように指示します。
 --table 文字列: テーブル名 --test-on-replica: スレーブでのデータ移行を含め、スレーブで gh-ost をテストします。データ移行が完了したら、スレーブを停止し、すぐに元のテーブルをゴースト テーブルと交換し、すぐに元に戻します。 2 つのテーブルを比較できるように、スレーブを停止し続けます。
 --test-on-replica-skip-replica-stop: -test-on-replica を実行する場合、このパラメータはプロセス中にスレーブを停止する必要がないことを意味します。
 --throttle-additional-flag-file 文字列: このファイルが作成されると、gh-ost 操作は直ちに停止します。このパラメータは、複数の gh-ost 操作が同時に実行されている場合に、ファイルを作成してすべての gh-ost 操作を停止したり、ファイルを削除してすべての gh-ost 操作を再開したりするために使用できます。
 --throttle-control-replicas 文字列: マスター-スレーブ レプリケーションの遅延を確認する必要があるすべてのスレーブ ライブラリを一覧表示します。
 --throttle-flag-file 文字列: このファイルが作成されると、gh-ost 操作は直ちに停止します。このパラメータは、単一の gh-ost 操作を制御するのに適しています。 -throttle-additional-flag-file 文字列は、複数の gh-ost 操作を制御するのに適しています。
 --throttle-http 文字列
 --throttle-query 文字列: スロットルクエリ。 1 秒ごとに 1 回実行されます。戻り値が 0 の場合、スロットルは必要ありません。戻り値 > 0 の場合、スロットルを実行する必要があります。このクエリは移行されたサーバー上で実行されるため、軽量であることを確認してください。
 --timestamp-old-table: 古いテーブル名にタイムスタンプを使用します。 これにより、古いテーブル名の相互移行が一意になり、競合がなくなります --tungsten: gh-ost に、tungsten レプリケーション トポロジを実行していることを伝えます。
 --user 文字列 :MYSQL ユーザー --verbose
 --バージョン

3) 使用手順: 前提条件として、MySQL 操作に必要な binlog モードが ROW であることが必要です。スレーブでテストする場合は、ROW モードも使用し、log_slave_updates を有効にする必要があります。上記の説明に従って、必要に応じてパラメータを調整します。

環境: マスター ライブラリ: 192.168.163.131; スレーブ ライブラリ: 192.168.163.130

DDL プロセス:

① 外部キーとトリガーがあるか確認します。
②テーブルの主キー情報を確認します。
③ マスターデータベースかスレーブデータベースか、log_slave_updates が有効かどうか、および binlog 情報を確認します ④ gho と del で終わる一時テーブルが存在するかどうかを確認します ⑤ データ移行情報や binlog 情報などを格納するために ghc で終わるテーブルを作成します --- 上記の検証段階 ⑥ ストリーム接続を初期化し、binlog リスニングを追加します --- 次の移行段階 ⑥ gho で終わる一時テーブルを作成し、gho で終わる一時テーブルに対して DDL を実行します ⑦ トランザクションを開始し、プライマリキー ID に従って gho で終わるテーブルにソーステーブルデータを書き込み、送信し、binlog を適用します。
---次の切り替え段階⑧ ソーステーブルをロックし、テーブルの名前を変更します。ソーステーブルの名前をsource_delテーブルに変更し、ghoテーブルの名前をソーステーブルに変更します。
⑨ ghcテーブルをクリーンアップします。

1. 単一インスタンスでの DDL: 単一インスタンスはマスター データベースと同等であり、--allow-on-master パラメータと ROW モードを有効にする必要があります。

gh-ost --user="root" --password="root" --host=192.168.163.131 --database="test" --table="t1" --alter="ADD COLUMN cc2 varchar(10),add column cc3 int not null default 0 comment 'test' " --allow-on-master --execute

2. マスターとスレーブでの DDL:

オプションは 2 つあります。1 つは、手順 1 に従ってマスターからスレーブにデータを直接同期することです。もう 1 つは、スレーブに接続してマスターからデータを移行することです (マスターではなくスレーブの binlog が ROW であることを確認してください)。

gh-ost --user="root" --password="root" --host=192.168.163.130 --database="test" --table="t" --initially-drop-old-table --alter="ADD COLUMN y1 varchar(10),add column y2 int not null default 0 comment 'test' " --execute

このときの操作は、おおよそ次のようになります。

  • 行データはマスターデータベース上で読み書きされます
  • スレーブライブラリのバイナリログを読み取り、マスターライブラリに変更を適用する
  • データベースからテーブル形式、フィールドとインデックス、行数などを収集します
  • リポジトリから内部変更イベント(ハートビートイベントなど)を読み取る
  • メインデータベースのスイッチテーブル

DDL を実行すると、スレーブ データベースはスレーブの停止/開始コマンドを実行します。スレーブの binlog が ROW であることが確実な場合は、パラメータ --assume-rbr を追加できます。スレーブのバイナリログがROWでない場合は、パラメータ--switch-to-rbrを使用してROWに変換できます。このとき、実行後にバイナリログモードが元の値に変換されないことに注意してください。 --assume-rbr パラメータと --switch-to-rbr パラメータを一緒に使用することはできません。

3. スレーブで DDL テストを実行します。

gh-ost --user="root" --password="root" --host=192.168.163.130 --database="test" --table="t" --alter="ADD COLUMN abc1 varchar(10),add column abc2 int not null default 0 comment 'test' " --test-on-replica --switch-to-rbr --execute

パラメータ --test-on-replica: スレーブでのデータ移行、データ移行完了後のスレーブの停止、元のテーブルとゴーストテーブルの即時スワップ、その後即時スワップバックなど、スレーブで gh-ost をテストします。 2 つのテーブルを比較できるように、スレーブを停止し続けます。スレーブを停止したくない場合は、パラメータを追加できます: --test-on-replica-skip-replica-stop

上記の 3 つは gh-ost 操作モードです。上記の操作では、一時テーブルは最後にクリーンアップされないため、手動でクリーンアップする必要があります。次の実行前に一時テーブルがまだ存在する場合、実行は失敗します。パラメータを使用して削除できます。

--initially-drop-ghost-table: gh-ost 操作の前に既存のゴースト テーブルをチェックして削除します。このパラメータは推奨されません。既存のゴースト テーブルを手動で処理してください。デフォルトでは、このパラメータは有効になっていないため、gh-ost は操作を終了します。

--initially-drop-old-table: gh-ost 操作の前に、既存の古いテーブルをチェックして削除します。このパラメータは推奨されません。既存のゴースト テーブルを手動で処理してください。デフォルトでは、このパラメータは有効になっていないため、gh-ost は操作を終了します。

--initially-drop-socket-file:gh-ost は既存のソケット ファイルを強制的に削除します。このパラメータは推奨されません。実行中の gh-ost プログラムが削除され、DDL 障害が発生する可能性があります。

--ok-to-drop-table: gh-ost 操作が完了すると、古いテーブルが削除されます。デフォルトでは、古いテーブルは削除されず、_tablename_del テーブルが存在します。

他にも、--exact-rowcount、--max-lag-millis、--max-load などのパラメータがあります。上記の手順を参照してください。よく使用されるパラメータ コマンドのほとんどは次のようになります。

gh-osc --user= --password= --host= --database= --table= --max-load=Threads_running=30、--chunk-size=1000 --serve-socket-file=/tmp/gh-ost.test.sock --exact-rowcount --allow-on-master/--test-on-replica --initially-drop-ghost-table/--initially-drop-old-table/--initially-drop-socket-file --max-lag-millis= --max-load='Threads_running=100、Threads_connected=500' --ok-to-drop-table

4) 追加指示: 終了、停止、速度制限

gh-ost --user="root" --password="root" --host=192.168.163.131 --database="test" --table="t1" --alter="ADD COLUMN o2 varchar(10),add column o1 int not null default 0 comment 'test' " --exact-rowcount --serve-socket-file=/tmp/gh-ost.t1.sock --panic-flag-file=/tmp/gh-ost.panic.t1.flag --postpone-cut-over-flag-file=/tmp/ghost.postpone.t1.flag --allow-on-master --execute

① 操作を終了するためのフラグファイル: --panic-flag-file

操作を終了するためのファイルを作成します。この例では、実行中の gh-ost を終了するために /tmp/gh-ost.panic.t1.flag ファイルが作成されます。一時ファイルのクリーンアップは手動で行う必要があります。

② 当該ファイルのカットオーバー禁止、つまりテーブル名の切り替えが禁止され、データレプリケーションが正常に行われていることを示します。 --カットオーバーフラグファイルの延期

カットオーバーを遅延する、つまり切り替え操作を延期するためのファイルを作成します。この例では、/tmp/ghost.postpone.t1.flag ファイルが作成されます。gh-ost は行のレプリケーションを完了しますが、テーブルは切り替えません。元のテーブルから一時テーブルへのデータ更新の同期を継続します。

③ソケットを使用してリクエストをリッスンし、オペレーターはコマンドの実行後に対応するパラメータを変更できます。 --serve-socket-file、--serve-tcp-port(デフォルトでは無効)

リスニング用のソケット ファイルを作成し、インターフェイスを介してパラメータを調整します。操作中に負荷と遅延が増加した場合は、操作を終了し、チャンク サイズなどのパラメータを再設定する必要があります。その後、操作コマンドを再実行できます。動的な調整は、ソケット インターフェイスを介して行うことができます。のように:

一時停止操作:

# エコースロットルを一時停止 | socat - /tmp/gh-ost.test.t1.sock
#再開エコー スロットルなし | socat - /tmp/gh-ost.test.t1.sock

速度制限パラメータを変更します。

echo チャンクサイズ=100 | socat - /tmp/gh-ost.t1.sock

エコー最大ラグミリ=200 | socat - /tmp/gh-ost.t1.sock

エコー最大負荷=Thread_running=3 | socat - /tmp/gh-ost.t1.sock

4) pt-online-schema-changeとの比較テスト

1. テーブルが書き込まれておらず、パラメータがデフォルトの場合、2 つの DDL 操作時間はほぼ同じです。結局のところ、どちらも行のコピー操作です。

2. テーブルへの書き込みが多い場合 (sysbench)、pt-osc はマルチスレッドで高速に実行できますが、gh-ost はシングルスレッド アプリケーションをシミュレートします。極端な場合、DDL 操作を完了するのは非常に困難です。

結論: pt-osc はトリガーを必要とせず、メイン データベースの負荷とパフォーマンスへの影響ははるかに少ないですが、高同時実行シナリオでの DDL の効率は依然として pt-osc よりも低いため、ピーク時以外の営業時間中に処理する必要があります。関連するテストについては、gh-ost と pt-osc のパフォーマンス比較を参照してください。

5) カプセル化スクリプト:

環境: M: 192.168.163.131 (ROW)、S: 192.168.163.130/132

ラッパースクリプト: gh-ost.py

#!/bin/env python
# -*- エンコーディング: utf-8 -*-
#----------------------------------------------
# 目的: gh-ost
# 作成日: 2018-06-16
#----------------------------------------------

MySQLdbをインポートする
輸入再
インポートシステム
インポート時間
サブプロセスのインポート
インポートOS
optparse から OptionParser をインポートする

calc_time() を定義します。
 def _deco(*args, **kwargs):
  begin_time = 時間.時間()
  関数(*引数、**キーワード)
  cost_time = time.time() - begin_time
  'コスト時間: %ss' を出力 % round(cost_time,2)
 _decoを返す

def get_table_count(conn,dbname,tbname):
 クエリ = ''' SELECT count(*) FROM %s.%s ''' %(dbname,tbname)
 カーソル = conn.cursor()
 カーソル.execute(クエリ)
 row_nums = カーソル.fetchone()
 カーソルを閉じる()
 接続を閉じる() 
 row_numsを返す

def online_ddl(conn,ddl_cmd):
 カーソル = conn.cursor()
 カーソル.execute(ddl_cmd)
 conn.commit()
 カーソルを閉じる()
 接続を閉じる() 

#@計算時間
def run_cmd(cmd):
 p = サブプロセス.Popen(cmd, シェル=True)
 p,p.pidを返す

def drop_ghost_table(conn, ゴースト名リスト):
 試す:
  カーソル = conn.cursor()
  クエリ = ''' %s が存在する場合はテーブルを削除してください。''' %(ghost_name_list)
  カーソル.execute(クエリ)
  conn.commit()
  カーソルを閉じる()
  接続を閉じる()
 例外を除く、e:
  印刷e

__name__ == "__main__" の場合:
 パーサー = OptionParser()
 parser.add_option("-P", "--Port", help="検索用のポート", dest="ポート")
 parser.add_option("-D", "--Dbname", help="使用するDbname", dest="dbname")
 parser.add_option("-T", "--Table", help="使用するテーブル", dest="テーブル名")

 (オプション、引数) = parser.parse_args()

 そうでない場合、options.port:
  'params port need to apply' を印刷します
  出口()

 そうでない場合、options.dbname:
  'params dbname need to apply' を印刷します
  出口()

 そうでない場合、options.tablename:
  'params tablename need to apply' を印刷します
  出口()

 gh_ost_socket = '/tmp/gh-ost.%s.%s.sock' %(options.dbname,options.tablename)
 #終了フラグ panic_flag = '/tmp/gh-ost.panic.%s.%s.flag' %(options.dbname,options.tablename)
 # postpone_flag = '/tmp/gh-ost.postpone.%s.%s.flag' %(options.dbname,options.tablename)
 #スロットルフラグ throttle_flag = '/tmp/gh-ost.throttle.%s.%s' %(options.dbname,options.tablename)
# ソケット = '/data/%s/tmp/mysql.sock' %(options.port)
 ソケット = '/var/run/mysqld/mysqld.sock'

 

 get_conn = MySQLdb.connect(ホスト='192.168.163.131'、ポート=int(options.port)、ユーザー='root'、パスワード='root'、db=options.dbname、unix_socket=socket、文字セット='utf8')
 conn = MySQLdb.connect(ホスト='192.168.163.131'、ポート=int(options.port)、ユーザー='root'、パスワード='root'、db=options.dbname、unix_socket=socket、文字セット='utf8')
 
 (テーブル数、) = get_table_count(get_conn、オプション.dbname、オプション.tablename)
 print ("\033[0;32m%s\033[0m" % "テーブル数: %s" %table_count)

 DDL_CMD = raw_input('DDL CMDを入力してください: ').replace('`','')

 gh_command_list = re.split('[ ]+',DDL_CMD)
 gh_command_list[0].upper() == 'CHANGE' かつ gh_command_list[1] != gh_command_list[2] の場合:
  print ("\033[0;31m%s\033[0m" % "名前が変更された列のデータは失われます。pt-osc は終了します...")
  出口()

 table_count <= 10000の場合:
  ddl = ''' ALTER TABLE %s %s ''' %(options.tablename,DDL_CMD)
  印刷 ("\033[0;36m%s\033[0m" %ddl)
  print ("\033[0;32m%s\033[0m" % "オンライン DDL ...")
  online_ddl(接続、ddl)
  print ("\033[0;32m%s\033[0m" % "実行が完了しました...")
  出口()

 それ以外:
  MAX_LOAD = raw_input('最大実行スレッド数【25】を入力してください: ')
  MAX_LOADでない場合:
   実行中のスレッド数 = 25 
  それ以外:
   試す:
    実行中のスレッド数 = int(MAX_LOAD)
   ValueErrorを除く:
    print ("\033[0;31m%s\033[0m" % "入力タイプエラー、終了...")
    出口()

  CHUNK_SIZE = raw_input('最大チャンクサイズ【1000】を入力してください: ')
  CHUNK_SIZEでない場合:
   チャンクサイズ = 1000
  それ以外:
   試す:
    チャンクサイズ = int(CHUNK_SIZE)
   ValueErrorを除く:
    print ("\033[0;31m%s\033[0m" % "入力タイプエラー、終了...")
    出口()

  印刷 ("\033[0;32m%s\033[0m" % "gh-ost ddl ...")
  #--カットオーバーフラグファイルを延期する=%s 
  gh_command = '''/usr/bin/gh-ost --user="root" --password="root" --host=192.168.163.131 --port=%s --database="%s" --table="%s" --allow-on-master --max-load='Threads_running=%d' --chunk-size=%d --serve-socket-file=%s --panic-flag-file=%s --throttle-additional-flag-file=%s --alter="%s" --execute ''' %(options.port,options.dbname,options.tablename,Threads_running,chunk_size,gh_ost_socket,panic_flag,throttle_flag,DDL_CMD)
  印刷 ("\033[0;36m%s\033[0m" %gh_command)

 
  子、pid = run_cmd(gh_command)
  print ("\033[0;31mgh-ost の PID: %s\033[0m" %pid)
  print ("\033[0;33mCreate: [touch %s] ファイル、DDL を一時停止 ...\033[0m" %throttle_flag)
  試す:
   子.wait()
  を除外する:
   子.終了()
   #クリーン
   ghost_name_list = '_%s_ghc,_%s_gho' %(options.tablename,options.tablename)
   drop_ghost_table(接続、ゴースト名リスト)
   os.path.exists(gh_ost_socket) が存在する場合:
    os.system('rm -r %s' %gh_ost_socket)
    print ("\033[0;32m%s\033[0m" % "クリーニングが完了しました...")
    出口()
   print ("\033[0;32m%s\033[0m" % "クリーニングが完了しました...")
   出口()
  ついに :
   合格

走る:

ルート@test2:~# python gh-ost.py -P3306 -Dtest -Tzjy
テーブル数: 1310720
DDL CMDを入力してください: ADD COLUMN q1 varchar(10), ADD COLUMN q2 varchar(10)
最大スレッド数【25】を入力してください: 10
最大チャンクサイズ【1000】を入力してください: 200
gh-ost ddl ...
/usr/bin/gh-ost --user="root" --password="root" --host=192.168.163.131 --port=3306 --database="test" --table="zjy" --allow-on-master --max-load='Threads_running=10' --chunk-size=200 --serve-socket-file=/tmp/gh-ost.test.zjy.sock --panic-flag-file=/tmp/gh-ost.panic.test.zjy.flag --throttle-additional-flag-file=/tmp/gh-ost.throttle.test.zjy --alter="ADD COLUMN q1 varchar(10),ADD COLUMN q2 varchar(10)" --execute 
gh-ost の PID: 2105
作成: [touch /tmp/gh-ost.throttle.test.zjy] ファイル、DDL を一時停止...
2018/06/17 14:37:37 binlogsyncer.go:79: [info] 設定 {99999 mysql 192.168.163.131 3306 root false false <nil>} で BinlogSyncer を作成
2018/06/17 14:37:37 binlogsyncer.go:246: [info] 位置 (mysql-bin.000013, 31197930) から binlog の同期を開始します
2018/06/17 14:37:37 binlogsyncer.go:139: [info] マスターサーバー 192.168.163.131:3306 のスレーブを登録
2018/06/17 14:37:37 binlogsyncer.go:573: [情報] (mysql-bin.000013, 31197930) に回転
# `test`.`zjy` を移行しています。ゴースト テーブルは `test`.`_zjy_gho` です。
# test2:3306 を移行中; test2:3306 を検査中; test2 で実行中
# 移行は 2018 年 6 月 17 日日曜日 14:37:37 +0800 に開始されました
# チャンクサイズ: 200; 最大ラグミリ秒: 1500ms; dml バッチサイズ: 10; 最大負荷: Threads_running=10; クリティカル負荷: ; ナイス比: 0.000000
# スロットル追加フラグファイル: /tmp/gh-ost.throttle.test.zjy 
# パニックフラグファイル: /tmp/gh-ost.panic.test.zjy.flag
# Unix ソケットで提供: /tmp/gh-ost.test.zjy.sock
コピー: 0/1305600 0.0%; 適用済み: 0; バックログ: 0/1000; 時間: 0 秒 (合計)、0 秒 (コピー); ストリーマー: mysql-bin.000013:31199542; 状態: 移行中; ETA: N/A
コピー: 0/1305600 0.0%; 適用済み: 0; バックログ: 0/1000; 時間: 1 秒 (合計)、1 秒 (コピー); ストリーマー: mysql-bin.000013:31202866; 状態: 移行中; ETA: N/A
コピー: 44400/1305600 3.4%; 適用済み: 0; バックログ: 0/1000; 時間: 2 秒 (合計)、2 秒 (コピー); ストリーマー: mysql-bin.000013:33352548; 状態: 移行中; ETA: 56 秒
コピー: 91200/1305600 7.0%; 適用済み: 0; バックログ: 0/1000; 時間: 3 秒 (合計)、3 秒 (コピー); ストリーマー: mysql-bin.000013:35598132; 状態: 移行中; ETA: 39 秒
コピー: 135200/1305600 10.4%; 適用済み: 0; バックログ: 0/1000; 時間: 4 秒 (合計)、4 秒 (コピー); ストリーマー: mysql-bin.000013:37727925; 状態: 移行中; ETA: 34 秒
コピー: 174000/1305600 13.3%; 適用済み: 0; バックログ: 0/1000; 時間: 5 秒 (合計)、5 秒 (コピー); ストリーマー: mysql-bin.000013:39588956; 状態: 移行中; ETA: 32 秒
コピー: 212200/1305600 16.3%; 適用済み: 0; バックログ: 0/1000; 時間: 6 秒 (合計)、6 秒 (コピー); ストリーマー: mysql-bin.000013:41430090; 状態: 移行中; ETA: 30 秒
コピー: 254800/1305600 19.5%; 適用済み: 0; バックログ: 0/1000; 時間: 7 秒 (合計)、7 秒 (コピー); ストリーマー: mysql-bin.000013:43483555; 状態: 移行中; ETA: 28 秒
コピー: 303600/1305600 23.3%; 適用済み: 0; バックログ: 0/1000; 時間: 8 秒 (合計)、8 秒 (コピー); ストリーマー: mysql-bin.000013:45834978; 状態: 移行中; ETA: 26 秒
コピー: 351200/1305600 26.9%; 適用済み: 0; バックログ: 0/1000; 時間: 9 秒 (合計)、9 秒 (コピー); ストリーマー: mysql-bin.000013:48128675; 状態: 移行中; ETA: 24 秒
コピー: 401400/1305600 30.7%; 適用済み: 0; バックログ: 0/1000; 時間: 10 秒 (合計)、10 秒 (コピー); ストリーマー: mysql-bin.000013:50547454; 状態: 移行中; ETA: 22 秒
コピー: 451200/1305600 34.6%; 適用済み: 0; バックログ: 0/1000; 時間: 11 秒 (合計)、11 秒 (コピー); ストリーマー: mysql-bin.000013:52946991; 状態: 移行中; ETA: 20 秒
コピー: 490000/1305600 37.5%; 適用済み: 0; バックログ: 0/1000; 時間: 12 秒 (合計)、12 秒 (コピー); ストリーマー: mysql-bin.000013:54817320; 状態: 移行中; ETA: 19 秒
コピー: 529600/1305600 40.6%; 適用済み: 0; バックログ: 0/1000; 時間: 13 秒 (合計)、13 秒 (コピー); ストリーマー: mysql-bin.000013:56735431; 状態: 移行中; ETA: 19 秒
コピー: 589200/1305600 45.1%; 適用済み: 0; バックログ: 0/1000; 時間: 14 秒 (合計)、14 秒 (コピー); ストリーマー: mysql-bin.000013:59606450; 状態: 移行中; ETA: 17 秒
コピー: 639400/1305600 49.0%; 適用済み: 0; バックログ: 0/1000; 時間: 15 秒 (合計)、15 秒 (コピー); ストリーマー: mysql-bin.000013:62025561; 状態: 移行中; ETA: 15 秒
コピー: 695200/1305600 53.2%; 適用済み: 0; バックログ: 0/1000; 時間: 16 秒 (合計)、16 秒 (コピー); ストリーマー: mysql-bin.000013:64704138; 状態: 移行中; ETA: 14 秒
コピー: 751200/1305600 57.5%; 適用済み: 0; バックログ: 0/1000; 時間: 17 秒 (合計)、17 秒 (コピー); ストリーマー: mysql-bin.000013:67401961; 状態: 移行中; ETA: 12 秒
コピー: 803800/1305600 61.6%; 適用済み: 0; バックログ: 0/1000; 時間: 18 秒 (合計)、18 秒 (コピー); ストリーマー: mysql-bin.000013:69935884; 状態: 移行中; ETA: 11 秒
コピー: 856400/1305600 65.6%; 適用済み: 0; バックログ: 0/1000; 時間: 19 秒 (合計)、19 秒 (コピー); ストリーマー: mysql-bin.000013:72470455; 状態: 移行中; ETA: 9 秒
コピー: 907400/1305600 69.5%; 適用済み: 0; バックログ: 0/1000; 時間: 20 秒 (合計)、20 秒 (コピー); ストリーマー: mysql-bin.000013:74927401; 状態: 移行中; ETA: 8 秒
コピー: 958800/1305600 73.4%; 適用済み: 0; バックログ: 0/1000; 時間: 21 秒 (合計)、21 秒 (コピー); ストリーマー: mysql-bin.000013:77404243; 状態: 移行中; ETA: 7 秒
コピー: 999200/1305600 76.5%; 適用済み: 0; バックログ: 0/1000; 時間: 22 秒 (合計)、22 秒 (コピー); ストリーマー: mysql-bin.000013:79351223; 状態: 移行中; ETA: 6 秒
コピー: 1009600/1305600 77.3%; 適用済み: 0; バックログ: 0/1000; 時間: 23 秒 (合計)、23 秒 (コピー); ストリーマー: mysql-bin.000013:79855229; 状態: 移行中; ETA: 6 秒
コピー: 1059600/1305600 81.2%; 適用済み: 0; バックログ: 0/1000; 時間: 24 秒 (合計)、24 秒 (コピー); ストリーマー: mysql-bin.000013:82264712; 状態: 移行中; ETA: 5 秒
コピー: 1107200/1305600 84.8%; 適用済み: 0; バックログ: 0/1000; 時間: 25 秒 (合計)、25 秒 (コピー); ストリーマー: mysql-bin.000013:84558411; 状態: 移行中; ETA: 4 秒
コピー: 1147000/1305600 87.9%; 適用済み: 0; バックログ: 0/1000; 時間: 26 秒 (合計)、26 秒 (コピー); ストリーマー: mysql-bin.000013:86486148; 状態: 移行中; ETA: 3 秒
コピー: 1198000/1305600 91.8%; 適用済み: 0; バックログ: 0/1000; 時間: 27 秒 (合計)、27 秒 (コピー); ストリーマー: mysql-bin.000013:88943747; 状態: 移行中; ETA: 2 秒
コピー: 1245400/1305600 95.4%; 適用済み: 0; バックログ: 0/1000; 時間: 28 秒 (合計)、28 秒 (コピー); ストリーマー: mysql-bin.000013:91218202; 状態: 移行中; ETA: 1 秒
コピー: 1286600/1305600 98.5%; 適用済み: 0; バックログ: 0/1000; 時間: 29 秒 (合計)、29 秒 (コピー); ストリーマー: mysql-bin.000013:93203991; 状態: 移行中; ETA: 0 秒
コピー: 1310720/1310720 100.0%; 適用済み: 0; バックログ: 0/1000; 時間: 29 秒 (合計)、29 秒 (コピー); ストリーマー: mysql-bin.000013:94366846; 状態: 移行中; ETA: 予定
コピー: 1310720/1310720 100.0%; 適用済み: 0; バックログ: 1/1000; 時間: 30 秒 (合計)、29 秒 (コピー); ストリーマー: mysql-bin.000013:94369042; 状態: 移行中; ETA: 予定
# `test`.`zjy` を移行しています。ゴースト テーブルは `test`.`_zjy_gho` です。
# test2:3306 を移行中; test2:3306 を検査中; test2 で実行中
# 移行は 2018 年 6 月 17 日日曜日 14:37:37 +0800 に開始されました
# チャンクサイズ: 200; 最大ラグミリ秒: 1500ms; dml バッチサイズ: 10; 最大負荷: Threads_running=10; クリティカル負荷: ; ナイス比: 0.000000
# スロットル追加フラグファイル: /tmp/gh-ost.throttle.test.zjy 
# パニックフラグファイル: /tmp/gh-ost.panic.test.zjy.flag
# Unix ソケットで提供: /tmp/gh-ost.test.zjy.sock
コピー: 1310720/1310720 100.0%; 適用済み: 0; バックログ: 0/1000; 時間: 30 秒 (合計)、29 秒 (コピー); ストリーマー: mysql-bin.000013:94371928; 状態: 移行中; ETA: 予定
2018/06/17 14:38:08 binlogsyncer.go:107: [info] syncer を終了しています... 
2018/06/17 14:38:08 binlogstreamer.go:47: [エラー] 同期を終了しました。エラー: 同期が終了しています... (ここでのエラーは使用には影響しません。同期は繰り返し終了しており、作者が修正するのを待っています)
2018/06/17 14:38:08 binlogsyncer.go:122: [情報] syncer は閉じられています 
# 終わり

要約:

gh-ost はトリガーを放棄し、同期に binlog を使用します。偽のスレーブ データベースとして、gh-ost はマスター/スレーブ データベースからバイナリ ログを取得し、フィルター処理して、マスター データベースに再適用できます。これは、バイナリ ログを介してマスター データベースの増分操作をマスター データベース自体に適用することと同じですが、ゴースト テーブルに適用されます。

gh-ost は最初にマスターに接続し、alter ステートメントに基づいてゴースト テーブルを作成し、次に実際のスレーブの 1 つに「スレーブ」として接続し、マスター上の既存のデータをゴースト テーブルにコピーし、スレーブから増分データの binlog を取得して、binlog をマスターに継続的に適用します。図のカットオーバーは最後のステップで、マスター データベースのソース テーブルをロックし、binlog が適用されるまで待機してから、gh-ost テーブルをソース テーブルに置き換えます。実行中、gh-ost は、プロセス全体の進行を制御したり、ステータスを検出したりするために、次のヒントとハートビート パケットを元の binlog イベントに追加します。このアーキテクチャには、次のような多くの利点があります。

  • プロセス全体は非同期で実行されるため、ソース テーブルでの増分データ操作に追加のオーバーヘッドは発生せず、ピーク時のビジネスの変更がパフォーマンスに及ぼす影響はほとんどありません。
  • 書き込み負荷を軽減するために、トリガー操作はすべて 1 つのトランザクションにまとめられ、gh-ost は別の接続で binlog を適用します。
  • 停止することができます。Binlog には位置記録があります。変更処理中にメインデータベースのパフォーマンスに影響があることが判明した場合は、すぐに binlog の取得を停止し、binlog の適用を停止し、安定した後に適用を続行することができます。
  • gh-ost は、スレーブ データベースに接続してオンライン DDL を直接実行できるテスト機能を提供します。プライマリ データベースで操作する前に、スレーブ データベースで変更結果が正しいかどうかを確認できます。

以下もご興味があるかもしれません:
  • MySQL 8.0 で列を素早く追加する方法
  • MySQLオンラインDDLの使用に関する詳細な説明
  • MySQL DDL による同期遅延を解決する方法
  • MySQL 8.0 アトミック DDL 構文の詳細な説明
  • MySQL オンライン DDL ツール gh-ost 原理分析
  • MySQL DDLステートメントの使用
  • 一般的なMysql DDL操作の概要
  • MySQL 8.0 の新機能の分析 - トランザクション データ ディクショナリとアトミック DDL
  • MySQL データ定義言語 DDL の基本ステートメント
  • MySQL 8.0 DDLアトミック機能と実装原則
  • MySQL 5.7 でブロックポジショニング DDL の問題を解決する
  • MySQL 8.0 の新機能: アトミック DDL ステートメントのサポート
  • MySQL がユーザー名とパスワードの漏洩を引き起こす可能性のある Riddle の脆弱性を公開
  • MySQL 8.0 オンライン DDL クイック列追加の概要

<<:  CentOS8 jdk8 / java8 のインストールチュートリアル(推奨)

>>:  React 高階コンポーネント HOC 使用方法の概要

推薦する

Linuxのseqコマンドを使用して数字のシーケンスを生成します(推奨)

Linux の seq コマンドは、数字のリストを非常に高速に生成でき、使いやすく柔軟性に優れてい...

コンテナDockerCommitを介してイメージを送信し、DockerPushでイメージをプッシュします。

ローカルでコンテナを作成した後、このコンテナに基づいてローカル イメージを作成し、このイメージを D...

MySQLアカウントのパスワード変更方法(概要)

序文:データベースを日常的に使用すると、パスワードが単純すぎて変更する必要がある場合、パスワードの有...

Centos8 で Apache httpd2.4.37 を使用して Web サーバーをインストールする詳細な手順

ステップ 1: yum install httpd -y #httpd サービスをインストールします...

VMware + Ubuntu18.04 による Hadoop クラスタ環境の構築に関するグラフィック チュートリアル

目次序文VMware クローン仮想マシン (準備、3 台の仮想マシンのクローン、1 台のマスター、2...

ウェブサイト上のWeiboコンポーネントの再設計の詳細な紹介(写真とテキスト)

前面に書かれたWeibo コンポーネントは、サードパーティのアクセス ユーザーが開発を必要とせずに ...

Zabbixで監視する必要があるホストを追加するための詳細な手順

監視ホストの追加ホスト 192.168.179.104 が zabbix 監視項目に追加されます (...

Vue-CLI マルチページディレクトリパッケージ化手順の記録

ページディレクトリ構造 デフォルトの HTML テンプレート ファイル public/index.h...

mysql.data.dll ドライバーのさまざまなバージョンの簡単な分析

ここにmysqlドライバmysql.data.dllがあります知らせ:ここではX86バージョンが多く...

レンダリング関数と JSX の詳細

目次1. 基本2. ノード、ツリー、仮想DOM 1. 仮想DOM 3. createElementパ...

MySQLスローログクエリの詳細な説明

遅いログクエリ機能スロー ログ クエリの主な機能は、設定された時間しきい値を超える SQL ステート...

ダッシュボードを実装するためのjQueryプラグイン

jQueryプラグインは、参考のためにダッシュボードを実装します。具体的な内容は次のとおりです。一般...

Linux FTP匿名アップロードとダウンロードが自動的に開始される問題を解決する

勉強や仕事で FTP サーバーを頻繁に使用する場合は、起動時に自動的に起動するように設定できます。設...

CSSリストのスライドにより、下部に隠れるのを防ぎ、長い画面モデルの処理に適応します。

1. モバイル端末がリストスライドを処理するとき、WeChat には下部にページに戻るボタンが組み...