PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

レポヌトでは、これを可胜にするいく぀かのアプロヌチが玹介されおいたす。 XNUMX 日に数癟䞇件の SQL ク゚リが発生する堎合の SQL ク゚リのパフォヌマンスを監芖する、監芖察象の PostgreSQL サヌバヌは数癟台ありたす。

このような倧量の情報を効率的に凊理できる技術゜リュヌションは䜕でしょうか?たた、これによっお䞀般の開発者の䜜業がどのように楜になるのでしょうか?


誰が興味を持っおいたすか? 特定の問題の分析ずさたざたな最適化手法 SQL ク゚リず PostgreSQL での兞型的な DBA の問題の解決 - たた、 䞀連の蚘事を読む このトピックに぀いお

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)
私の名前はキリル・ボロビコフです。代衚を務めたす。 テン゜ル䌚瀟。 具䜓的には、瀟内でデヌタベヌスを扱うこずを専門ずしおいたす。

今日は、単䞀のク゚リのパフォヌマンスを「個別に抜出」する必芁がなく、問題をたずめお解決する堎合に、ク゚リを最適化する方法に぀いお説明したす。 䜕癟䞇ものリク゚ストがあり、いく぀かを芋぀ける必芁がある堎合 解決ぞのアプロヌチ この倧きな問題。

䞀般に、XNUMX 䞇のクラむアントにずっお Tensor は次のずおりです。 VLSI は私たちのアプリケヌションです䌁業の゜ヌシャルネットワヌク、ビデオコミュニケヌションの゜リュヌション、瀟内倖のドキュメントフロヌ、䌚蚈ず倉庫の䌚蚈システム...぀たり、100以䞊の異なる䌁業が統合された経営管理のための「メガコンバむン」です。内郚プロゞェクト。

すべおが正垞に動䜜し、開発できるようにするために、圓瀟は党囜に 10 か所の開発センタヌを蚭けおおり、さらに倚くの開発センタヌを蚭眮しおいたす。 1000人の開発者.

圓瀟は 2008 幎から PostgreSQL を䜿甚しおおり、クラむアント デヌタ、統蚈デヌタ、分析デヌタ、倖郚情報システムからのデヌタなど、凊理するデヌタを倧量に蓄積しおきたした。 400TB以䞊。 本番環境だけでも玄 250 台のサヌバヌがあり、合蚈で玄 1000 台のデヌタベヌス サヌバヌが監芖されおいたす。

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

SQL は宣蚀型蚀語です。 䜕かが「どのように」機胜するかではなく、「䜕を」達成したいかを説明したす。 DBMS は、JOIN の䜜成方法、぀たりテヌブルの接続方法、課す条件、むンデックスを通過するものず通過しないものをよく知っおいたす。

䞀郚の DBMS は、「いいえ、この XNUMX ぀のテヌブルをこれこれのキュヌに接続しおください」ずいうヒントを受け入れたすが、PostgreSQL ではこれができたせん。 これは、䞻芁な開発者の意識的な立堎です。「開発者に䜕らかのヒントを䜿甚させるよりも、ク゚リ オプティマむザヌを完成させたいず考えおいたす。」

しかし、PostgreSQL は「倖郚」による自身の制埡を蚱可しおいないずいう事実にもかかわらず、完党に蚱可しおいたす。 圌の䞭で䜕が起こっおいるか芋おみたしょうク゚リを実行するずきず、どこで問題が発生したか。

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

䞀般に、開発者 (DBA にずっお) は通垞、どのような兞型的な問題に盎面したすか? 「ここで私たちはその芁求を満たしたした、そしお、 私たちにずっおはすべおが遅い、すべおがハングアップしおいたす、䜕かが起こっおいたす...䜕らかのトラブルが発生しおいたす!」

理由はほずんど垞に同じです。

  • 非効率的なク゚リアルゎリズム
    開発者: 「今、JOIN 経由で SQL で 10 個のテヌブルを圌に䞎えおいたす...」 - そしお、圌の条件が奇跡的に事実䞊「解きほぐされ」、すべおをすぐに取埗できるこずを期埅しおいたす。 しかし、奇跡は起こらず、このような倉動性のあるシステム (10 ぀の FROM に XNUMX 個のテヌブル) では垞に䜕らかの゚ラヌが発生したす。 [蚘事]
  • 無関係な統蚈
    この点は特に PostgreSQL に非垞に関連しおおり、倧芏暡なデヌタセットをサヌバヌに「泚ぎ」、リク゚ストを行うず、タブレットが「セックス」されたす。 昚日は 10 件のレコヌドがあり、今日は 10 䞇件のレコヌドがありたしたが、PostgreSQL はただこれを認識しおいないため、PostgreSQL にそれを䌝える必芁がありたす。 [蚘事]
  • リ゜ヌスに「接続」する
    ディスク、メモリ、プロセッサのパフォヌマンスが十分でない匱いサヌバヌに、倧芏暡で負荷の高いデヌタベヌスをむンストヌルしたした。 それがすべおです...どこかにパフォヌマンスの䞊限があり、それを超えるずゞャンプできなくなりたす。
  • ブロッキング
    これは難しい点ですが、さたざたな倉曎ク゚リ (INSERT、UPDATE、DELETE) に最も関連しおいたす。これは別の倧きなトピックです。

蚈画を立おる

...その他すべおに぀いおは、 蚈画が必芁です サヌバヌ内で䜕が起こっおいるかを確認する必芁がありたす。

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

PostgreSQL のク゚リ実行プランは、テキスト衚珟でのク゚リ実行アルゎリズムのツリヌです。 たさにプランナヌが分析した結果、最も効果的であるず刀明したアルゎリズムです。

各ツリヌ ノヌドは、テヌブルたたはむンデックスからのデヌタの取埗、ビットマップの構築、XNUMX ぀のテヌブルの結合、結合、亀差、たたは遞択の陀倖などの操䜜です。 ク゚リを実行するには、このツリヌのノヌドをたどる必芁がありたす。

ク゚リ プランを取埗するには、次のステヌトメントを実行するのが最も簡単な方法です。 EXPLAIN。 すべおの実際の属性を取埗するには、぀たりベヌスに察しお実際にク゚リを実行するには - EXPLAIN (ANALYZE, BUFFERS) SELECT ....

悪い点: 実行するず、「今ここ」で実行されるため、ロヌカル デバッグにのみ適しおいたす。 デヌタ倉曎の匷いフロヌ䞋にある高負荷のサヌバヌを䟋にするず、次のようになりたす。 ここでは実行が遅くなりたす倏 リク゚スト。" XNUMX 分、XNUMX 時間前、実行䞭にこのリク゚ストをログから取埗し、サヌバヌに戻しおいる間に、デヌタセット党䜓ず統蚈が倉曎されたした。 デバッグのために実行するず、すぐに実行されたす。 そしお、あなたはなぜ、なぜ、理解できないのですか былП ゆっくり。

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

リク゚ストがサヌバヌ䞊で実行された瞬間に䜕が起こったのかを正確に理解するために、賢い人々は次のように曞きたした。 auto_explain モゞュヌル。 これは、最も䞀般的な PostgreSQL ディストリビュヌションのほがすべおに含たれおおり、構成ファむルで簡単にアクティブ化できたす。

䞀郚のリク゚ストが指定された制限を超えお実行されおいるこずが刀明した堎合は、実行したす。 このリク゚ストの蚈画の「スナップショット」を䜜成し、それらをたずめおログに曞き蟌みたす.

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

今ではすべおがうたくいっおいるようです。ログに行き、そこを芋おみたす...[テキストフットクロス]。 しかし、実行に 11 ミリ秒かかったずいう点では、これが優れた蚈画であるずいう事実以倖には䜕も蚀えたせん。

すべおがうたくいっおいるように芋えたすが、実際に䜕が起こったのかは䜕も明らかではありたせん。 䞀般的な時間以倖には、実際には䜕も芋えたせん。 なぜなら、そのようなプレヌンテキストの「子矊」を芋るこずは、䞀般に芖芚的ではないからです。

しかし、それが明癜でなくおも、䞍䟿であっおも、もっず根本的な問題がありたす。

  • ノヌドが瀺すのは、 サブツリヌ党䜓のリ゜ヌスの合蚈 圌の䞋で。 ぀たり、その䞋にネストされた条件がある堎合、この特定のむンデックス スキャンに費やされた時間を単に調べるこずはできたせん。 内郚に「子」や条件倉数、CTE があるかどうかを動的に確認し、これらすべおを「心の䞭で」差し匕く必芁がありたす。
  • XNUMX点目ノヌドに衚瀺される時刻は 単䞀ノヌドの実行時間。 たずえば、テヌブル レコヌドを耇数回ルヌプした結果ずしおこのノヌドが実行された堎合、プラン内のルヌプ数 (このノヌドのサむクル) が増加したす。 ただし、アトミック実行時間自䜓は蚈画䞊同じたたです。 ぀たり、このノヌドが合蚈でどのくらいの時間実行されたかを理解するには、もう䞀床「頭の䞭で」䜕かを掛ける必芁がありたす。

このような状況では、「誰が最も匱いリンクなのか」を理解しおください。 ほが䞍可胜である。 そのため、開発者自身も「マニュアル」にこう曞いおいたす。 「蚈画を理解するには、孊習し、経隓しなければならない技術です...」.

しかし、圓瀟には 1000 人の開発者がおり、この経隓を各人に䌝えるこずはできたせん。 私も、あなたも、圌も知っおいたすが、向こうの誰かはもう知りたせん。 おそらく圌は孊ぶだろうし、孊ばないかもしれないが、圌は今働く必芁がある - そしお圌はどこでこの経隓を埗るのだろうか?

蚈画の芖芚化

したがっお、これらの問題に察凊するには、次のこずが必芁であるこずに気づきたした。 蚈画を適切に芖芚化する. [蚘事]

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

私たちはたず「垂堎を調べお」みたした。むンタヌネットで䜕が存圚するのか芋おみたしょう。

しかし、倚かれ少なかれ開発䞭の比范的「ラむブ」な゜リュヌションはほずんどないこずが刀明したした。文字通り、次の XNUMX ぀だけです。 Explain.depesz.com ヒュヌバヌト・ルバチェフスキ著。 「フィヌド」フィヌルドに蚈画のテキスト衚珟を入力するず、解析されたデヌタを含む衚が衚瀺されたす。

  • ノヌド自䜓の凊理時間
  • サブツリヌ党䜓の合蚈時間
  • 統蚈的に予想された、取埗されたレコヌドの数
  • ノヌド本䜓自䜓

このサヌビスには、リンクのアヌカむブを共有する機胜もありたす。 あなたはそこに自分の蚈画を投げ蟌み、こう蚀いたした。「ねえ、ノァシャ、ここにリンクがありたす。そこに䜕か問題がありたす。」

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

しかし、小さな問題もありたす。

たず、膚倧な量の「コピペ」。 䞞倪の䞀郚を取り出し、そこに突き刺すのを、䜕床も䜕床も繰り返したす。

第二に、 読み取られたデヌタ量の分析はありたせん — 出力するのず同じバッファ EXPLAIN (ANALYZE, BUFFERS)、ここでは芋られたせん。 圌は単にそれらを分解し、理解し、それらを扱う方法を知りたせん。 倧量のデヌタを読み取るずきに、ディスクずメモリ キャッシュの割り圓おが間違っおいる可胜性があるこずに気づいた堎合、この情報は非垞に重芁です。

XNUMX 番目のマむナス点は、このプロゞェクトの展開が非垞に匱いこずです。 コミットは非垞に小さく、XNUMX か月に XNUMX 回皋床が適切で、コヌドは Perl です。

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

しかし、これはすべお「歌詞」であり、これで䜕ずかやっおいけるのですが、このサヌビスから倧きく遠ざかったこずが XNUMX ぀ありたす。 これらは、Common Table Expression (CTE) および InitPlan/SubPlan などのさたざたな動的ノヌドの分析における゚ラヌです。

この図を信じるのであれば、個々のノヌドの合蚈実行時間は、リク゚スト党䜓の合蚈実行時間よりも長いずいうこずになりたす。 それは簡単です - この CTE の生成時間は CTE スキャン ノヌドから差し匕かれたせんでした。 したがっお、CTE スキャン自䜓にかかった時間に぀いおの正確な答えはもはやわかりたせん。

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

その埌、自分たちで独自のコヌドを䜜成する時期が来たこずに気づきたした。䞇歳 すべおの開発者はこう蚀いたす。「今床は自分たちで䜜成したしょう。ずおも簡単です!」

私たちは Web サヌビスに兞型的なスタックを採甚したした。Node.js + Express をベヌスにしたコアで、矎しい図を䜜成するために Bootstrap ず D3.js を䜿甚したした。 そしお私たちの期埅は完党に的䞭し、最初のプロトタむプを 2 週間で受け取りたした。

  • カスタムプランパヌサヌ
    ぀たり、PostgreSQL によっお生成されたプランから任意のプランを解析できるようになりたした。
  • 動的ノヌドの正しい分析 - CTE スキャン、InitPlan、SubPlan
  • バッファヌ分垃の分析 - デヌタ ペヌゞがメモリから読み取られる堎所、ロヌカル キャッシュから読み取られる堎所、ディスクから読み取られる堎所
  • 明確になった
    これは、ログをすべお「掘る」のではなく、画像内で「最も匱いリンク」をすぐに確認できるようにするためです。

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

構文の匷調衚瀺が含たれた、次のような結果が埗られたした。 しかし、通垞、開発者は蚈画を完党に衚珟したものではなく、より短いものを䜿甚しおいたす。 結局のずころ、すでにすべおの数倀を解析しお巊右に投げおおり、䞭倮には、それがどのような皮類のノヌドであるかを瀺す最初の行だけが残されおいたす: 䜕らかの笊号によるず、CTE スキャン、CTE 生成、たたは Seq スキャン。

これは私たちが呌んでいる省略衚珟です 蚈画テンプレヌト.

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

他に䟿利なものは䜕でしょうか 合蚈時間のどの割合がどのノヌドに割り圓おられおいるかを確認し、暪に「貌り付ける」だけで䟿利です。 円グラフ.

ノヌドを指しお芋おみるず、Seq Scan にかかった時間は合蚈の 3 分の 4 未満で、残りの XNUMX/XNUMX が CTE Scan にかかっおいるこずがわかりたした。 ホラヌ これは、ク゚リで CTE スキャンを積極的に䜿甚する堎合の CTE スキャンの「発射速床」に関する小さなメモです。 これらはそれほど高速ではありたせん。通垞のテヌブル スキャンよりも劣りたす。 [蚘事] [蚘事]

しかし、通垞、そのような図は、セグメントをすぐにポむントしお、たずえば、半分以䞊の時間で䞀郚の Seq Scan が「食べた」こずがわかるず、より興味深く、より耇雑になりたす。 さらに、内郚にはある皮のフィルタヌがあり、それに応じお倚くのレコヌドが砎棄されたした...この写真を開発者に盎接投げお、次のように蚀うこずができたす。 考えおみおください、䜕かが間違っおいたす!」

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

圓然のこずながら、いく぀かの「熊手」が関係しおいたした。

私たちが最初に遭遇したのは䞞めの問題でした。 蚈画内の個々のノヌドの時間は 1 ÎŒs の粟床で瀺されたす。 そしお、ノヌド サむクル数が、たずえば 1000 を超えるず、PostgreSQL の実行埌、「粟床の範囲内で」陀算され、逆算するず合蚈時間は「0.95 ミリ秒から 1.05 ミリ秒の間」になりたす。 カりントがマむクロ秒に達する堎合は問題ありたせんが、すでに[ミリ秒]になっおいる堎合は、「誰がどのくらい消費したか」蚈画のノヌドからリ゜ヌスを「切り離す」ずきに、この情報を考慮する必芁がありたす。

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

2 番目のポむントは、より耇雑ですが、動的ノヌド間でのリ゜ヌス (バッファヌ) の分散です。 これにより、プロトタむプの最初の 4 週間に加えお、さらに XNUMX 週間かかりたした。

この皮の問題は非垞に簡単に発生したす。CTE を実行し、その䞭で䜕かを読み取るず考えられたす。 実際、PostgreSQL は「賢い」ので、そこから盎接䜕かを読み取るこずはありたせん。 次に、そこから最初のレコヌドを取埗し、そこに同じ CTE からの XNUMX 番目のレコヌドを取埗したす。

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

蚈画を芋お理解したす。奇劙なこずに、Seq スキャンで 3 ぀のバッファ (デヌタ ペヌゞ) が「消費」され、CTE スキャンでさらに 1 ぀、2 番目の CTE スキャンでさらに 6 ぀が「消費」されおいたす。 ぀たり、すべおを単玔に合蚈するず 3 になりたすが、タブレットからは XNUMX しか読み取れたせん。 CTE スキャンはどこからでも䜕も読み取りたせんが、プロセス メモリを盎接操䜜したす。 ぀たり、ここでは明らかに䜕かが間違っおいたす。

実際、ここに Seq Scan から芁求された 3 ペヌゞのデヌタがすべおあり、最初の 1 ペヌゞが 1 回目の CTE スキャンを芁求し、次に 2 ペヌゞ目、そしおさらに 2 ペヌゞが読み取られたこずがわかりたした。 3 ペヌゞではなく 6 ペヌゞが読み取られたデヌタです。

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

そしお、この図は、蚈画の実行はもはやツリヌではなく、単なるある皮の非埪環グラフであるずいう理解を私たちにもたらしたした。 そしお、「そもそも䜕がどこから来たのか」がわかるように、このような図が埗られたした。 ぀たり、ここでは pg_class から CTE を䜜成し、それを 2 回芁求したしたが、101 回目の芁求時にほがすべおの時間がブランチに費やされたした。 タブレットから 1 番目の゚ントリを読み取るこずは、最初の゚ントリを単に読み取るよりもはるかにコストがかかるこずは明らかです。

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

私たちはしばらく息を吐きたした。 圌らは蚀いたした「ネオ、君はカンフヌを知っおいるね」 私たちの経隓があなたの画面䞊に衚瀺されるようになりたした。 これで䜿えるようになりたした。」 [蚘事]

ログの統合

1000 人の開発者は安堵のため息を぀きたした。 しかし、「戊闘」サヌバヌは数癟台しかなく、開発者偎のこの「コピヌペヌスト」はたったく䟿利ではないこずを私たちは理解しおいたした。 私たちはそれを自分たちで集めなければならないこずに気づきたした。

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

䞀般に、統蚈を収集できる暙準モゞュヌルがありたすが、これも構成で有効にする必芁がありたす。 pg_stat_statements モゞュヌル。 しかし、圌は私たちには合わなかった。

たず、同じデヌタベヌス内の異なるスキヌムを䜿甚しお同じク゚リに割り圓おたす。 異なるQueryId。 ぀たり、最初に実行するず、 SET search_path = '01'; SELECT * FROM user LIMIT 1;そしお SET search_path = '02'; ず同じリク゚ストの堎合、このモゞュヌルの統蚈には異なるレコヌドが含たれるこずになり、スキヌムを考慮せずに、特にこのリク゚スト プロファむルのコンテキストで䞀般的な統蚈を収集するこずはできたせん。

䜿甚を劚げた XNUMX 番目の点は、 蚈画の欠劂。 ぀たり、蚈画はなく、芁求自䜓があるだけです。 䜕が枛速しおいるのかはわかりたしたが、その理由はわかりたせん。 ここで、急速に倉化するデヌタセットの問題に戻りたす。

そしお最埌の瞬間―― 「事実」の欠劂。 ぀たり、ク゚リ実行の特定のむンスタンスに察凊するこずはできたせん。存圚するのは、集蚈された統蚈だけです。 これで䜜業するこずは可胜ですが、非垞に困難です。

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

そこで、コピペず戊うこずを決意し、曞き始めたした。 コレクタヌ.

コレクタヌは SSH 経由で接続し、蚌明曞を䜿甚しおサヌバヌずデヌタベヌスぞの安党な接続を確立したす。 tail -F ログファむルに「くっ぀いおいたす」。 そこで今回のセッションでは ログファむル党䜓の完党な「ミラヌ」を取埗したす。、サヌバヌが生成したす。 サヌバヌでは䜕も解析せず、トラフィックをミラヌリングするだけなので、サヌバヌ自䜓の負荷は最小限です。

すでに Node.js でむンタヌフェむスの䜜成を開始しおいたので、匕き続きその䞭でコレクタヌを䜜成したした。 そしお、JavaScript を䜿甚しお匱いフォヌマットのテキスト デヌタ (ログ) を操䜜するのが非垞に䟿利であるため、このテクノロゞ自䜓が正圓化されおいたす。 たた、バック゚ンド プラットフォヌムずしおの Node.js むンフラストラクチャ自䜓により、ネットワヌク接続、さらにはあらゆるデヌタ ストリヌムを簡単か぀䟿利に操䜜できるようになりたす。

したがっお、123 ぀の接続を「拡匵」したす。123 ぀目はログ自䜓を「リッスン」しお自分自身に取り蟌み、XNUMX ぀目は定期的にベヌスに問い合わせたす。 「しかし、ログには oid XNUMX の蚘号がブロックされおいるこずが瀺されおいたす。」 しかし、これは開発者にずっおは䜕の意味もありたせん。デヌタベヌスに「そもそも OID = XNUMX ずは䜕ですか?」ず尋ねるのが良いでしょう。 そこで私たちは自分自身に぀いおただ知らないこずを定期的に基地に尋ねたす。

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

「考慮しおいないこずが 10 ぀だけありたす。ゟりに䌌たミツバチの䞀皮がいるずいうこずです。」 私たちは、XNUMX 台のサヌバヌを監芖したいず考えたずきにこのシステムの開発を開始したした。 私たちの理解の䞭で最も重芁なのは、察凊が難しいいく぀かの問題が発生した堎合です。 しかし、第 XNUMX 四半期には XNUMX 件のモニタリングが行われたした。システムが機胜し、誰もがそれを望んでおり、誰もが快適だったからです。

これらすべおを合蚈する必芁があり、デヌタ フロヌは倧芏暡でアクティブです。 実際、私たちが監芖しおいるもの、察凊できるものは、私たちが䜿甚しおいるものです。 デヌタ ストレヌゞずしお PostgreSQL も䜿甚しおいたす。 そしお、オペレヌタヌほどデヌタを「泚入」するのが速いものはありたせん。 COPY ただ。

しかし、単にデヌタを「泚ぐ」だけでは、実際には私たちのテクノロゞヌではありたせん。 50 台のサヌバヌで 100 秒あたり玄 150 のリク゚ストがある堎合、XNUMX 日あたり XNUMX  XNUMX GB のログが生成されるためです。 したがっお、ベヌスを慎重に「カット」する必芁がありたした。

たず、私たちがやったのは、 日ごずに区切るなぜなら、抂しお、日間の盞関関係には誰も興味がないからです。 今倜アプリケヌションの新しいバヌゞョンを公開した堎合、そしおすでにいく぀かの新しい統蚈が公開された堎合、昚日ず比べおどのような違いが生じるでしょうか。

第二に、私たちは孊んだ匷制された を䜿甚しお非垞に高速に曞くこずができたす COPY。 ぀たり、それだけではなく、 COPY圌はより速いから INSERT、さらに速くなりたす。

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

XNUMX 番目のポむント - しなければならなかった それぞれトリガヌず倖郚キヌを攟棄したす。 ぀たり、参照敎合性がたったくありたせん。 なぜなら、FK のペアを持぀テヌブルがあり、デヌタベヌス構造で「ここに、たずえばレコヌドのグルヌプに察しお FK によっお参照されるログ レコヌドがある」ず指定した堎合、それを挿入するず、PostgreSQL があずはそれをどう受け止めお正盎に実行するかだけだ SELECT 1 FROM master_fk1_table WHERE ... 挿入しようずしおいる識別子を䜿甚したす。これは、このレコヌドがそこに存圚するこず、挿入によっおこの倖郚キヌが「切断」されおいないこずを確認するためです。

タヌゲット テヌブルずそのむンデックスに察する XNUMX ぀のレコヌドの代わりに、それが参照するすべおのテヌブルから読み取るずいう远加の利点が埗られたす。 しかし、これはたったく必芁ありたせん。私たちの仕事は、最小限の負荷でできるだけ倚くの内容をできるだけ早く蚘録するこずです。 それでFK - ダりン

次のポむントは集玄ずハッシュです。 最初はデヌタベヌスに実装したしたが、結局のずころ、レコヌドが到着したら、ある皮のタブレットですぐに実行できるのが䟿利です。 トリガヌのすぐ近くに「プラス XNUMX」。 これは䟿利ですが、同じように悪い点もありたす。レコヌドを XNUMX ぀挿入しおも、別のテヌブルから䜕か他のものを読み曞きしなければならないずいうこずです。 しかも、ただ読み曞きするだけではなく、毎回それを行うのです。

ここで、特定のホストを通過したリク゚ストの数を単玔にカりントするテヌブルがあるず想像しおください。 +1, +1, +1, ..., +1。 そしお、原則ずしお、これは必芁ありたせん - すべお可胜です コレクタヌ䞊のメモリ内の合蚈 䞀床にデヌタベヌスに送信したす +10.

はい、䜕らかの問題が発生した堎合、論理的な敎合性が「厩れる」可胜性がありたすが、これはほずんど非珟実的なケヌスです。通垞のサヌバヌがあり、コントロヌラヌにバッテリヌがあり、トランザクション ログやログが存圚するためです。ファむル システム... 䞀般的に、それだけの䟡倀はありたせん。 トリガヌ/FK の実行によっお生じる生産性の損倱は、発生するコストに芋合ったものではありたせん。

ハッシュ化も同様です。 あるリク゚ストが飛んできお、デヌタベヌス内のそれからある識別子を蚈算しおデヌタベヌスに曞き蟌み、それをみんなに䌝えたす。 録音時に、同じこずを録音したいずいう別の人があなたのずころに来おブロックされるたでは、すべおがうたくいきたす。これはすでに悪いこずです。 したがっお、䞀郚の ID の生成を (デヌタベヌスに察しお) クラむアントに転送できる堎合は、これを実行するこずをお勧めしたす。

リク゚スト、プラン、テンプレヌトなどのテキストから MD5 を䜿甚するのは私たちにずっお完璧でした。コレクタヌ偎でそれを蚈算し、既成の ID をデヌタベヌスに「流し蟌み」たす。 MD5 の長さず毎日のパヌティショニングにより、衝突の可胜性を心配する必芁はありたせん。

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

しかし、これらすべおを迅速に蚘録するには、蚘録手順自䜓を倉曎する必芁がありたした。

普段どのようにデヌタを曞き蟌んでいたすか? ある皮のデヌタセットがあり、それを耇数のテヌブルに分割しおコピヌしたす。最初に最初のテヌブルに、次に XNUMX 番目のテヌブルに、そしお XNUMX 番目のテヌブルにコピヌしたす。XNUMX ぀のデヌタ ストリヌムを XNUMX ぀のステップで曞き蟌んでいるようなので䞍䟿です。順次。 䞍快。 もっず早くできるでしょうか できる

これを行うには、これらのフロヌを互いに䞊行しお分解するだけで十分です。 ゚ラヌ、リク゚スト、テンプレヌト、ブロッキングなどが別々のスレッドで発生しおおり、それらをすべお䞊行しお曞いおいるこずがわかりたした。 これで十分です 個々のタヌゲット テヌブルごずに COPY チャネルを垞に開いたたたにする.

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

぀たり、コレクタヌでは、 垞に流れがある、そこに必芁なデヌタを曞き蟌むこずができたす。 ただし、デヌタベヌスがこのデヌタを認識し、誰かがこのデヌタが曞き蟌たれるのを埅っお立ち埀生しないようにするために、 COPYは䞀定間隔で䞭断する必芁がある。 私たちの堎合、最も効果的な時間は玄 100 ミリ秒でした。これを閉じお、すぐに同じテヌブルに再床開きたす。 たた、いく぀かのピヌク時に XNUMX ぀のフロヌが䞍足した堎合は、䞀定の制限たでプヌルしたす。

さらに、このような負荷プロファむルの堎合、レコヌドがバッチで収集される堎合の集蚈は悪であるこずがわかりたした。 叀兞的な悪は、 INSERT ... VALUES さらに1000件のレコヌド。 なぜなら、その時点でメディアぞの曞き蟌みがピヌクに達し、ディスクに䜕かを曞き蟌もうずする他の人はすべお埅機するこずになるからです。

このような異垞を取り陀くには、単に䜕も集玄しないでください。 たったくバッファリングしないでください。 たた、ディスクぞのバッファリングが発生した堎合は (幞いなこずに、Node.js の Stream API を䜿甚するずそれを確認できたす)、この接続を延期したす。 再び空きむベントを受信したら、蓄積されたキュヌから曞き蟌みたす。 そしお、ビゞヌ状態の間に、プヌルから次の空いおいるものを取り出しお曞き蟌みたす。

デヌタ蚘録にこのアプロヌチを導入する前は、玄 4K の曞き蟌み操䜜があり、この方法で負荷を 4 分の 6 に削枛できたした。 珟圚では、新しい監芖察象デヌタベヌスのおかげでさらに 100 倍に増加し、最倧 3MB/秒たで増加したした。 そしお珟圚、過去 10 か月分のログを玄 15  XNUMX TB の量で保存しおおり、開発者がわずか XNUMX か月以内にあらゆる問題を解決できるようになるこずを期埅しおいたす。

私たちは問題を理解しおいたす

しかし、このすべおのデヌタを単に収集するだけでは優れおおり、有甚で関連性がありたすが、十分ではないこずを理解する必芁がありたす。 なぜなら、これらは XNUMX 日に䜕癟䞇もの異なる蚈画があるからです。

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

しかし、䜕癟䞇人も管理するこずは䞍可胜です。私たちはたず「より小芏暡」に取り組む必芁がありたす。 そしおたず第䞀に、この「小さな」ものをどのように敎理するかを決める必芁がありたす。

私たちは XNUMX ぀の重芁なポむントを特定したした。

  • 誰が このリク゚ストを送信したした
    ぀たり、Web むンタヌフェむス、バック゚ンド、支払いシステム、たたはその他のアプリケヌションから「到着」したした。
  • どこ それは起こった
    特定のサヌバヌ䞊で? なぜなら、XNUMX ぀のアプリケヌションの䞋に耇数のサヌバヌがあり、そのうちの XNUMX ぀が突然「おかしくなった」堎合 (「ディスクが腐った」、「メモリ リヌク」、その他の問題が原因)、そのサヌバヌに具䜓的に察凊する必芁があるからです。
  • 方法 問題は䜕らかの圢で明らかになった

「誰」がリク゚ストを送信したかを理解するために、暙準ツヌルを䜿甚しおセッション倉数を蚭定したす。 SET application_name = '{bl-host}:{bl-method}'; — リク゚ストの送信元のビゞネス ロゞック ホストの名前ず、リク゚ストを開始したメ゜ッドたたはアプリケヌションの名前を送信したす。

リク゚ストの「所有者」を枡した埌、リク゚ストをログに出力する必芁がありたす。このために倉数を蚭定したす。 log_line_prefix = ' %m [%p:%v] [%d] %r %a'。 興味のある人にずっおは、もしかしたら マニュアルを芋おくださいそれは䜕を意味したすか。 ログで次のこずがわかりたす。

  • 時間
  • プロセスずトランザクションの識別子
  • デヌタベヌス名
  • このリク゚ストを送信した人のIP
  • ずメ゜ッド名

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

その埌、異なるサヌバヌ間の XNUMX ぀のリク゚ストの盞関関係を調べるのはあたり面癜くないこずに気づきたした。 XNUMX ぀のアプリケヌションがあちこちで同じように倱敗するずいう状況は、あたりありたせん。 ただし、同じであっおも、これらのサヌバヌのいずれかを芋おください。

それで、これがカットです 「XNUMX サヌバヌ - XNUMX 日」 あらゆる分析にはこれで十分であるこずがわかりたした。

最初の分析セクションは同じです "サンプル" - すべおの数倀指暙を陀いた、蚈画の簡略化された圢匏のプレれンテヌション。 XNUMX 番目のカットはアプリケヌションたたはメ゜ッドで、XNUMX 番目のカットは問題を匕き起こした特定の蚈画ノヌドです。

特定のむンスタンスからテンプレヌトに移行するず、次の XNUMX ぀の利点が同時に埗られたした。

  • 分析察象のオブゞェクト数を倧幅に削枛
    私たちはもはや䜕千ものク゚リや蚈画ではなく、数十のテンプレヌトによっお問題を分析する必芁がありたす。
  • タむムラむン
    ぀たり、「事実」を䞀定のセクション内にたずめるこずで、その日の様子を衚瀺するこずができたす。 ここで、ある皮のパタヌンが、たずえば XNUMX 時間に XNUMX 回発生するが、それは XNUMX 日に XNUMX 回発生するはずである堎合、䜕が問題だったのか、誰が原因で、なぜ発生したのかを考える必芁があるこずが理解できたす。おそらく、それはここにあるはずです。そうすべきではありたせん。 これは、もう XNUMX ぀の非数倀的で玔粋に芖芚的な分析方法です。

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

残りの方法は、蚈画から抜出した指暙に基づいおいたす。぀たり、そのようなパタヌンが発生した回数、合蚈時間ず平均時間、ディスクから読み取られたデヌタの量、メモリから読み取られたデヌタの量などです。

たずえば、ホストの分析ペヌゞにアクセスするず、ディスク䞊で䜕かが過剰に読み取られ始めおいたす。 サヌバヌ䞊のディスクはそれを凊理できたせん。誰がそこから読み取るのでしょうか?

そしお、任意の列で䞊べ替えお、プロセッサやディスクの負荷、たたはリク゚ストの総数など、今䜕を扱うかを決めるこずができたす...私たちはそれを䞊べ替え、「䞊䜍」のものを芋お、修正し、アプリケヌションの新しいバヌゞョンを公開したした。
【ビデオ講矩】

そしお、次のようなリク゚ストから同じテンプレヌトが付属するさたざたなアプリケヌションをすぐに確認できたす。 SELECT * FROM users WHERE login = 'Vasya'。 フロント゚ンド、バック゚ンド、凊理...そしお、ナヌザヌが察話しおいないのに、なぜ凊理がナヌザヌを読み取るのか䞍思議に思いたす。

逆の方法は、アプリケヌションからその動䜜をすぐに確認するこずです。 たずえば、フロント゚ンドは XNUMX 時間に XNUMX 回、これ、これ、これ、そしおこれです (タむムラむンが圹に立ちたす)。 そしおすぐに疑問が生じたす。XNUMX 時間に XNUMX 回䜕かを行うのはフロント゚ンドの仕事ではないようです...

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

しばらくしおから、集蚈が䞍足しおいるこずに気づきたした。 プランノヌドごずの統蚈。 テヌブル自䜓のデヌタを操䜜する (むンデックスによる読み取り/曞き蟌みの有無にかかわらず) ノヌドのみをプランから分離したした。 実際、前の写真に察しお远加された点は XNUMX ぀だけです - このノヌドは䜕件のレコヌドをもたらしたしたか?、および砎棄された行の数 (フィルタヌによっお削陀された行)。

プレヌト䞊に適切なむンデックスがなく、それにリク゚ストを送信するず、むンデックスを通り過ぎお Seq Scan に萜ちたす...100 ぀を陀くすべおのレコヌドをフィルタヌで陀倖したした。 なぜ XNUMX 日あたり XNUMX 億件のフィルタヌ枈みレコヌドが必芁なのでしょうか? むンデックスをロヌルアップしたほうがよいのではないでしょうか?

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

すべおの蚈画をノヌドごずに分析した結果、蚈画には疑わしいず思われる兞型的な構造がいく぀かあるこずがわかりたした。 そしお、開発者に次のように䌝えるずよいでしょう。「友人、ここでは、たずむンデックスで読み取り、次に䞊べ替え、次に切り取りたす。」 - 原則ずしお、レコヌドは XNUMX ぀ありたす。

ク゚リを䜜成した人なら誰でも、おそらくこのパタヌンに遭遇したこずがありたす: 「Vasya の最埌の泚文、その日付を教えおください。」 そしお、日付によるむンデックスがない堎合、たたは䜿甚したむンデックスに日付がない堎合は、党く同じ「熊手」を螏みたす。

しかし、これが「熊手」であるこずはわかっおいたす。それなら、開発者に䜕をすべきかをすぐに指瀺しないのはなぜでしょうか。 したがっお、今プランを開くず、開発者はすぐにヒント付きの矎しい写真を芋お、「あちこちに問題がありたすが、これらはこうしお解決されたす」ずすぐに䌝えたす。

その結果、問題解決に必芁な経隓倀は圓初ず珟圚では倧幅に枛少しおいたす。 これが私たちが持っおいる皮類のツヌルです。

PostgreSQL ク゚リの䞀括最適化。 キリル・ボロビコフ (テン゜ル)

出所 habr.com

コメントを远加したす