MySQLデータベースの複製。前書き

最新の本番システムがデータベースの複製なしで行うことはめったにありません。これは、システムのパフォーマンスと障害耐性を向上させるための強力なツールであり、現代の開発者にとって、少なくともレプリケーションの基本を理解していることが非常に重要です。この記事では、レプリケーションの基本的な知識を共有し、Dockerを使用してMySQLでレプリケーションを設定する方法の簡単な例を示します。



画像



レプリケーションとは何ですか。なぜ必要なのですか。



レプリケーション自体は、オブジェクトの複数のコピーを同期するプロセスを指します。私たちの場合、そのようなオブジェクトはデータベースサーバーであり、データ自体が最大の価値を持っています。2つ以上のサーバーがあり、それらのサーバーで同期されたデータセットを維持する場合は、システムレプリケーションを実装しています。手動オプションcでさえ mysqldump -> mysql load



複製です。



データ複製自体には価値がなく、次のタスクを解決するためのツールにすぎないことを理解する必要があります。



  • データ読み取りパフォーマンスの向上。レプリケーションの助けを借りて、サーバーの複数のコピーを維持し、それらの間で負荷を分散することができます。
  • . , . , .
  • . , , , .
  • . , ( , ), , .
  • . , , .
  • . .


MySQL



レプリケーションプロセスには、マスターサーバー(通常はマスター、マスターと呼ばれます)から1つ以上のスレーブサーバー(スレーブ、 スレーブのデータ変更の伝播が含ま ます特に複数のマスターサーバーを使用する場合は、より複雑な構成もありますが、特定のマスターサーバーでの変更ごとに、残りのマスターが条件付きでスレーブになり、これらの変更を消費します。



一般に、MySQLレプリケーションは次の3つのステップで構成されます。



  1. マスターサーバーは、データの変更をログに書き込みます。このログはバイナリログと呼ばれ、変更はバイナリログイベントと呼ばれます
  2. スレーブは、バイナリログへの変更をリレーログと呼ばれる独自のログにコピーします
  3. スレーブはリレーログからの変更を再生し、それらを自身のデータに適用します。


レプリケーションタイプ



レプリケーションには、基本的に異なる2つのアプローチがあります 。command-by- commandrow-by-rowです。コマンドごとのレプリケーションの場合、データ変更要求(INSERT、UPDATE、DELETE)はマスターログに記録され、スレーブは同じコマンドを正確に再現します。行ごとのレプリケーションでは、ログによってテーブルの行が直接変更され、同じ実際の変更がスレーブに適用されます。



特効薬がないため、これらの方法にはそれぞれ長所と短所があります。コマンドによるレプリケーションは、実装と理解が容易であり、マスターとネットワークの負荷を軽減します。ただし、コマンドごとの複製は、NOW()、RAND()などの非決定論的関数を使用する場合、予測できない影響をもたらす可能性があります。マスターとスレーブ間でデータが同期していないために問題が発生することもあります。実際のデータ変更がキャプチャされて再現されるため、行ごとのレプリケーションにより、より予測可能な結果が得られます。ただし、この方法では、ログ内のすべての変更をログに記録する必要があるマスターサーバー、およびこれらの変更が伝播するネットワークの負荷が大幅に増加する可能性があります。



MySQLは両方のレプリケーション方法をサポートしており、バージョンに応じてデフォルト(推奨される方法と言えます)が変更されました。 MySQL 8のような最新バージョンは、デフォルトで行ベースのレプリケーションを使用します。



レプリケーションアプローチを分割する2番目の原則は 、マスターサーバーの数です。..。 1つのマスターサーバーが存在するということは、彼だけがデータの変更を受け入れることを意味し、変更がすでに多くのスレーブに伝播されている一種のベンチマークです。マスター-マスターレプリケーションの場合、利益と問題の両方が発生します。たとえば、利点の1つは、同じシドニーとヘルシンキからのリモートクライアントに、データベースに変更を書き込む同じように高速な機会を提供できることです。これは、両方のクライアントが同じデータを同時に変更した場合、その変更が最終的なものと見なされ、トランザクションがコミットされ、トランザクションがロールバックされる場合に、主な欠点につながります。



また、一般にマスターレプリケーションマスターが存在しても、システムへのデータ書き込みのパフォーマンスを向上させることはできないことに注意してください。私たちの唯一のマスターが一度に最大1000のリクエストを処理できると想像してみましょう。複製された2番目のマスターを追加すると、「それらの」要求の処理に加えて、2番目のマスターで行われた変更を適用する必要があるため、それぞれで1000個の要求を処理できなくなります。つまり、コマンドごとのレプリケーションの場合、両方に可能な負荷の合計が最も弱いものになり、行ごとのレプリケーションでは、効果を完全に予測することはできません。特定の条件に応じて、正または負のいずれかになります。



MySQLで単純なレプリケーションを構築する例



今こそ、MySQLで簡単なレプリケーション構成を作成するときです。このために、dockerhubのDockerイメージとMySQLイメージ、および ワールドデータベースを使用します



まず、2つのコンテナを起動します。1つは後でマスターとして構成し、もう1つはスレーブとして構成します。彼らがお互いに話すことができるように彼らをネットワーク化しましょう。



docker run -d --name samplereplication-master -e MYSQL_ALLOW_EMPTY_PASSWORD=true -v ~/path/to/world/dump:/docker-entrypoint-initdb.d  mysql:8.0

docker run -d --name samplereplication-slave -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql:8.0

docker network create samplereplication
docker network connect samplereplication samplereplication-master
docker network connect samplereplication samplereplication-slave

      
      





マスターコンテナには、初期ベースの存在をシミュレートするために、world.sqlダンプとのボリューム接続が指定されています。コンテナを作成するとき、mysqlはdocker-entrypoint-initdb.dディレクトリにあるsqlスクリプトをダウンロードして実行します。



構成ファイルを操作するには、テキストエディターが必要です。便利なものなら何でも使えますが、vimが好きです。



docker exec samplereplication-master apt-get update && docker exec samplereplication-master apt-get install -y vim 
docker exec samplereplication-slave apt-get update && docker exec samplereplication-slave apt-get install -y vim

      
      





まず、レプリケーションに使用されるマスターにアカウントを作成しましょう。



docker exec -it samplereplication-master mysql

      
      





mysql> CREATE USER 'replication'@'%';
mysql> GRANT REPLICATION SLAVE ON *.* TO 'replication'@'%';

      
      





次に、マスターサーバーの構成ファイルを変更しましょう。



docker exec -it samplereplication-master bash
~ vi /etc/mysql/my.cnf

      
      





次のパラメータを[mysqld]セクションのmy.cnfファイルに追加する必要があります。



server_id = 1 #     
log_bin = mysql-bin #       

      
      





バイナリログを有効/無効にするには、サーバーを再起動する必要があります。Dockerの場合、コンテナーが再ロードされます。



docker restart samplereplication-master

      
      





バイナリログが有効になっていることを確認してください。ファイル名や位置などの特定の値は異なる場合があります。



mysql> SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 |      156 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

      
      





データ複製を開始するには、スレーブをマスターの状態に「プルアップ」する必要があります。これを行うには、実際のデータのスナップショットを作成するために、ウィザード自体を一時的にブロックする必要があります。



mysql> FLUSH TABLES WITH READ LOCK;

      
      





次に、mysqldumpを使用して、データベースからデータをエクスポートしましょう。もちろん、この例では、同じworld.sqlを使用できますが、より現実的なシナリオに近づきましょう。



docker exec samplereplication-master mysqldump world > /path/to/dump/on/host/world.sql

      
      





その後、SHOW MASTER STATUSコマンドを再度実行し、ファイルと位置の値を記憶または書き留める必要があります。これらは、バイナリログのいわゆる座標です。スレーブを開始するようにさらに指示するのは、それらからです。これで、マスターのロックを再び解除できます。



mysql> UNLOCK TABLES;

      
      





マスターが構成され、他のサーバーに複製する準備ができています。さあ、奴隷に移りましょう。まず、マスターからダンプをロードします。



docker cp /path/to/dump/on/host/world.sql samplereplication-slave:/tmp/world.sql
docker exec -it samplereplication-slave mysql
mysql> CREATE DATABASE `world`;
docker exec -it samplereplication-slave bash
~ mysql world < /tmp/world.sql

      
      





次に、パラメータを追加してスレーブ構成を変更します。



log_bin = mysql-bin  #      
server_id = 2  #   
relay-log = /var/lib/mysql/mysql-relay-bin #    
relay-log-index = /var/lib/mysql/mysql-relay-bin.index  #        
read_only = 1  #     “ ”

      
      





その後、スレーブをリロードします。



docker restart samplereplication-slave

      
      





次に、どのサーバーがマスターになるか、どこからデータの複製を開始するかをスレーブに指示する必要があります。MASTER_LOG_FILEとMASTER_LOG_POSの代わりに、マスターのSHOW MASTERSTATUSから取得した値に置き換える必要があります。これらのパラメータは、まとめてバイナリログ座標と呼ばれます。



mysql> CHANGE MASTER TO MASTER_HOST='samplereplication-master', MASTER_USER='replication', MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=156;

      
      





リレーログの再生を開始して、レプリケーションステータスを確認しましょう。



mysql> START SLAVE;
mysql> SHOW SLAVE STATUS\G

      
      





スレーブステータス
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: samplereplication-master
                  Master_User: replication
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000001
          Read_Master_Log_Pos: 156
               Relay_Log_File: mysql-relay-bin.000002
                Relay_Log_Pos: 324
        Relay_Master_Log_File: mysql-bin.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 156
              Relay_Log_Space: 533
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File:
           Master_SSL_CA_Path:
              Master_SSL_Cert:
            Master_SSL_Cipher:
               Master_SSL_Key:
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 1
                  Master_UUID: c341beb7-3a33-11eb-9440-0242ac110002
             Master_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Master_Retry_Count: 86400
                  Master_Bind:
      Last_IO_Error_Timestamp:
     Last_SQL_Error_Timestamp:
               Master_SSL_Crl:
           Master_SSL_Crlpath:
           Retrieved_Gtid_Set:
            Executed_Gtid_Set:
                Auto_Position: 0
         Replicate_Rewrite_DB:
                 Channel_Name:
           Master_TLS_Version:
       Master_public_key_path:
        Get_master_public_key: 0
            Network_Namespace:
1 row in set, 1 warning (0.00 sec)
      
      







すべてがうまくいけば、あなたのステータスは同じように見えるはずです。ここでの重要なパラメータ:



  • Slave_IO_State-実際には、レプリケーションの状態。
  • Read_Master_Log_Posは、マスターログから読み取られた最後の位置です。
  • Relay_Master_Log_File-現在のマスターログファイル。
  • Seconds_Behind_Master-スレーブはマスターより数秒遅れます。
  • Last_IO_ErrorLast_SQL_Error-レプリケーションエラー(ある場合)。


マスターのデータを変更してみましょう。



docker exec -it samplereplication-master mysql

      
      





mysql> USE world;
mysql> INSERT INTO city (Name, CountryCode, District, Population) VALUES ('Test-Replication', 'ALB', 'Test', 42);

      
      





そして、それらがスレーブに表示されたかどうかを確認します。



docker exec -it samplereplication-slave mysql

      
      





mysql> USE world;
mysql> SELECT * FROM city ORDER BY ID DESC LIMIT 1;
+------+------------------+-------------+----------+------------+
| ID   | Name             | CountryCode | District | Population |
+------+------------------+-------------+----------+------------+
| 4081 | Test-Replication | ALB         | Test     |         42 |
+------+------------------+-------------+----------+------------+
1 row in set (0.00 sec)

      
      





優秀な!入力されたレコードはスレーブにも表示されます。おめでとうございます。これで、最初のMySQLレプリケーションが作成されました。



結論



この記事のフレームワーク内で、レプリケーションプロセスの基本を理解し、このツールの使用法に慣れ、MySQLでレプリケーションの簡単な例を独自に実装できるようになったと思います。複製のトピックとその実用化は非常に広範囲にわたっており、このトピックに興味がある場合は、次の情報源を参考にしてください。





この記事がお役に立てば幸いです。フィードバックやコメントを歓迎します。



All Articles