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

推薦する

JDKネイティブスレッドプールのバグを修正するTomcatの実装原理

処理能力と同時実行性を向上させるために、Web コンテナは通常、リクエストを処理するタスクをスレッド...

JavaScript オブジェクト指向クラス継承ケースの説明

1. オブジェクト指向のクラス継承これまでの章では、JavaScript のオブジェクト モデルがプ...

Vue3.0 異なる解像度のコンピュータの適応操作

まず依存関係をインストールする必要があります npm i lib-flexible-computer...

Dockerイメージの作成Dockerfileとコミット操作

イメージを構築するイメージを構築するには、主に 2 つの方法があります。実行中のコンテナをイメージに...

最新の MySQL 5.7.23 のインストールと設定のグラフィックチュートリアル

2018 年の最新 MySQL 5.7 の詳細なインストールと設定は 4 つのステップに分かれており...

Meituan DBデータをデータウェアハウスに同期するアーキテクチャと実践

背景データ ウェアハウス モデリングでは、何ら処理されていない元のビジネス レイヤー データは OD...

CentOS6.9 での MySQL 5.7.17 のインストールと設定のチュートリアル

CentOS6.9はMysql5.7をインストールします。参考までに、詳細は次のとおりです。 1. ...

CSS3 アドバンス LESS で星空アニメーションを実装するサンプルコード

この記事では、星空アニメーションを実現するための高度な CSS3 LESS のサンプルコードを次のよ...

画像ファイルの形式とその選択方法

1. どの 3 つの形式ですか?それぞれ、gif、jpg、png です。画像ファイルを最適化すること...

MySQL 外部キー制約の例の説明

MySQL の外部キー制約は、2 つのテーブル間のリンクを確立するために使用されます。 1 つのテー...

htmlハイパーリンクaのクリックイベントの後、hrefで指定されたアドレスにジャンプします。

場合によっては、ジャンプを完了するために href の代わりにハイパーリンク <a> を...

HTML 内の input type="reset" タグが無効 (機能しない) である理由として考えられるもの。

<html:reset> タグを使用すると、リセット ボタンが無効になり、ボタンをクリッ...

CSS の position 属性の値に関する研究 (概要)

CSS の位​​置属性は要素の配置タイプを指定し、上、下、左、右を使用して要素を具体的に配置します...

シンプルで簡単なJavaScript開発のためのSvelte実装原理の詳細な説明

目次デモ1フラグメントの作成スヴェルトコンポーネント状態を変更できるデモSvelte は長い間存在し...

DELL R730 サーバーの構成 RAID とインストール サーバー システムとドメイン制御の詳細なグラフィック チュートリアル

最近、会社で DELL R730 サーバーを購入したのですが、偶然次のチュートリアルを見つけたので、...