コメントに対する追加情報

コメントに対する追加情報

当社では、2 年以上にわたって Java システムを実行していますが、システムがハングアップしたことは一度もありません。当社には、クラスターを形成するために、同様の Java ソフトウェアを実行する物理サーバーが 2 台あります (各サーバーに 2 つの JVM)。私の知る限り、クラッシュが発生し始めたのは、サーバーの 1 つで 2 つの JVM 間の共有メモリ アクセス用にコア ピンニングと mapsedbus.io を導入したときだけです。システム ハングアップは 2 週間で 4 回しか発生しておらず、JVM 間のコア ピンニングとメモリ マップ ファイル アクセスを構成したマシンでのみ発生しています。当社はその構成を無効にしているため、メモリ マップ ファイルの読み取り時にコアを固定してスピンさせることはなく、主要なアプリ スレッドを固定することもありません。固定するとは、固定されたコアで実行されているスレッドもビジー スピンさせることです。

ただし、これは完全に逸話的なものです。システムが毎日ハングするわけではないので、コア ピンニングや共有メモリ アクセスと関係があると断言することはできません。ただし、ピンニング (およびビジー スピン) を無効にし、LockSupport.parkNanos(5000) を使用してループで共有メモリにアクセスすると、システムがハングすることはないようです。

レイテンシは私たちにとって非常に重要なので、この「ビジーでない」設定は一時的な回避策にすぎません。

また、アプリケーションを同一のサーバーに移動したところ、システム全体のハングも発生しました。したがって、これがハードウェア障害であるとは考えられません。

クラッシュの前後のログを調べたところ、これが私にとって関連しているようです。これらのスタックはいくつかあります。ここでは最初のものだけを投稿します (つまり、これは postgres 自体とは何の関係もないと思います)

kernel: [25738.874778] INFO: task postgres:2155 blocked for more than 120 seconds.
kernel: [25738.874833]       Not tainted 5.4.0-050400-generic #201911242031
kernel: [25738.874878] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
kernel: [25738.874928] postgres        D    0  2155   2056 0x00004000
kernel: [25738.874931] Call Trace:
kernel: [25738.874942]  __schedule+0x2e3/0x740
kernel: [25738.874948]  ? __wake_up_common_lock+0x8a/0xc0
kernel: [25738.874951]  schedule+0x42/0xb0
kernel: [25738.874957]  jbd2_log_wait_commit+0xaf/0x120
kernel: [25738.874961]  ? wait_woken+0x80/0x80
kernel: [25738.874965]  jbd2_complete_transaction+0x5c/0x90
kernel: [25738.874969]  ext4_sync_file+0x38c/0x3e0
kernel: [25738.874974]  vfs_fsync_range+0x49/0x80
kernel: [25738.874977]  do_fsync+0x3d/0x70
kernel: [25738.874980]  __x64_sys_fsync+0x14/0x20
kernel: [25738.874985]  do_syscall_64+0x57/0x190
kernel: [25738.874991]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
kernel: [25738.874993] RIP: 0033:0x7f96dc24b214
kernel: [25738.875002] Code: Bad RIP value.
kernel: [25738.875003] RSP: 002b:00007fffb2abd868 EFLAGS: 00000246 ORIG_RAX: 000000000000004a
kernel: [25738.875006] RAX: ffffffffffffffda RBX: 00007fffb2abd874 RCX: 00007f96dc24b214
kernel: [25738.875007] RDX: 00005635889ba238 RSI: 00005635889a1490 RDI: 0000000000000003
kernel: [25738.875009] RBP: 00007fffb2abd930 R08: 00005635889a1480 R09: 00007f96cc1e1200
kernel: [25738.875010] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
kernel: [25738.875011] R13: 0000000000000000 R14: 000056358899c5a0 R15: 0000000000000001

ps これは 16.04 およびカーネル 4.15 でも発生しました。18.04 および 5.0 へのアップグレードはシステム ハングの解決を試みたものの、何の変化もありませんでした。

私が検討したもう 1 つの点は、このトレースは単なる症状であり、問​​題ではないかもしれないということです。つまり、私のアプリケーションがサーバーをバインドし、他のプロセスが io でブロックされ、これらのエラーを受信する原因となったのです。しかし、サーバーが完全にフリーズすると、その時点でのアプリケーションの状態を知る方法がありません。

コメントに対する追加情報

まず、繰り返しになりますが、コア ピンニング + 共有メモリが、いわゆる「最後の手段」であるという確固たる証拠はありませんが、変更履歴と停止に基づく私の最善の推測はこれです。

CPU モデルは、Intel(R) Xeon(R) CPU E5-2620 v4 @ 2.10GHz、ターボ ブースト付きです。サーバーにはこの CPU が 2 つあります。CPU 番号 2、4、6 を固定していますが、これらは同じ物理 CPU 上にあると考えられます。ハイパースレッディングはオンです。

セットアップは次のようになります。JVM-A には、メモリ マップ ファイル X に書き込み、メモリ マップ ファイル Y から読み取る固定ビジー スピン スレッドがあります。JVM-B には、メモリ マップ ファイル X から読み取り、メモリ マップ ファイル Y に書き戻す固定ビジー スピン スレッドがあります。JVM-B では、固定読み取りスレッドが、固定ビジー スピン ワーカーを使用して、メッセージをディスラプター リング バッファーに発行します。メッセージは注文指示であり、最終的にこのワーカーで市場に送信されます。これは、低レイテンシの取引プラットフォームです。

この投稿では、LockSupport.parkNanosについてここで説明するよりも詳しく解説しています。https://hazelcast.com/blog/locksupport-parknanos-under-the-hood-and-the-curious-case-of-parking/

組み込み RAID コントローラを使用して RAID 1 で 2 台の 10,000 rpm HDD を使用しています。

ターゲットレイテンシに関しては、理論上は 2 つの JVM を 1 つに統合して、このメモリマップされたファイル チャネルを完全に取り除くことができます。ただし、それを実行する前に他の考慮事項があるため、まずはこの技術的な問題を理解することに重点を置きたいと思います。

最後に、このサーバーの postgres はリカバリ モードでのみ実行されており、プライマリではありません。また、当社のシステムではデータベース IO をほとんど実行していません。実際には、ブートストラップと 1 日の開始にのみ使用され、その日の取引アクティビティを夜間に維持します。クラッシュの 1 つは、データベース IO がほぼゼロだったときに発生しました。

答え1

この場合の「ブロック」は、hung_task_timeout_secsタスクが長い間 D 割り込み不可の状態であったことを意味します。120 秒というのは、I/O を実行するにはかなり異常な時間です。

このホストからメトリックを取得できる監視を開始します。ネットデータはこれに適しています。メモリに毎秒大量のデータが収集されるため、ディスク I/O はそれほど発生しません。また、グラフもきれいです。

などのディスク レイテンシを確認しますiostat -xz 1。1 桁のミリ秒を超える待機時間は適切ではありません。そのストレージが何であるか (スピンドル、ソリッド ステート、SAN LUN) を共有します。

スピニングとピンニングに関しては、スケジューラを強制的にスターブさせているのではないかと思います。問題の CPU モデルと、どのコアを何のためにピンニングしているのかを教えてください。どのようにLockSupport.parkNanos()実装されていますか?

レビューvmstat 1。多くのタスクが常に実行中r または中断できないb状態にあるのは良くありません。

BPF をインストールし、スクリプトを使用してタスク診断を収集することを検討してください。runqslower特定のしきい値を超える待機中のタスクを表示します。非常に高速であることが理想的です。しきい値の単位はマイクロ秒であることに注意してください。


少し立ち止まって、このもののデザインについて考えてみましょう。

レイテンシ目標は正確には何で、何をどのくらいの速さで実行するのでしょうか?

postgres が同じホスト上で実行されている理由はありますか? リモートで TCP 経由でアクセスする場合、その I/O は JVM アプリケーションにとって問題にはなりません。

答え2

結局のところ、問題は非常に単純でした。テスト コードにこの 1 つの要素が欠けていたため、分離されたテストではマシンをクラッシュさせることが一度もありませんでした。問題は共有メモリやコア ピンニング自体にはありません。コアを分離すると、利用可能な共有リソースがわずかに減少し、スケジューラが飢餓状態になる可能性があるというだけです。

両方のJVMは、リアルタイム優先度を使用して設定されました。

sudo renice -n -20 $!
sudo chrt -r -a -p 99 $!

JVM 全体がバンプされたため、合計で約 300 スレッドが最大優先度になりました。CPU 使用率が比較的低い場合でも、コンテキスト スイッチングは 150,000/秒を超えました。

我々は niceness を残し、リアルタイムの変更を削除しました。これで問題は解決したようです。従来の RT 設定の本来の目的は、busyspin/pinning/c-states/p-states などの方法を変更することで達成できます。

関連情報