階段の謎-ステップ プロファイル。 Rust イニシアチブ 、絶対 プロバイダー、メモリ使用量に関しては刺激的な動作を示します。 私が Rust プログラムに要求する最後の要素は、注目のメモリ プロファイルを刺激するものですが、ここでは
プロバイダーは一定時間「フラットな」メモリで逃げ、その後すべてが即座に急増します。ブランドノベルプラトーとして。 このパターンは何時間にもわたって繰り返され、通常は負荷がかかっていませんが、常にではありません。 魅力的な拡大を見たときの懸念部分は、メモリがサポートを下に降りることがめったにありませんでした。 以前は、メモリが置き忘れられているかのように、場合によっては「リーク」されていました.
お気に入りのケースの下では、この「階段」プロファイル以前は見ただけで刺激的でしたが、ある時点でメモリ使用量が不釣り合いに上昇しました。 無制限のメモリ開示は、プロバイダーと製品が終了を余儀なくされる可能性があります。 プロバイダーと製品がすべて即座に終了すると、公平な可用性の低下が発生する可能性があります… これは 企業にとって汚染されています
。
通常、プログラムで特異なメモリ開示を判断するときは、リークを判断します。 静かで、これはさまざまに見えました。 リークがあると、より現実的でお気に入りの開示パターンに注意する傾向があります.
これは基本的に、上に傾斜して壮大なラインを描いているように見えます。 では、私たちのプロバイダーがリークしていなかった場合、以前は何をしていたのでしょうか?
メモリ使用量の急上昇を引き起こしたタイトルの条件が原因である可能性があるとしたら、おそらく私はこれまでに起こっていたことを軽減できる可能性があります.
2つの切実な質問がありました:
過去の測定基準から、魅力的な同じパターンをのぞくことができるかもしれません長いフラット間隔の間で増加しますが、この開示の場所をぶら下げたよりも早くプロットはありません. 成長自体が斬新であったかどうかを知るために(「階段」パターンがお気に入り
であるにもかかわらず) 私たちにとって), この行動を繁殖させるための正当な計画が必要です.それ自体をカモフラージュするための「ステップ」、次に、記憶の開示を抑制するためのステップを特定するときに、動作の代替を検証するためにプロットをぶら下げます。 私はまた、私たちの git の履歴を逆にたどり、プロバイダが無制限の開示を提示しなかった場合に、時間制限を確認することもできます.
The負荷テストを実行したときに老化したディメンションは次のとおりでした:
以前の私にとっての魔法の集合体は: 私たちのより高い需要ボディ
および
より高い同時実行性
.
ローカル システムで負荷テストを実行する場合、すべての形式の制限コンポーネントがあります。これには、すべての購入者とサーバー自体を実行するために手元にあるプロセッサの有限の欲求が含まれます。 静かで、私は、総需要価格が下がったとしても、壮大なケースを与えられた私のネイティブマシンのメモリの「階段」に注意するのに生きていました.
場所サイズのペイロードを利用し、リクエストをバッチで送信し、それらの間に短い余暇を挟んで、プロバイダーのメモリを多くのインスタンスで少しずつパワーアップするのに生計を立てていました.
私は、おそらく時間の経過とともにメモリを増やすことができたかもしれませんが、最終的にある程度の収穫逓減を達成する可能性があることを偶然に知りました. 最終的には、(前代未聞の滑らかな)成長率の上限がいくらかあるでしょう。 もう少し参加してみると、さまざまなペイロードサイズでリクエストを送信することで、おそらく最高の上限に到達できる可能性があります.
私の入力を特定したとき、私は git の歴史をさかのぼって仕事をしていましたが、最終的に、私たちのプロダクションへの畏敬の念は、一時停止中の最新の変更の結果ではなくなった可能性があることを知りました.
この「階段」から抜け出すためのワークロードの詳細は、アプリケーション自体に固有のものです。 トイミッション
.
構造体 { ペイロード: serde_json:: 料金, } struct
WidgetCreateResponse {
身元: 弦、 寸法: usize, } 非同期 fn create_widget(Json(ウィジェット): Json )<ウィジェット ) -> 応答 ( StatusCode:: 作成した, Json(プロセスウィジェット(ウィジェット
。クローン()まで起きていてください ) .into_response[emphasize] () }
process_widget( ) -> WidgetCreateResponse { ); widget_id Uuid:: new_v4( . ) させてto_vec(&ウィジェット.ペイロード); tokio:: time[emphasize] :: .unwrap_or_default(
寝る長さ:: from_millis( ) env ("SLEEP_MS" .as_deref () .unwrap_or(「150」
) .パース() , "無効な SLEEP_MS") ; WidgetCreateResponse .to_string() 次元 : バイト .レン(
} } widget_id ) . 起きていて 時間::それはあなたがそこに調達する前代未聞の必要がないことをアウトに変えました.
axum から同じ魅力的な (ただし、この場合は前代未聞の) magnify を見つけることができました。 JSON 体格を受け取る単一のハンドラーを持つアプリ
wongarsu
おもちゃのミッションでメモリが増えるのに対し、プロダクションで見たほど劇的な計画はどこにもありませんでしたプロバイダー、それは私の調査の次の部分までのすべてのプロットを評価して区別するのに十分だった. さらに、さまざまなワークロードを試しながら、小さなコードベースのよりタイトな反復ループをぶら下げるのにも役立ちました。 の重要な機能については、
README を参照してください。負荷テストの実行方法.
コンピューター ウイルスのレビューやディスカッションで、同じ動作がリストされている可能性があるため、時間をかけて調べました。 多くのインスタンスで出てきた用語は、以前は ヒープの断片化[emphasize] でした。 そして、自己規律についてさらに多くのことを学んだ後、それはおそらくフィットするかもしれないと思いました
![]()
ヒープフラグメンテーションとは?
明らかな年齢の私たちの場合、
defrag ユーティリティ
を観察することで、偏りのないぶら下がりが発生する可能性があります。 DOS またはホーム ウィンドウでは、困難なディスク上でブロックを切り替えて、「古い」領域と「空き」領域を統合します。
この場合 時代遅れの PC は電力に挑戦し、さまざまなサイズの記録データがディスクに書き込まれ、後で移動または削除されたため、さまざまな古い地域間で生活するための「穴」が残りました。 ディスクが起動し始めるので、小さな領域のようなものとは見なされない、まったく新しいファイルを作成しようとする可能性があります。 ヒープの断片化計画では、ディスク断片化の失敗モードがそれほど劇的ではない可能性があるという議論の余地のない現実にもかかわらず、割り当ての失敗につながる可能性があります。 ディスク上では、ファイルはより小さなチャンクと同じくらい細かく切り刻まれる必要があり、前例のないほど効率が低下します (ありがとう
訂正のため)。 ディスクパワーの解決策は、ナレーションの柔軟性を「デフラグ」(断片化解除)して、これらの配信ブロックを現実の空間で再処理することです.
何かアロケータ (要素プログラムでメモリ割り当てを管理する責任があります) は、さまざまなサイズの値を一定の間隔で提供し、取り除きます。 ギャップが小さすぎて、すべてのプロットがヒープ全体に散らばっていると、他のケースではスロットに入れられないまったく新しい値に対応するために、メモリの新しい「新鮮な」ブロックが割り当てられる可能性があります。 悲しいことに、メモリ管理の仕組みから「デフラグ」はもはや考えられません. serde で、 内のフレームワーク レベルの何かaxum、 のさらに深いところにあるもの*)tokio であり、特定のシステムの実際のアロケータ実装の奇抜ささえあります。 根源を揺らさなくても(そのような要素が存在する可能性がある場合)、動作は私たちの環境で観察可能であり、ベアボーンアプリである程度再現可能です.
これがフォーミュレーションメモリに起こっていたものである場合、それについて何を達成する必要がありますか? ワークロードを交互に切り替えて、断片化から遠ざけるのは難しいと思われます。 また、断片化イベントが発生しているスタイルのコードで生活するルートを獲得するために、私の使命のすべての依存関係を解きほぐすことは洗練されているように見えます. では、何を成し遂げるのか?
ジェマロックを助けに
jemallocはを目指していると自称) "[emphasize] 断片化の回避とスケーラブルな同時実行性の紫肉アップ。"
以来 jemalloc は、最前線の断片化から遠く離れて保護するという計画から外れたアロケーターです。私たちのプロバイダーであった希望は、メモリを段階的に増やすことなく、より長く逃げることができるかもしれません.
プログラムへの入力や、アプリケーションの依存関係の山を交互に入れ替えることは、もはやそれほど簡単なことではありません。 反対に、アロケーターを交換するのは簡単です。 https の例に従います。 //github.com/tikv/jemallocator readme、以前はテストパワーのためにそれを確認するためにわずかな作業またはまったく作業が必要ありませんでした.
私のおもちゃの使命のために
、jemalloc
のデフォルト アロケーターをオプションで交換するために、カーゴ特性を追加しました。 そして負荷テストを再実行しました.
シミュレートされた負荷を介してすべてのプロットの常駐メモリを記録する特定の 2 つのメモリ プロファイルを示します。
なし jemalloc
、おなじみの階段のプロファイルをのぞきます。
jemalloc でメモリの突き上げをのぞき、何度も降りてきます。テスト実行。 さらに重要なのは、jemalloc とのメモリ使用量には前例のない違いがあることです。ロード対怠惰なインスタンスを介したすべてのプロットでは、メモリが常にベースラインまでのすべてのスタイルをサポートするという説明よりも早く行ったように、「フロアを失う」ことはありません.
おわりに
Rust プロバイダーの「階段状」のプロファイルに気付きましたが、
jemalloc を考えてシールドします。 テスト電力の場合。 ヒープの断片化を促進するワークロードをたまたまぶら下げると、jemalloc が発生する可能性があります。
個別に、
おもちゃの使命 レポは benchmark.yml を と共に使用) https://github.com/fcsonline/drill 負荷テスト ソフトウェア。 並行性、物理的次元 (およびプロバイダー自体の任意のハンドラーのスリープ間隔) などを変更して、allocator の代替がメモリ プロファイルにどのように影響するかを確認してください。
As staunch-world の影響については、スワップを jemalloc
にロールアウトした後、別のプロファイルを明確にのぞくことができます。 .
![]()
Rust の特徴であるタフでスケーラブルなプロバイダーを構築することに魅力を感じているあなたのために、私たちは人材を募集しています! 試み 私たちのキャリア インターネット ページ で、より多くの記録データを入手できます。私たちに従ってください ツイッター、 Github または RSS
の最新の更新情報) Svix Webhook プロバイダー、または のディスカッションに参加する 私たちのコミュニティ Slack.
𝚆𝚊𝚝𝚌𝚑 𝙽𝙾𝚆 📺