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回実行済みです)。しかし、データの不整合は何度もポップアップし続けます。
私の質問は多様です:
複数のスキーマ(データベース)にわたって、データの不一致に関連するテーブル/行のみを簡単に特定する方法はありますか。スレーブを再構築する代わりに、これらの特定の行を修正します。私の疑問は、このデータが一致しない複数のテーブルがある可能性があることです。特定のレポートに疑わしいデータが含まれている場合にのみ、これらの不一致が検出されます。
データの不一致が表示される理由として何が考えられますか。スレーブがマスターより0秒遅れている場合でも。上記のクエリの例のテーブルはInnoDBを使用しています。そのテーブルで実行されているトランザクションがいくつかあり、トランザクションがマスターで正常にコミットされているのに、スレーブではコミットされていないときどき。
SHOW GLOBAL VARIABLES LIKE 'binlog_format';
を使用すると、マスターサーバーではbinlog_format
がMIXED
に設定されているのに対し、スレーブサーバーでは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)
pt-table-checksum および pt-table-sync を使用して、マスターとスレーブ間のデータの不一致を修正できます。詳細な参照用のブログ投稿を以下に示します。 https://www.percona.com/blog/2015/08/12/mysql-replication-primer-with-pt-table-checksum-and-pt-table-同期/
更新がマスターではなくスレーブに直接送信された可能性があります。マスターでsql_log_bin=0
を使用することもできます。これは発生する可能性がありますが、read_only=1
またはsuper_read_only=1
でスレーブを設定することで防止できます。