web-dev-qa-db-ja.com

マスター->スレーブのmysql / percona innodbbinlogの競合状態

外部キーの関係が原因でスレーブに問題を引き起こし、オフラインでノックしている競合状態を診断して回避するのに非常に苦労しています。基本的なmaster -> slave関係でMIXED形式のレプリケーションを使用しています。

したがって、問題のテーブルはtopicsテーブルとstatsテーブルの2つです。トピックテーブルは、新しいトピックがまだ存在しない場合に見つかったときに追加するメンテナンスタスクから生成されます。 2番目のテーブルstatsは、トピックがトレンドになったときとその頻度に関する統計を保持し、基本的に各トピックの1時間ごとの統計を保持します。

新しいトピックが追加されると、競合状態が発生します。 statsテーブルには、topicに関連する外部キーがあります。新しいトピックが追加されると、ブール応答によってINSERTが成功したことが確認されると、最初の「トレンド」カウントを登録するstatsクラスが呼び出されます。

マスターでは、これは期待どおりに機能し、トピックが追加され、最初の統計が登録されます。ただし、スレーブではそうではなく、レプリケーションはエラーをログに記録しています...

Error 'Cannot add or update a child row: a foreign key constraint
fails (`db`.`stats`, CONSTRAINT `stats_primary` FOREIGN KEY (`Topic_ID`)
REFERENCES `topics` (`Topic_ID`) ON DELETE CASCADE ON UPDATE CASCADE)' 
on query.

...これは基本的に、topicsテーブルにはstatsテーブルが参照しようとしているトピックがないことを示しています。

競合状態が発生する理由がまったくわかりません。INSERTは確認を待ってから統計レコードを作成/インクリメントしようとしますなぜbinlogはそうではないのですかステートメントを整理しますか?サニティチェックをあちこちに追加しようとしましたが、マスターに問題はありません何か提案はありますか?


編集1

これが2つのテーブルのスキーマです...

-- ----------------------------
-- Table structure for `history`
-- ----------------------------
DROP TABLE IF EXISTS `history`;
CREATE TABLE `history` (
  `ai_col` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `Topic_ID` char(32) NOT NULL,
  `timestamp` int(10) unsigned NOT NULL,
  `trended` int(10) unsigned NOT NULL DEFAULT '0',
  `viewed` int(10) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`ai_col`),
  UNIQUE KEY `history_primary` (`Topic_ID`,`timestamp`) USING BTREE,
  KEY `history_timestamp` (`timestamp`) USING BTREE,
  KEY `history_trended` (`trended`) USING BTREE,
  KEY `history_viewed` (`viewed`) USING BTREE,
  CONSTRAINT `history_primary` FOREIGN KEY (`Topic_ID`) REFERENCES `topics` (`Topic_ID`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

-- ----------------------------
-- Table structure for `topics`
-- ----------------------------
DROP TABLE IF EXISTS `topics`;
CREATE TABLE `topics` (
  `ai_col` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `Topic_ID` char(32) NOT NULL,
  `terms` varchar(255) NOT NULL,
  `title` varchar(100) DEFAULT NULL,
  `link` varchar(255) DEFAULT NULL,
  `type` enum('event','profile','timeline','general') DEFAULT NULL,
  `event_date` date DEFAULT NULL,
  `description` text,
  `active` tinyint(1) unsigned NOT NULL DEFAULT '1',
  `created` datetime NOT NULL,
  `lastedit` datetime NOT NULL,
  PRIMARY KEY (`ai_col`),
  UNIQUE KEY `topics_topic_id` (`Topic_ID`) USING BTREE,
  KEY `topics_link` (`link`) USING BTREE,
  KEY `topics_title` (`title`) USING BTREE,
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

ここに、この特定のエラーを引き起こした特定の行を含むいくつかのサンプル行がありますが、このエラーは、ログが完全にキャッチされ(0秒遅れ)、新しいデータで発生するとすぐに発生することに注意してください。また、これらはダンプファイルからのものであるため、更新ではなくすべて挿入であることに注意してください。「トレンド」の値が高いことに注意してください)...

INSERT INTO `topics` VALUES ('479410', '827658485a914809b6759d28e6fd7abe', 'd40bad723b2ccc7706bd612760ccd290', '07b2f3037d844db587ebbc5df4685820', 'PC Organics', 'Trending on Twitter,February 2017', 'PC Organics', 'Pc-Organics', 'general', null, 'Stories and events relating to PC Organics', '1', '2017-02-04 11:34:47', '2017-02-04 11:34:47');
INSERT INTO `topics` VALUES ('479411', 'd1fdb23fdf4949ae86441c8ae21573e0', 'd40bad723b2ccc7706bd612760ccd290', '07b2f3037d844db587ebbc5df4685820', 'Tom Lawrence', 'Trending on Twitter,February 2017', 'Tom Lawrence', 'Tom-Lawrence', 'general', null, 'Stories and events relating to Tom Lawrence', '1', '2017-02-04 11:34:47', '2017-02-04 11:34:47');
INSERT INTO `topics` VALUES ('479412', '74180ea91a2542eebcbe596b90311360', 'd40bad723b2ccc7706bd612760ccd290', '07b2f3037d844db587ebbc5df4685820', 'Moore', 'Trending on Twitter,February 2017', 'Moore', 'Moore', 'general', null, 'Stories and events relating to Moore', '1', '2017-02-04 11:34:47', '2017-02-04 11:34:47');

INSERT INTO `history` VALUES ('3647775', '827658485a914809b6759d28e6fd7abe', '1486224000', '4', '0');
INSERT INTO `history` VALUES ('3647776', 'd1fdb23fdf4949ae86441c8ae21573e0', '1486224000', '3', '0');
INSERT INTO `history` VALUES ('3647778', '74180ea91a2542eebcbe596b90311360', '1486224000', '3', '0');

そして、これはmy.cnf ansibleテンプレートファイルであり、共通、マスター、およびスレーブコンポーネントが示されています...

[client]
socket=/mnt/data/mysql.sock

[mysqld]
datadir=/mnt/data/
socket=/mnt/data/mysql.sock
user=mysql
symbolic-links=0
port=3306
bind-address=0.0.0.0
server-id = {{ mysql_db_id }}
skip-name-resolve
character-set-server=utf8
collation-server=utf8_general_ci
explicit_defaults_for_timestamp = 1
ignore-db-dir=lost+found

# Logs
slow_query_log = OFF
#slow_query_log_file=/mnt/data/mysql-slow.log
#long_query_time= 3
log-error=/mnt/data/mysqld.log

# Limits
max_allowed_packet = 256M
tmp-table-size  = 32M
max-heap-table-size = 32M
query-cache-type  = 0
query-cache-size  = 0
max-connections = 1000
thread-cache-size = 50
open-files-limit = 65535
table-definition-cache  = 4096
table-open-cache = 4096

{% if mysql_repl_role == 'master' %}
# Master
log_bin = mysql-bin
log-bin-index = mysql-bin.index
expire_logs_days = 10
max_binlog_size = 100M
max_binlog_files = 50
binlog_do_db = {{ database.name }}
binlog_format = MIXED
{% endif %}

{% if mysql_repl_role == 'slave' %}
# Slave
read_only
relay-log = relay-bin
relay-log-index = relay-bin.index
replicate-ignore-table = "db.sessions"
replicate-ignore-table = "db.cache"
{% endif %}

# INNODB
innodb-flush-method            = O_DIRECT
innodb-log-files-in-group      = 2
innodb-log-file-size           = 256M
innodb-flush-log-at-trx-commit = 1
innodb-file-per-table          = 1
innodb-buffer-pool-size        = {{ innodb_buffer_pool_size }}

# HANDLERSOCKET PLUGIN
loose_handlersocket_port = 9998
loose_handlersocket_port_wr = 9999
loose_handlersocket_threads = 8
loose_handlersocket_threads_wr = 1

[mysqldump]
quick
quote-names
max_allowed_packet = 128M

[mysqld_safe]
log-error=/mnt/data/mysqld.log
pid-file=/mnt/data/mysqld.pid

すべてが正常に開始され、システムの残りの部分は、レプリケーションが適切に行われていれば問題なく存在できます。唯一の問題は、上記の2つのテーブルに関するものであり、200以上のテーブルについて話しているので、ほとんどのテーブルには複数のFK関係があります。レプリケーションの問題があることがわかっているが、まだ何もヒットしていない... ON DUPLICATE KEY UPDATE ...などの非ANSI互換/ MySQL固有のクエリ関数の使用を停止したことを確認しました。


編集2:binlog

上記の外部キーエラーの原因となっている問題のステートメントは次のとおりです...

# at 1403605
#170204 12:05:01 server id 1  end_log_pos 1404039 CRC32 0x8dd8f69e      Query   thread_id=1120  exec_time=0     error_code=0
SET TIMESTAMP=1486227901/*!*/;
BEGIN
/*!*/;
# at 1403692
# at 1403724
#170204 12:05:01 server id 1  end_log_pos 1404071 CRC32 0x116b9b3a      Intvar
SET INSERT_ID=3647784/*!*/;
#170204 12:05:01 server id 1  end_log_pos 1404270 CRC32 0x45ec23e8      Query   thread_id=1120  exec_time=0     error_code=0
SET TIMESTAMP=1486227901/*!*/;
INSERT INTO history SET Topic_ID = '827658485a914809b6759d28e6fd7abe', `timestamp` = 1486227600, trended = 1
/*!*/;
# at 1403923
#170204 12:05:01 server id 1  end_log_pos 1404301 CRC32 0xe396df1e      Xid = 157330
COMMIT/*!*/;

SHOW SLAVE STATUS \Gは以下を示しています(これは上記を指します)...

Relay_Log_File: relay-bin.000003
Relay_Log_Pos: 1403605

要約すると、ここにLast_SQL_Error ..の下にリストされている完全なエラーがあります。

 Last_SQL_Error: Error 'Cannot add or update a child row: a foreign key constraint fails (`db`.`history`, CONSTRAINT `history_primary` FOREIGN KEY (`Topic_ID`) REFERENCES `topics` (`Topic_ID`) ON DELETE CASCADE ON UPDATE CASCADE)' on query. Default database: 'db'. Query: 'INSERT INTO history SET Topic_ID = '827658485a914809b6759d28e6fd7abe', `timestamp` = 1486227600, trended = 1'
2
oucil

したがって、最終的に、@ jynusはOPコメントで、彼らの経験では、このようなレプリケーションの問題は、多くの場合、フィルターとそれらに起因する予期しない動作に起因し、解決策につながったようだと示唆しました...

さまざまな理由でフィルターが必要だったため、フィルターを削除するのではなく、詳細に宣言しようとしました。これにより、replicate-do-dbスレーブ定義でmy.cnfを使用して複製するDBを明示的に宣言することになりました。 replicate-ignore-table宣言の前。

特定のデータベースを削除しないことですべてのデータベースが複製されるため、あまり論理的ではありませんが、ロジックにもかかわらず、これで問題が解決したようです。スレーブは5時間の稼働時間で問題はありません。

何かあったら、関連する情報を追加します。

0
oucil