1746625471
2025-05-07 11:03:00
まず第一に、私はこれをこのブログへの別れの投稿にしたいと思います。私の雇用主がgeneしみなく後援するこのブログをホストしているVMは廃止されています。私はブログを移動するためのいくつかの選択肢を見ましたが、時間/努力/コストの観点から興味深いものはありません。私の人生ですべてのことが起こっているので、新しいブログを設定することは優先順位ではありません(最近、驚き、驚き、トマト)。私たちは良い走りをしました、そして、私はこのブログがあなたにとって有用であることを願っています、ある方法である方法です。そして、私はまた、いつかまたお会いしたいと思っています。
ビジネスに戻る。今日のトピックは、geta-notfoundlerの非常に致命的な欠陥であり、それはで開かれたソースです Github – geta/geta-notfoundhandler:asp.netコアとオプティマイズリーの人気のないハンドラーは、もはや機能しない古いURLのリダイレクトを許可することに加えて、404ページをより適切に制御できます。。顧客のインスタンスが非常に高いCPUに当たった場合、本質的にぶら下がっている場合があり、唯一の行動方針はインスタンスを再起動することです。当時撮影されたメモリダンプは、具体的には、すべてのものを指し示しています。 CustomRedirectCollectionこの問題は、数ヶ月前に同僚によって私にもたらされました。彼がそれをローキーとして扱ったとき、私たちはそれをすばやく調べ、いくつかの良いアイデアを持っていましたが、私たちは実際にその底にたどり着きませんでした。それは批判的に緊急/重要ではなかったので、私はそれを滑らせました(そして、あなたはそれが何かが対処されないときであることを知っています)。
別の同僚が最近再びそれを育て、私が長期にわたるインフルエンザから悪い頭痛に苦しんでいたとき、私はこれをやり直すことにしました。結論と修正にジャンプする前に、症状と分析から始めましょう。
上記のように、撮影したメモリダンプでは、このスタックトレースに1つまたは2つのスレッドが詰まっているのを見てきました
00007E69D57E67F0 00007e6c3bded5c3 Geta.NotFoundHandler.Core.Redirects.CustomRedirectCollection.CreateSubSegmentRedirect(System.ReadOnlySpan`1, System.ReadOnlySpan`1, Geta.NotFoundHandler.Core.Redirects.CustomRedirect, System.ReadOnlySpan`1)
00007E69D57E6880 00007e6c3a47ea43 Geta.NotFoundHandler.Core.Redirects.CustomRedirectCollection.FindInternal(System.String)
00007E69D57E6920 00007e6c3c1e2be5 Geta.NotFoundHandler.Core.Redirects.CustomRedirectCollection.Find(System.Uri)
00007E69D57E6950 00007e6c3c1e2a19 Geta.NotFoundHandler.Core.RequestHandler.HandleRequest(System.Uri, System.Uri, Geta.NotFoundHandler.Core.Redirects.CustomRedirect ByRef)
00007E69D57E6990 00007e6c3bd326f7 Geta.NotFoundHandler.Core.RequestHandler.Handle(Microsoft.AspNetCore.Http.HttpContext)
00007E69D57E69E0 00007e6c3bc9f9ba Geta.NotFoundHandler.Infrastructure.Initialization.NotFoundHandlerMiddleware+d__2.MoveNext()
00007E69D57E6A40 00007e6c3bce9418 System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[Geta.NotFoundHandler.Infrastructure.Initialization.NotFoundHandlerMiddleware+d__2, Geta.NotFoundHandler]](d__2 ByRef) [/_/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncMethodBuilderCore.cs @ 38]
00007E69D57E6A90 00007e6c3bce9360 Geta.NotFoundHandler.Infrastructure.Initialization.NotFoundHandlerMiddleware.InvokeAsync(Microsoft.AspNetCore.Http.HttpContext, Geta.NotFoundHandler.Core.RequestHandler)
同じスタックトレースに詰まったスレッドがたくさんある場合は、ロックの競合について考えることができます。つまり、ロックがリリースされるのを待っているだけのスレッドがたくさんあります。しかし、高いCPUの場合にいくつかのスレッドしかない場合、それは無限のループを示唆しています、いくつか do while または while 適切に終了しないコード。
無限のループの非常に悪名高いケースの1つは、同時シナリオで辞書を台無しにしたとき、他のスレッドが読んでいる間にそれを追加することです。それはあなたのforeachが決して終わらないときです。
しかし、どこに?
幸いなことに、ライブラリはオープンソースであるため、ドライコードの読み取りを試して、問題がどこにあるかを推測する方がはるかに簡単です。そしてもちろん、私たちは見つけました while ループ
// Note: Guard against infinite buildup of redirects
while (appendSegment.UrlPathMatch(oldPath))
{
appendSegment = appendSegment[oldPath.Length..];
}
残っている唯一の質問は、どのような価値です oldPath その無限のループをトリガーします。私と同じように怠zyで、私はコピーロットに頼ってコードを分析して、潜在的に犯人になる可能性のある値を確認しました。何とか何とか、副操縦士はようなことを言います /abc/abc/abc/ できた。しかし、そうではありません。 (私たちはまだ仕事を失うことからAI、人々に長い道のりです)
それが私の最初の婚約の停止です。別の同僚が私に同じ質問をするまで、私はそれをほとんど忘れていました。今回はもっと深刻です。とにかく頭痛のためにあまり生産的ではなかったので、この問題を完全に修正しましょう。
そのため、新しいメモリダンプを使用して、問題に再び飛び込みました。不快なスレッドを特定した後、実行しましょう !clrstack -p 問題をトリガーするURLを把握できるかどうかを確認します。これは本当に私の眉を上げました
0:026> !do 0x00007e69dcd8bb60
Name: Geta.NotFoundHandler.Core.Redirects.CustomRedirect
MethodTable: 00007e6c35be3ff8
EEClass: 00007e6c35bd30f0
Tracked Type: false
Size: 72(0x48) bytes
File: /app/Geta.NotFoundHandler.dll
Fields:
MT Field Offset Type VT Attr Value Name
00007e6c2ff0bac0 4000059 20 System.Boolean 1 instance 0 k__BackingField
00007e6c2ffbd2e0 400005a 8 System.String 0 instance 00007e6ad7fff3a0 _oldUrl
00007e6c2ffbd2e0 400005b 10 System.String 0 instance 00007e6ad7fff3a0 k__BackingField
00007e6c2ffa9018 400005c 18 System.Int32 1 instance 0 k__BackingField
00007e6c35bcf8f0 400005d 1c System.Int32 1 instance 302 k__BackingField
00007e6c3372f578 400005e 28 ...Private.CoreLib]] 1 instance 00007e69dcd8bb88 k__BackingField
0:026> !DumpObj /d 00007e6ad7fff3a0
Name: System.String
MethodTable: 00007e6c2ffbd2e0
EEClass: 00007e6c2ff97b10
Tracked Type: false
Size: 22(0x16) bytes
File: /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.36/System.Private.CoreLib.dll
String:
Fields:
MT Field Offset Type VT Attr Value Name
00007e6c2ffa9018 40002ba 8 System.Int32 1 instance 0 _stringLength
00007e6c2ff0e5a8 40002bb c System.Char 1 instance 0 _firstChar
00007e6c2ffbd2e0 40002b9 d0 System.String 0 static 00007e6ad7fff3a0 Empty
oldUrl ここでは空です。そして驚いたことに、空の価値を渡します while 上記のループは、実際にそれをだまして、決して終わらないようにします。問題を実証するための簡単なプログラム
var appendSegment = ReadOnlySpan.Empty;
var oldPath = "".AsSpan();
while (appendSegment.UrlPathMatch(oldPath))
{
appendSegment = appendSegment[oldPath.Length..];
}
internal static class SpanExtensions
{
public static ReadOnlySpan RemoveTrailingSlash(this ReadOnlySpan chars)
{
if (chars.EndsWith("/"))
return chars[..^1];
return chars;
}
public static bool UrlPathMatch(this ReadOnlySpan path, ReadOnlySpan otherPath)
{
otherPath = RemoveTrailingSlash(otherPath);
if (path.Length
問題は、セーフガードがあったことです null 価値はありませんが、そうではありません Empty。したがって、問題をトリガーするには、空のオールダルを持つカスタムリダイレクトルールが必要です。2。 url それは定義された他のルールと一致しません。
空のルールに達したら、それは死刑判決です。 while ループは終了せず、インスタンスが再起動されるまですべてのCPUリソースを食べます。
この場合の修正は、を確認することです oldUrl 両方のために null そして Empty。プロジェクトでパッケージを使用している場合、これは必要な変更です
たぶん誰かがこれを取り、私がトマトに参加するのに忙しいとき、誰もがメインのレポを貢献することができます
#geta #notfoundhandlerによる致命的な欠陥Quan #Maiのブログ