Linux で測位バックグラウンド サービスが時々クラッシュする問題の解決方法

Linux で測位バックグラウンド サービスが時々クラッシュする問題の解決方法

問題の説明

最近のバックグラウンドサービスでは、特定の命令の要求データをディスクに保存する新しい機能が追加されました。具体的な実装では、メンバー変数を使用して要求メッセージ プロキシ ヘッダーを保存します。このヘッダーは、応答が受信され、メッセージ管理クラスが解放されると破棄されます。テストのフィードバックによると、サービスは時々クラッシュするようです。

問題分析

プログラムの rel バージョンはテスト環境で実行されています。コンパイル時にデバッグ情報 (-g) を削除し、O3 レベルの最適化を有効にしたため、クラッシュ ダンプ スタックからはプログラム クラッシュのコール スタックのみが確認できます。関数パラメータは最適化により除去されています。こちらはログがないため、再現するには他の方法しか考えられません。クラッシュの原因はポインタの繰り返し解放によるものと推測されるため、引き続き解析を進めていきます。

relバージョンのコール スタックからは、最後に破棄された関数呼び出ししか確認できません。ただし、実際のコードには、破棄された関数呼び出しエントリが 2 つあります。ダンプに表示されるコール スタックの順序が実際のコードと一致しないのはなぜですか。推測では、O3 最適化が有効になっていて、関数がインライン化されています。

分析のために以下の実験を実施しました。

void test_dump()
{
	int* p = NULL;
	*p = 2; // ダンプ発生
}

void test_f2(int b)
{
	1 です。
	テストダンプ();
}

void test_f1(int a)
{
	1 を 0 にする
	テスト_f2(a);
}

int メイン()
{
 テスト_f1(1);
	0を返します。
}

デバッグ モードと Rel モードでは、クラッシュをトリガーし、gdb を使用して次のようにスタック情報を出力します。

結論: Relモードでは、O3 レベルの最適化により呼び出し関数がインライン化されます。クラッシュ ポイントからトレースバックしたときに複数のエントリ ポイントが存在する場合、 dump情報だけではどのエントリ ポイントがクラッシュを引き起こしたかを確認できません。

テスト環境の構築

コードを分析すると、複数のリリースをトリガーするには、作成と破棄が同時に実行されるシナリオを構築する必要があることがわかります。

作成: テストツールを使用して、特定の指示を高頻度かつ一定の時間に送信し、作成プロセスをトリガーできます。 破棄: スケジュールされたタスクで、無効なステータスを報告して破棄プロセスをトリガーできます。 クラッシュの再現速度を高速化するには、作成速度と破棄速度を適度に一致させる必要があります。 破棄が速すぎると、作成プロセスに入ることができなくなります。分析と実験を経て、最終的にテスト ツールを 50 ミリ秒ごとに送信し、バックグラウンド サービスが 50 ミリ秒ごとに無効なステータスを報告するように設定しました。

クラッシュのアイデアをさらに検証するには、破棄操作などのキーパスにログを追加し、 Relバージョンを起動して再現します。長期間のテストを経て、貴重なクラッシュ ダンプ2対応するログを取得しました。各ダンプの再現には 2.5 時間以上かかるため、この問題は散発的であり、マルチスレッドの競合に関連している可能性が高いことがわかります。問題を再現するには少し時間がかかりますが、取得したダンプとログがあれば問題を特定するのに十分です。

ログ分析

同じバックエンドサービスでも、異なる業務モジュールのログは異なるログファイルに分散しており、分析する際には、全体のプロセスを再現しやすくするために、各部分のログを集約する必要があります。集約中に、必要に応じて各モジュールの最後の数行のログを傍受できます。各ログには正常ログと異常ログが含まれており、これらは 1 つのファイルに集約され、行ごとの相関分析のためにコードと結合されます。

分析プロセス中に、フレームワークに関するいくつかの疑問が生じ、関係する同僚に質問して回答を得ました。現在のメッセージ送受信フレームワークは、メッセージを受信すると、まずメッセージをスレッド プールのメッセージ キューに入れ、セマフォを通じてスレッドを起動し、スレッドはメッセージ キューからメッセージを取得して、メッセージから処理関数を取り出して処理します。
アプリケーション層で異なるメッセージを処理する場合、同じ変数を処理するときに競合状態が発生する可能性があります。解放されたポインタを分析すると、正常に解放されたポインタには一定のルールがあることがわかります。クラッシュが発生すると、解放されたポインタの値は明らかに正常な値と異なります。

体験のまとめ: ダンプ ファイルが見つかった場合は、ダンプ ファイルが生成された時刻を確認し、その時刻のログと実行可能ファイルをダンプ ファイルと一緒に別のフォルダーに保存して、後で分析できるようにします。現在のログ ファイルと実行可能ファイルが削除および更新される可能性があるためです。問題に対するあらゆる解決策は、既存のシステムに対するより深い理解です。再現環境を構築する場合は、Rel バージョンを使用し、ブレークポイントではなくログのみを使用してプログラムフローを確認してください。 Linux ではネストされたミューテックスを使用できないため、設計の目的が達成されず、潜在的なデッドロックを検出するのが難しくなります。エラーは後で発見するよりも、早めに発見する方がよいでしょう。大胆な仮定を立て、それを慎重に検証すれば、やがて勝利の夜明けが訪れるでしょう。

Linux でバックグラウンド サービスが時々クラッシュする問題を解決する方法については、これで終わりです。Linux でバックグラウンド サービスがクラッシュする場所を特定する方法の詳細については、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

<<:  JSONデータをHTMLで表示する方法

>>:  vue3.0 sfcのセットアップの変更について簡単に説明します。

推薦する

無視されたDOCTYPE記述の分析

doctype もその 1 つです。 <!DOCTYPE HTML PUBLIC "...

k8s に ingress-nginx をデプロイする手順

目次序文1. Ingressの展開と構成2. httpsを使用する序文k8sクラスタサービスがデプロ...

docker を使って sonarqube を構築する方法

目次1. Dockerをインストールする2. ソナーイメージをインストールする3. ソナーを使ってコ...

macOS での MySQL 8.0.17 のインストールと簡単な設定チュートリアル

私が書いた内容が理解できない場合は、インターネット上に理解できるチュートリアルがない可能性があります...

Vue+js 矢印をクリックして画像を切り替える

この記事の例では、矢印をクリックして画像を切り替えるVue + jsの具体的なコードを共有しています...

MySQL のテーブル内のレコード数を制限する方法

目次1. トリガーソリューション2. パーティションテーブルソリューション3. 一般的な表領域ソリュ...

DockerコンテナのIPアドレスを取得する方法の詳細な説明

1.コンテナに入った後 /etc/hosts を cat するコンテナ自体の IP アドレスと (-...

ノードを使用して静的ファイルキャッシュを実装する方法

目次キャッシュキャッシュ位置の分類キャッシュ設定ヘッダーNodeは静的ファイルキャッシュを実装する強...

Linux で MySQL をインストールして設定する

システム: Ubuntu 16.04LTS 1\公式サイトからmysql-5.7.18-linux-...

MySQLにインデックスを追加する方法

インデックスの簡単な紹介は次のとおりです。インデックスを追加する目的は、データベース クエリのパフォ...

HTML テーブルタグと関連する改行の問題の詳細な分析

テーブルとは何ですか?テーブルは、データのキャリアである HTML テーブルです。以下は比較的標準的...

CentOS7.5にHarbor1.7をインストールして設定するプロセス全体

1. 必要なパッケージをダウンロードする wget -P /usr/local https://st...

MySQL COUNT関数の使用と最適化

目次COUNT 関数は何をするのですか? MyISAMの「魔法」シンプルなCOUNT最適化近似値を使...

MySQLのルートパスワードをリセットする最も簡単な方法

私の MySQL バージョンは MYSQL V5.7.9 です。古いバージョンを使用してください: ...

Bash スクリプトでの配列メソッドの作成と使用の概要

Bashで配列を定義するbash スクリプトで新しい配列を作成する方法は 2 つあります。 1 つ目...