web-dev-qa-db-ja.com

リモートサーバー上のbinlogファイルを閉じるまたはフラッシュするにはどうすればよいですか

mysqlbinlog --stop-never --read-from-remote-serverフラグを使用して、binlogファイルをセカンダリサーバーに複製しています。プライマリデータベースサーバーが侵害された場合、リモートサーバーでbinlogを再生したいのですが、「現在の」binlogに問題があります。

mysqlbinlogを使用してSQLに変換すると、常に次のようなエラーが発生します。

エラー:Log_event :: read_log_event()のエラー: '読み取りエラー'、data_len:2682、イベント_type:2エラー:オフセット4426095のエントリを読み取れませんでした:ログ形式のエラーまたは読み取りエラー

この問題は、このbinlogファイルがメインデータベースサーバーで閉じられていないか、フラッシュされていないという事実に関連していると思います。メインデータベースサーバーでflush logsを実行した後、ファイルでこの問題は発生しません。

だから、私の質問はこれです:メインデータベースサーバーが危険にさらされ、flush logsを実行できず、リモートサーバーに複製されたbinlogファイルにしかアクセスできない場合。 DB停止イベント時に開いていたbinlogをクリーンアップ、クローズ、またはフラッシュするにはどうすればよいですか?

2
bwizzy

マスターのログをフラッシュすると、ほとんど偶然に問題が解決します。マスターログファイルがローテーションすると、mysqlbinlogは現在のファイルを閉じ、次のファイルを開きます。これにより、バッファリングされたデータが暗黙的にフラッシュされます。

mysqlbinlogをトリガーして、実際のサーバーと同じようにオンデマンドでログをフラッシュすることはできませんが、ファイルを常にフラッシュされた状態に維持するためにトリガーする方法を見つけました。結果を改善するための実行可能な方法。

Oracleが_--raw_オプションをmysqlbinlogに追加した場合、これを_--read-from-remote-server_および_--stop-never_と組み合わせて使用​​すると、マスターのbinlogのリアルタイムバックアップをキャプチャできます。一見明らかなことの少なくともいくつかを見落としていました。

機能の文書化された目的に照らして...

_--raw_オプションを使用して、サーバーのバイナリログのバックアップを作成できます。 _--stop-never_オプションを使用すると、mysqlbinlogがサーバーに接続されたままになるため、バックアップは「ライブ」になります。

https://dev.mysql.com/doc/refman/5.6/en/mysqlbinlog.html#option_mysqlbinlog_raw

... mysqlbinlogが各書き込み後に出力ストリームをフラッシュすることを気にしないことは明確な見落としのようです。

たぶんそれが彼らが「ライブ」を引用符で囲んでいる理由です。 :)

私のテストでは、出荷時にmysqlbinlogが、フラッシュされた可能性のあるぶら下がっているデータをバッファーに残していることを確認していますが、これは修正するのがかなり簡単な問題のようです。

たとえば、2477行目の_mysql-5.6.27/client/mysqlbinlog.cc_のこの小さな変更:

_2477c2477
<         if (my_fwrite(result_file, net->read_pos + 1 , len - 1, MYF(MY_NABP)))
---
>         if (my_fwrite(result_file, net->read_pos + 1 , len - 1, MYF(MY_NABP)) || fflush(result_file))
_

この変更により、mysqlbinlogによって作成されたファイルのサイズは、常に数バイト遅れているように見えるのではなく、_SHOW MASTER STATUS;_によって返されるサイズと常に一致します。私はこのわずかな遅れを常に知っていましたが、それを深く調べたことはありませんでした。もちろん、バッファを継続的にフラッシュすることにはコストがかかりますが、これは「バックアップ」の目的のために交渉の余地のない必要性のように思われます。これはユーザースペースバッファのフラッシュにすぎず、fsync()などではないことに注意してください。したがって、パフォーマンスの点でそれほど異なることはないと思います...そしていずれにしても、マスターに影響を与えるつもりはありません。

論理_||_が使用されるのは、my_fwrite()が成功すると0を返すためです。したがって、fflush()が失敗した場合、短絡してフラッシュを試行せず、いずれかの操作が失敗した場合はエラーになります。 function()] _も、成功すると0を返します。

この変更により、表示される動作が大幅に改善されるはずです。

もちろん、ログはまだ開いていて書き込まれているため、不完全なログになる可能性は常にあります...しかし、トラフィックの少ない環境でこの修正をテストすると、ファイルをホットコピーすると、私にとって使用可能なbinlog-それ以外の場合、同じ環境で、ストックバイナリを使用すると、ファイルの終わりはほとんどの場合不完全になります。

異なるバージョン(5.6以降のみ-この機能は5.6より前にはまったく実装されていませんでした)の場合、ソースの行は異なる可能性がありますが、それでも簡単に見つけることができ、ここに示されている行番号からそれほど遠くありません。

FacebookのMySQL5.6のフォークは、同様ですがより洗練された fix と、フラッシュを少し弱くしますが構成可能にする新しいオプション _--flush-result-file_ を備えています。しかし、現在の形式でコンパイルするのは不必要に難しいと感じたので、上記の小さなパッチを開発しました。


Mysqlbinlogにパッチを適用している限り、別の小さな調整が別の設計の見落としを解決するのに役立つ場合があります。公式ディストリビューションのmysqlbinlogユーティリティには、_--compress_コマンドラインオプションのサポートがありません(ただし、Perconaには 追加する という意味がありました)。

ただし、圧縮を有効にするのも簡単です。私はこの質問に対して上記の修正を思いついたばかりですが、私はかなり長い間、以下の修正を使用しています。

5.6.27のソースから、次のようになります。

_1948c1948
<   if (!mysql_real_connect(mysql, Host, user, pass, 0, port, sock, 0))
---
>   if (!mysql_real_connect(mysql, Host, user, pass, 0, port, sock, CLIENT_COMPRESS))
_

この変更では、_--compress_コマンドラインオプションの受け渡しのサポートは有効になりません。マスターへの接続時に、それをサポートするすべてのマスターに対してクライアント圧縮プロトコルがオンになるだけです(基本的にすべてサポートされます)。ログの転送に必要なネットワーク帯域幅の量を削減します。特定のペイロードによっては、10:1以上になることもあります。生成されたファイルの内容は変更されません。ネットワークを通過するデータの圧縮が可能になるだけです。回線上では、これはマスターの観点から、スレーブサーバーで _slave_compressed_protocol_ を有効にするのと同じ効果があります。 (ドキュメントはあいまいですが、マスターが別のサーバーのスレーブでもない限り、この設定はマスターに影響を与えません。)

2