MySQLインスタンスクラッシュ事例の詳細な分析

MySQLインスタンスクラッシュ事例の詳細な分析

[問題の説明]

私たちの実稼働環境には、複数の MySQL サーバー (MySQL 5.6.21) のクラスターがあり、時々クラッシュします。ただし、エラー ログには再起動情報のみが記録され、クラッシュ スタックは記録されません。

mysqld_safe 現在実行中のプロセス数: 0
mysqld_safe mysqld が再起動しました

次に、システムログ /var/log/message ファイルを確認します。クラッシュ時に他の異常な情報はなく、OOM が原因ではありません。

【トラブルシューティングのアイデア】

ログには貴重な情報が記録されないためです。クラッシュの原因を特定するには、まず MySQL コア ダンプ機能を有効にします。

コア ダンプを有効にする手順は次のとおりです。

1. my.cnfファイルに2つの設定項目を追加します。

[mysqld]

コアファイル

[mysqld_safe]

コアファイルサイズ=無制限

2. システムパラメータを変更し、suid_dumpableを構成する

エコー 1 >/proc/sys/fs/suid_dumpable

3. MySQLサービスを再起動すると設定が有効になります

【問題分析】

コア ダンプを有効にすると、サーバーが再度クラッシュしたときにコア ファイルが生成されます。

gdb を使用して生成されたコア ファイルを分析すると、クラッシュ時のスタック情報を次のように確認できます。


関数table_esms_by_digest::delete_all_rowsから、クラッシュはテーブル events_statements_summary_by_digest の切り捨て操作によってトリガーされたことがわかります。

当社には、1 分あたりの追加、削除、変更、クエリのデータベース アクセス数をカウントするために使用される内部 DML 分析ツールがあります。このツールのデータ ソースは events_statements_summary_by_digest テーブルです。収集プログラムは 1 分ごとにこのテーブルからデータを収集し、収集が完了した後に切り捨て操作を実行します。

このクラスター グループで DML コレクション プログラムを一時停止すると、MySQL がクラッシュしなくなりました。

複数のコア ファイルをさらに分析すると、最終的な関数呼び出しはすべて _lf_pinbox_real_free 関数で発生していることが明らかになりました。

現場環境と合わせて、分析する価値のある場所が 2 つあります。

1. メモリ値が異常です。変数を印刷すると、ここでの変数のアドレスは低く、これは正常ではありません。

(gdb) p ピン->ピンボックス

$2 = (LF_PINBOX *) 0x1367208

2. 赤い部分は、ダイジェスト レコードを 1 つずつ解放する pfs の操作です。データ行を解放するときにエラーが発生しました。

void reset_esms_by_digest()

{

uint インデックス;

if (statements_digest_stat_array == NULL)

戻る;

PFS_thread * スレッド = PFS_thread::get_current_thread();

if (unlikely(thread == NULL))

戻る;

(インデックス = 0; インデックス < digest_max; インデックス++)

{

statements_digest_stat_array[インデックス].reset_index(スレッド);

ステートメントダイジェスト統計配列[インデックス].reset_data();

}

ダイジェストインデックス = 1;

}

エラーの原因としては、次の 2 つが考えられます。

1. 同時実行性が高い場合、メモリアクセスで競合が発生します。

2. 特殊なSQLによりハッシュ処理時にエラーが発生します。

同様の問題をオンラインで検索すると、さらに進展があり、基本的にこの問題はバグによって引き起こされていることが確認されました。

次のMysqlバグレポートでは同様の問題について説明しています。

参考:

環境のより詳細な説明は次のリンクにあります。

https://bugs.launchpad.net/percona-server/+bug/1351148

5.6.35 のバグ修正は、私たちが遭遇した状況と非常に似ていることが判明しました。

_lf_pinbox_real_free の変更と比較すると、この部分は確かに大きな調整が加えられています。

以下は、MySQL 5.6.35 関数 _lf_pinbox_real_free のコード スニペットです。

static void _lf_pinbox_real_free(LF_PINS ピン)

{

LF_PINBOX pinbox= ピン->pinbox;

構造体 st_match_and_save_arg arg = {pins、pinbox、pins->purgatory};

ピン->煉獄 = NULL;

ピン->purgatory_count = 0;

lf_dynarray_iterate(&pinbox->pinarray,

(lf_dynarray_func)match_and_save、&arg);

(arg.old_purgatory) の場合

{

void *last = arg.old_purgatory;

(pnext_node(ピンボックス、最後))

最後 = pnext_node(ピンボックス、最後);

pinbox->free_func(arg.old_purgatory, last, pinbox->free_func_arg);

}

}

以下はMySQL 5.6.21関数_lf_pinbox_real_freeのコードスニペットです。

static void _lf_pinbox_real_free(LF_PINS ピン)

{

int ピン数;

無効リスト;

void **addr = NULL;

void 最初= NULL、最後= NULL;

LF_PINBOX pinbox= ピン->pinbox;

npins = ピンボックス->pins_in_array + 1;

if (pins->stack_ends_here != NULL)

{

int alloca_size = sizeof(void)LF_PINBOX_PINSnpins;

(利用可能なスタックサイズ(&ピンボックス、*ピン->スタック終了位置)>alloca_size)の場合

{

構造体st_harvesterhv;

引数は (void **) alloca(alloca_size);

hv.granary = アドレス;

hv.npins = nピン;

_lf_dynarray_iterate(&ピンボックス->ピン配列,

(lf_dynarray_func) 収穫ピン、 &hv);

npins = hv.granary-addr;

(ピン数)の場合

qsort(addr, npins, sizeof(void *), (qsort_cmp)ptr_cmp);

}

}

同時に、問題のあるクラスターでは、QPS が 6000 未満、Threads_connected が 8000 近くと異常な指標が見られることが確認されました。 (他の高同時実行クラスターと比較すると、QPS は 20,000 を超え、Threads_connected は 300 程度にすぎません)。

アプリケーション側の接続方法を確認したところ、アプリケーションの 1 つに 100 台近くのアプリケーション サーバーがあり、適切な接続の再利用なしに同時にリクエストを開始する可能性があることがわかりました。多数の接続スレッドを維持すると、バグが発生する可能性が高くなります。

修正されたバグの説明は次のとおりです。

qsort 操作のメモリ要件の計算ミスにより、多数の同時サーバー接続がある状況でスタック オーバーフロー エラーが発生する可能性があります。(バグ #73979、バグ #19678930、バグ #23224078)

【解決】

クラッシュ時のコア ファイルを分析し、クラッシュの原因となる条件を特定し、DML コレクション プログラム (テーブル events_statements_summary_by_digest 操作の切り捨て) を一時停止してから再開しました。

後で、これは MySQL のバグであり、MySQL バージョン 5.6.35 で修正されたことがわかりました。このバグは、アプリケーションがデータベースへの接続を大量に確立したときに発生する可能性が高くなります。

要約する

上記はこの記事の全内容です。この記事の内容が皆さんの勉強や仕事に一定の参考学習価値を持つことを願っています。ご質問があれば、メッセージを残してコミュニケーションしてください。123WORDPRESS.COM を応援していただきありがとうございます。

<<:  Centos Docker ブリッジ モードでホスト Redis サービスにアクセスできないというトラブルシューティングの経験

>>:  ロンボク実装 JSR-269

推薦する

Dockerのセキュリティについて Docker-TLS暗号化通信の問題

目次1. Dockerのセキュリティ問題2. Dockerアーキテクチャの欠陥とセキュリティメカニズ...

Ubuntu サーバーで MySQL を設定し、リモート接続を実装する方法

サーバー: Ubuntu Server 16.04 LSSクライアント: Ubuntu 16.04 ...

無料のパブリック STUN サーバー

無料のパブリック STUN サーバーSIP 端末がプライベート IP アドレスを使用する場合、スタン...

Vue3+el-tableは行と列の変換を実現します

目次行と列の変換トランスクリプトの構成を分析するvue3 + el-table で作成されたトランス...

React 非親子コンポーネントパラメータ渡しのサンプルコード

React は、ユーザー インターフェイスを構築するための JavaScript ライブラリです。 ...

Nginx フォワード プロキシとリバース プロキシ、および負荷分散機能の構成コード例

この記事は主に、Nginx のフォワード プロキシとリバース プロキシ、および負荷分散機能の設定コー...

ミニプログラムカスタムタブバーコンポーネントのカプセル化

この記事の例では、ミニプログラムのカスタムタブバーコンポーネントをカプセル化するための具体的なコード...

シェルを使用して複数のサーバーでバッチ操作を実行する方法

目次SSHプロトコルパスワード接続プロセスsshツールssh公開鍵ログインバッチ操作複数サーバーファ...

写真とテキストによる MySQL と sqlyog のインストール チュートリアル

1. MySQL 1.1 MySQLのインストールmysql-5.5.27-winx64 ダウンロー...

HTML テーブル マークアップ チュートリアル (18): テーブル ヘッダー

<br />ヘッダーはテーブルの最初の行を参照します。ヘッダー内のテキストは中央揃えで太...

MySQL 8.0.20 winx64 のインストールと設定方法のグラフィックチュートリアル

この記事では、MySQL 8.0.20 winx64 のインストールと設定方法を次のように説明します...

MySQLオンラインデッドロック分析練習

序文MySQL を学習する際に、MySQL のロック メカニズムについて簡単に理解したことがあると思...

Linux で固定 IP を設定する方法 (テスト済みで効果的)

まず、仮想マシンを開きます xshell5 を開いて仮想マシンに接続します (より便利です。Linu...

MySQL トランザクション自動コミット自動コミット操作

MySQL のデフォルトの動作モードは自動コミット モードです。つまり、明示的にトランザクションを開...

MySQL 8.0.26 のインストールと簡易チュートリアル (インターネット上で最も完全)

目次1. MySQLをダウンロードする1.1 ダウンロード1.2 インストール1. MySQLをダウ...