web-dev-qa-db-ja.com

MySQLレプリケーションスレーブステータスは正常ですが、データに不整合があります

MySQL 5.7を使用しており、マスターサーバーと3台のスレーブサーバーのレプリケーション設定があります。 4台のサーバーはすべて、MySQL専用であり、プライベートネットワーク経由で接続された同じデータセンターに属しています。したがって、レプリケーションのネットワークの問題は最小限に抑える必要があると思います。

そこで、スレーブ1サーバーでSHOW SLAVE STATUS\Gを実行しました。

mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: <removed for anonymity>
                  Master_User: repl
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.004803
          Read_Master_Log_Pos: 885020002
               Relay_Log_File: ubuntu-s-4vcpu-8gb-blr1-slave02-relay-bin.001056
                Relay_Log_Pos: 885020215
        Relay_Master_Log_File: mysql-bin.004803
             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: 885020002
              Relay_Log_Space: 885020495
              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: 103
                  Master_UUID: 78e93502-d3af-11e7-9af0-5aaa686987ef
             Master_Info_File: /var/lib/mysql/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: 
1 row in set (0.00 sec)

それはすべてが問題ないことを明確に述べています。 Zabbix、Packetbeat(Kibana)セットアップなどの監視ツールもかなりあります。また、3つのスレーブサーバーのいずれかでレプリケーションに遅延がある場合にもアラートが表示されます。レプリケーションの問題の可能性についてもアラートを受け取りませんでした。

次に、スレーブ1サーバーでクエリを実行しました。

mysql> select order_id, order_status_id, buyer_invoice_id 
       from oc_suborder where order_id = 62284;
+----------+-----------------+------------------+
| order_id | order_status_id | buyer_invoice_id |
+----------+-----------------+------------------+
|    62284 |               1 |             NULL |
|    62284 |              15 |            76729 |
+----------+-----------------+------------------+
2 rows in set (0.01 sec)

この場合、2つの行が返されますが、これは誤りです。

マスターサーバーで同じクエリを実行しました。

mysql> select order_id, order_status_id, buyer_invoice_id 
       from oc_suborder where order_id = 62284;
+----------+-----------------+------------------+
| order_id | order_status_id | buyer_invoice_id |
+----------+-----------------+------------------+
|    62284 |              15 |            76729 |
+----------+-----------------+------------------+
1 row in set (0.18 sec)

正しいのは1行だけです。そのため、スレーブは間違いなくデータに一貫性がありませんにもかかわらず、スレーブのステータスをOKとして表示しています。

また、マスターでいくつかのDML操作を実行し、それらの変更がスレーブサーバーでレプリケートされました。したがって、レプリケーションが実行されています。私たちはサードパーティのDBAサービスを使用しており、毎回これが発生します。彼らが示唆するのは、スレーブサーバーを再構築することだけです。私たちはすでに100 GB以上のデータを使用しており、このプロセスにはかなりの時間がかかります(過去数か月間に4回実行済みです)。しかし、データの不整合は何度もポップアップし続けます。

私の質問は多様です:

  1. 複数のスキーマ(データベース)にわたって、データの不一致に関連するテーブル/行のみを簡単に特定する方法はありますか。スレーブを再構築する代わりに、これらの特定の行を修正します。私の疑問は、このデータが一致しない複数のテーブルがある可能性があることです。特定のレポートに疑わしいデータが含まれている場合にのみ、これらの不一致が検出されます。

  2. データの不一致が表示される理由として何が考えられますか。スレーブがマスターより0秒遅れている場合でも。上記のクエリの例のテーブルはInnoDBを使用しています。そのテーブルで実行されているトランザクションがいくつかあり、トランザクションがマスターで正常にコミットされているのに、スレーブではコミットされていないときどき

  3. SHOW GLOBAL VARIABLES LIKE 'binlog_format';を使用すると、マスターサーバーではbinlog_formatMIXEDに設定されているのに対し、スレーブサーバーではROWに設定されていることがわかりました。これはこのエラーまたは他のいくつかの未検出エラーの原因になる可能性がありますか?

質問が広すぎる(スタックオーバーフロールールによる)と思われる場合は、ご容赦ください。必要な数の詳細を提供するか、質問を特定の詳細に編集します。私は定期的に Stack Overflowユーザー で、ここに初めて投稿します。どんなポインタでも本当に役に立ちます。

編集#1

すべてのスレーブが読み取り専用= 1で構成されていますか?アプリケーションがスレーブに直接書き込む可能性はありますか?

はい。また、アプリケーションコードには、読み取りと書き込みを分離するための精巧なコードがあります。実際、トランザクション内のすべてのクエリ(START TRANSACTION .. COMMIT/ROLLBACK)は、このブロック内にSELECTクエリがある場合でも、常にマスターサーバーにルーティングされます。レプリケーションラグ(sometimes)をカバーするために、DML操作後の次の2つのSELECTクエリをマスターのみにルーティングします。

万が一スレーブスキップエラーが設定されているスレーブはありますか?もしそうなら、このパラメータの値は何ですか?

以下を見つけてください:

mysql> select @@slave_skip_errors;
+---------------------+
| @@slave_skip_errors |
+---------------------+
| 1032,1062           |
+---------------------+
1 row in set (0.10 sec)

#2を編集

詳細な問題について、マスターとスレーブの両方にSHOW CREATE TABLE oc_suborderを提供してください。

マスターサーバー:

mysql> show create table oc_suborder\G;
*************************** 1. row ***************************
       Table: oc_suborder
Create Table: CREATE TABLE `oc_suborder` (
  `order_id` int(11) NOT NULL,
  `suborder_id` varchar(20) NOT NULL,
  `gst` tinyint(1) NOT NULL DEFAULT '1',
  `buyer_invoice_id` int(11) unsigned DEFAULT NULL,
  `invoice_no` int(11) NOT NULL DEFAULT '0',
  `invoice_date` datetime DEFAULT NULL,
  `invoice_prefix` varchar(26) NOT NULL,
  `shipping_method` varchar(128) NOT NULL,
  `shipping_code` varchar(128) NOT NULL,
  `total` decimal(15,4) DEFAULT NULL,
  `order_status_id` int(11) NOT NULL,
  `date_added` datetime NOT NULL,
  `date_modified` datetime NOT NULL,
  `cform_submit` enum('no_submit','will_submit','submitted','') NOT NULL DEFAULT 'no_submit',
  `cst_with_cform` decimal(15,4) DEFAULT NULL,
  `refundable_cform` decimal(15,4) DEFAULT NULL,
  `refund_status` enum('refunded','not_refunded','not_applicable','') NOT NULL DEFAULT 'not_applicable',
  `courier_partner` varchar(100) DEFAULT NULL,
  `tracking_no` varchar(64) DEFAULT NULL,
  `shipping_charge` decimal(15,2) DEFAULT NULL,
  `custom_totals` text,
  `no_wsb_tape` tinyint(1) NOT NULL DEFAULT '0',
  `no_invoice_with_shipment` tinyint(1) NOT NULL DEFAULT '0',
  `courier_partner_preference` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`suborder_id`),
  UNIQUE KEY `order_id` (`order_id`,`suborder_id`),
  UNIQUE KEY `buyer_invoice_id` (`buyer_invoice_id`),
  KEY `invoice_date` (`invoice_date`),
  KEY `shipping_method` (`shipping_method`),
  KEY `order_status_id` (`order_status_id`),
  KEY `date_added` (`date_added`),
  KEY `tracking_no` (`tracking_no`),
  CONSTRAINT `oc_suborder_order_id_fk` FOREIGN KEY (`order_id`) REFERENCES `oc_order` (`order_id`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.08 sec)

スレーブサーバー:

mysql> show create table oc_suborder\G;
*************************** 1. row ***************************
       Table: oc_suborder
Create Table: CREATE TABLE `oc_suborder` (
  `order_id` int(11) NOT NULL,
  `suborder_id` varchar(20) NOT NULL,
  `gst` tinyint(1) NOT NULL DEFAULT '1',
  `buyer_invoice_id` int(11) unsigned DEFAULT NULL,
  `invoice_no` int(11) NOT NULL DEFAULT '0',
  `invoice_date` datetime DEFAULT NULL,
  `invoice_prefix` varchar(26) NOT NULL,
  `shipping_method` varchar(128) NOT NULL,
  `shipping_code` varchar(128) NOT NULL,
  `total` decimal(15,4) DEFAULT NULL,
  `order_status_id` int(11) NOT NULL,
  `date_added` datetime NOT NULL,
  `date_modified` datetime NOT NULL,
  `cform_submit` enum('no_submit','will_submit','submitted','') NOT NULL DEFAULT 'no_submit',
  `cst_with_cform` decimal(15,4) DEFAULT NULL,
  `refundable_cform` decimal(15,4) DEFAULT NULL,
  `refund_status` enum('refunded','not_refunded','not_applicable','') NOT NULL DEFAULT 'not_applicable',
  `courier_partner` varchar(100) DEFAULT NULL,
  `tracking_no` varchar(64) DEFAULT NULL,
  `shipping_charge` decimal(15,2) DEFAULT NULL,
  `custom_totals` text,
  `no_wsb_tape` tinyint(1) NOT NULL DEFAULT '0',
  `no_invoice_with_shipment` tinyint(1) NOT NULL DEFAULT '0',
  `courier_partner_preference` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`suborder_id`),
  UNIQUE KEY `order_id` (`order_id`,`suborder_id`),
  UNIQUE KEY `buyer_invoice_id` (`buyer_invoice_id`),
  KEY `invoice_date` (`invoice_date`),
  KEY `shipping_method` (`shipping_method`),
  KEY `order_status_id` (`order_status_id`),
  KEY `date_added` (`date_added`),
  KEY `tracking_no` (`tracking_no`),
  CONSTRAINT `oc_suborder_order_id_fk` FOREIGN KEY (`order_id`) REFERENCES `oc_order` (`order_id`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.07 sec)
1
Madhur Bhaiya
  1. pt-table-checksum および pt-table-sync を使用して、マスターとスレーブ間のデータの不一致を修正できます。詳細な参照用のブログ投稿を以下に示します。 https://www.percona.com/blog/2015/08/12/mysql-replication-primer-with-pt-table-checksum-and-pt-table-同期/

  2. 更新がマスターではなくスレーブに直接送信された可能性があります。マスターでsql_log_bin=0を使用することもできます。これは発生する可能性がありますが、read_only=1またはsuper_read_only=1でスレーブを設定することで防止できます。

3
jerichorivera