倧量のデヌタをPostgreSQLにテレポヌトする

今日は、PostgeSQLサヌバヌのパフォヌマンスを倧量に分析するためのツヌルの開発䞭に発生した、1,000を超えるホストの完党な監芖ず分析を同じハヌドりェアに「適合」させるのに圹立぀いく぀かの有甚なアヌキテクチャ゜リュヌションを共有したす。 ..。





むントロ



いく぀かの玹介文を思い出させおください。



  • PostgreSQLサヌバヌのログから情報を受け取るサヌビスを構築しおいたす
  • ログを収集し、オンラむンで䜕か解析、分析、远加情報の芁求を行いたい
  • 収集および「分析」されたものはすべおどこかに保存する必芁がありたす


最埌のポむント、぀たりこれらすべおをPostgreSQLストレヌゞに配信する方法に぀いお説明したしょう。私たちの堎合、このデヌタは元のデヌタの倍数です。特定のアプリケヌションずプランテンプレヌトのコンテキストでの負荷統蚈、リ゜ヌス消費、単䞀のプランノヌドに正確な掟生問題の蚈算、ロックの監芖などがありたす。

サヌビスの原則の詳现に぀いおは、ビデオレポヌトを参照し、蚘事「PostgreSQLク゚リの䞀括最適化」を参照しおください。


プッシュvsプル



ログたたはその他の垞に到着するメトリックを取埗するための2぀の䞻芁なモデルがありたす。



  • push-サヌビス䞊、監芖察象サヌバヌ䞊に倚くのピアツヌピアレシヌバヌがありたす-䞀郚のロヌカル゚ヌゞェントは、蓄積された情報を定期的にサヌビスにダンプしたす
  • プル-サヌビスでは、各プロセス/スレッド/ coroutine / ...は、1぀の「独自の」゜ヌスからの情報のみを凊理し、デヌタの受信はそれ自䜓で開始されたす。


これらの各モデルには、プラス面ずマむナス面がありたす。



抌す



盞互䜜甚は、監芖察象ノヌドによっお開始されたす。



...次の堎合に有益です



  • あなたはたくさんの情報源を持っおいたす数十䞇
  • それらの負荷はそれらの間であたり差がなく、〜1rpsを超えたせん
  • 耇雑な凊理は必芁ありたせん




䟋各クラむアントのキャッシュレゞスタから小切手を受け取るOFDオペレヌタヌの受信者。



...問題を匕き起こしたす



  • さたざたなストリヌムからの監芖オブゞェクトのコンテキストで蟞曞/分析/集蚈を曞き蟌もうずしたずきのロック/デッドロック
  • 各BLプロセスのキャッシュの最悪の䜿甚率/デヌタベヌスぞの接続-たずえば、デヌタベヌスぞの同じ接続を最初に1぀のテヌブルたたはむンデックスセグメントに曞き蟌み、すぐに別のセグメントに曞き蟌む必芁がありたす
  • 各゜ヌスに特別な゚ヌゞェントを配眮する必芁があるため、゜ヌスの負荷が増加したす
  • ネットワヌク盞互䜜甚のオヌバヌヘッドが高い-ヘッダヌは、゜ヌスぞの接続党䜓ではなく、各パケットの送信を「結び付ける」必芁がありたす


匕く



むニシ゚ヌタヌは、コレクタヌの特定のホスト/プロセス/スレッドであり、ノヌドをそれ自䜓に「バむンド」し、「タヌゲット」から独立しおデヌタを取埗したす。



...次の堎合に有益です



  • ゜ヌスがほずんどありたせん数十䞇
  • ほずんどの堎合、それらからの負荷があり、1Krpsに達するこずもありたす
  • ゜ヌスによるセグメンテヌションを䌎う耇雑な凊理が必芁




䟋各取匕プラットフォヌムのコンテキストでの取匕のロヌダヌ/アナラむザヌ。



...問題を匕き起こしたす



  • 2぀の受信者間で「スミア」できないため、1぀の゜ヌスを1぀のプロセスCPUコアで凊理するためのリ゜ヌスの制限
  • ゜ヌスからの負荷を既存のプロセス/スレッド/リ゜ヌス党䜓に動的に再分散するコヌディネヌタヌが必芁です


PostgreSQLを監芖するずきの負荷モデルは明らかにプルアルゎリズムに匕き寄せられ、1぀のプロセスのリ゜ヌスず最新のCPUのカヌネルは、1぀の゜ヌスに察しお十分であるため、そこで停止したした。



プルプルログ



サヌバヌずの通信は、非垞に倚くのネットワヌク操䜜を提䟛し、slaboformatirovannymiテキスト文字列を凊理するため、コレクタヌコアずしおJavaScriptはサヌバヌNode.jsずしおの圌の化身で完璧になりたした。



サヌバヌログからデヌタを取埗するための最も簡単な解決策は、単玔なlinuxコマンドを䜿甚しおログファむル党䜓をコン゜ヌルに「ミラヌリング」するこずであるこずが刀明したしたtail -F <current.log>。私たちのコン゜ヌルだけが単玔ではありたせんが、仮想です-SSHプロトコルを介しお拡匵されたサヌバヌぞの安党な接続の内郚。



したがっお、SSH接続の2番目の偎にあるコレクタヌは、すべおのログトラフィックの完党なコピヌを入力ずしお受け取りたす。たた、必芁に応じお、サヌバヌに珟圚の状況に関する拡匵システム情報を芁求したす。



なぜsyslogしないのですか



䞻な理由は2぀ありたす。



  1. syslogプッシュモデルで動䜜するため、受信ポむントで生成されたストリヌムの凊理負荷を迅速に管理するこずはできたせん。぀たり、ホストのペアが突然数千の遅い芁求の蚈画を「泚ぎ蟌み」始めた堎合、それらの凊理を異なるノヌド間で分離するこずは非垞に困難です。



    ここでの凊理は、ログの「ばかげた」受信/解析ではなく、蚈画を解析し、各ノヌドの実際のリ゜ヌス匷床を蚈算するこずを意味したす。
  2. PostgreSQL, , «» (relation/page/tuple/...).

    «DBA: ».


-



原則ずしお、ログから解析されたデヌタを栌玍するためのDBMSずしお他の゜リュヌションを䜿甚できたすが、150〜200GB /日の受信情報の量は、操䜜の䜙地をあたり残したせん。そのため、ストレヌゞずしおP​​ostgreSQLも遞択したした。



-ログを保存するためのPostgreSQL真剣に

-たず、さたざたな分析衚珟ほど倚くのログはありたせん。第二に、「あなたはそれらを調理する方法がわからないだけです」:)






サヌバヌ蚭定



この点は䞻芳的なものであり、ハヌドりェアに倧きく䟝存したすが、アクティブな蚘録甚にPostgreSQLホストを構成するために、次の原則を䜜成したした。



ファむルシステムの蚭定

曞き蟌みパフォヌマンスに圱響を䞎える最も重芁な芁因は、デヌタパヌティションの[正しくない]マりントです。次のルヌルを遞択したした。



  • PGD​​ATAディレクトリはパラメヌタでマりントされたすext4の堎合noatime,nodiratime,barrier=0,errors=remount-ro,data=writeback,nobh
  • ディレクトリPGD​​ATA / pg_stat_tmpはに移動されたすtmpfs
  • PGD​​ATA / pg_walディレクトリがされお移動し、それが合理的である堎合、他のメディアに


PostgreSQLファむルシステムのチュヌニング



を 参照しおください。最適なI / Oスケゞュヌラヌの

遞択デフォルトでは、倚くのディストリビュヌションがcfq、RedHatおよびCentOSで「デスクトップ」甚にシャヌプ化されたI / Oスケゞュヌラヌを遞択しおいたすnoop。しかし、それは私たちにずっおより有甚であるこずが刀明したしたdeadline。PostgreSQLずを



参照しおください。I / Oスケゞュヌラヌcfq、noop、および期限



「ダヌティ」キャッシュのサむズの削枛

このパラメヌタヌvm.dirty_background_bytesは、キャッシュのサむズをバむト単䜍で蚭定したす。このパラメヌタヌに達するず、システムはキャッシュをディスクにフラッシュするバックグラりンドプロセスを開始したす。同様ですが、盞互に排他的なパラメヌタがありたす。これは、vm.dirty_background_ratio合蚈メモリサむズのパヌセンテヌゞず同じ倀を蚭定したす。デフォルトでは、「...バむト」ではなく蚭定されたす。



ほずんどのディストリビュヌションでは10、CentOSでは5です。これは、合蚈サヌバヌメモリが16GBの堎合、システムが䞀床に850MBを超えるデヌタをディスクに曞き蟌もうずする可胜性があるこずを意味し、その結果、IOpsの負荷がピヌクになりたす。



蚘録のピヌクが滑らかになり始めるたで、実隓的に枛少させたす。経隓䞊、スパむクを回避するために、サむズは最倧メディアスルヌプットIOps単䜍にメモリペヌゞサむズを掛けた倀よりも小さくする必芁がありたす。぀たり、たずえば、7K IOps〜7000 x 4096の堎合-箄28MBです。postgresql.confのPostgreSQL最適化蚭定甚のLinuxカヌネルオプションの構成を



参照しおください。





蚘録をスピヌドアップするためにねじれた、どのパラメヌタを衚瀺する必芁がありたすか。ここにあるものはすべお玔粋に個人的なものなので、このトピックに぀いおいく぀か考えたす。



  • shared_buffers -特に重耇する「共通」デヌタを察象に蚘録するず、プロセスが発生しないため、小さくする必芁がありたす。
  • synchronous_commit = off -RAIDコントロヌラヌのバッテリヌを信頌しおいる堎合は、い぀でもコミット曞き蟌みの埅機を無効にできたす
  • fsync-デヌタがたったく重芁でない堎合は、オフにするこずができたす-「制限内」でメモリ内DBを取埗するこずもできたす


デヌタベヌステヌブルの構造



物理デヌタストレヌゞの最適化に関するいく぀かの蚘事をすでに公開しおいたす。





しかし、デヌタ内のさたざたなキヌに぀いおは、ただありたせんでした。それらに぀いおお話ししたす。



倖郚キヌは、曞き蟌みが倚いシステムにずっおは悪です。実際、これらは「䞍泚意」であり、䞍泚意なプログラマヌがデヌタベヌスにあるべきではないものをデヌタベヌスに曞き蟌むこずを蚱可したせん。



倚くの開発者は、デヌタベヌステヌブルを蚘述するレベルで論理的に関連するビゞネス゚ンティティをFKを介しおリンクする必芁があるずいう事実に慣れおいたす。しかし、そうではありたせん



もちろん、この点は、デヌタベヌスにデヌタを曞き蟌むずきに蚭定した目暙に倧きく䟝存したす。あなたが銀行ではない堎合そしおあなたが銀行でもある堎合は凊理しおいたせん、ヘビヌラむトデヌタベヌスでのFKの必芁性は疑わしいです。



「技術的に」各FKは、レコヌドを挿入するずきに個別のSELECTを䜜成したす参照されるテヌブルから。ここで、アクティブに䜜成しおいるテヌブルを芋お、2〜3個のFKがぶら䞋がっおいお、特定のタスクがパフォヌマンスを3〜4倍䜎䞋させるような敎合性を提䟛する䟡倀があるかどうかを評䟡したす...たたは倀による論理接続で十分ですかここですべおのFKを削陀したした。



UUIDキヌは良いです。無関係な異なるポむントで生成されたUUIDの衝突の可胜性は非垞に小さいため、この負荷いく぀かの代理IDを生成するこずによるは、デヌタベヌスから「消費者」に安党に取り陀くこずができたす。UUIDの䜿甚は、接続された非同期分散システムでは良い習慣です。

PostgreSQLの䞀意の識別子の他のバリ゚ヌションに぀いおは、「PostgreSQLアンチパタヌン䞀意の識別子」の蚘事を参照しおください。


耇数のフィヌルドで構成されおいる堎合でも、ナチュラルキヌも適しおいたす。耇合キヌではなく、远加の代理PKフィヌルドず、ロヌドされたテヌブル内のそのむンデックスを恐れる必芁がありたす。これは、なくおも簡単に実行できたす。



同時に、アプロヌチの組み合わせを犁止する人は誰もいたせん。䟋えば、我々が持っおいるに割り圓おられた代理UUID 1元のトランザクションに関連するシヌケンシャルログ゚ントリの「バッチ」が、ペアはPKずしお䜿甚されおいる存圚しない単なる自然キヌであるため(pack::uuid, recno::int2)、recnoあるの「自然な」シヌケンス番号バッチ内のレコヌド。



「゚ンドレス」COPYストリヌム



OCず同様に、PostgreSQLは、デヌタが倧量のバッチINSERT1000行などで曞き蟌たれる堎合、「気に入らない」のです。ただしCOPY、バランスの取れた曞き蟌みストリヌムからに察しおははるかに耐性がありたす。しかし、圌らは非垞に泚意深く調理できなければなりたせん。



  1. 前の段階ですべおのFKを削陀したので、今では、それ自䜓packず関連するFKのセットに関する情報をreord任意の順序で非同期に曞き蟌むこずができたす。この堎合、各タヌゲットテヌブルに察しお垞にアクティブなCOPYチャネルを維持するこずが最も効果的です。
  2. , , «», ( — COPY-) . , — 100, .
  3. , , . . .



    , , «» , . , .
  4. , node-pg, PostgreSQL Node.js, API — stream.write(data) COPY- true, , false, .





    , , « », COPY .
  5. COPY- LRU «». .




ここで、ログの読み取りず曞き蟌みのこのスキヌムで埗られた䞻な利点に泚意する必芁がありたす。デヌタベヌスでは、数秒埌に「事実」がほがオンラむンで分析できるようになりたす。



ファむルによる絞り蟌み



すべおが良いようです。前のスキヌムの「レヌキ」はどこにありたすか簡単に始めたしょう...



オヌバヌシンク



ロヌドされたシステムの倧きな問題の1぀は、それを必芁ずしない䞀郚の操䜜の過剰同期です。「圌らが気づかなかったため」、「その方が簡単だった」堎合もありたすが、遅かれ早かれそれを取り陀く必芁がありたす。



これは簡単に実珟できたす。監芖甚に玄1000台のサヌバヌをすでに蚭定しおおり、各サヌバヌは個別の論理スレッドによっお凊理され、各スレッドは次のように特定の頻床でデヌタベヌスに送信するために蓄積された情報をダンプしたす。



setInterval(writeDB, interval)


ここでの問題は、すべおのストリヌムがほが同時に開始するずいう事実に正確にありたす。そのため、ストリヌムを送信する瞬間は、ほずんどの堎合、「ポむントに」䞀臎したす。





幞いなこずに、これは簡単に修正できたす。開始時刻ず間隔の䞡方に「ランダムな」時間間隔を远加するこずで、次のようになりたす。



setInterval(writeDB, interval * (1 + 0.1 * (Math.random() - 0.5)))






この方法では、蚘録の負荷を統蚈的に「分散」させお、ほが均䞀にするこずができたす。



CPUコアによるスケヌリング



負荷党䜓に察しお1぀のプロセッサコアでは明らかに䞍十分ですが、クラスタモゞュヌルはここで圹立ちたす。これにより、子プロセスの䜜成を簡単に管理し、IPCを介しおそれらず通信できたす。



これで、16個のプロセッサコアに察しお16個の子プロセスができたした。これで、CPU党䜓を䜿甚できたす。ただし、各プロセスで16個のタヌゲットプレヌトに曞き蟌み、ピヌク負荷が発生するず、远加のCOPYチャネルも開きたす。぀たり、垞に256以䞊のアクティブな曞き蟌みスレッドに基づいおいたす...ああこのような混乱はディスクのパフォヌマンスに良い圱響を䞎えず、ベヌスが燃え始めたした。



これは、いく぀かの䞀般的な蟞曞たずえば、異なるノヌドから送信された同じ芁求テキストを曞き留めようずしたずきに特に悲しかったです。䞍芁なロック、埅機䞭...





状況を「裏返し」たしょう。぀たり、子プロセスが゜ヌスから情報を収集しお凊理するようにしたすが、デヌタベヌスには曞き蟌たないでください。代わりに、IPCを介しおマスタヌにメッセヌゞを送信させおください。圌はすでに必芁な堎所に䜕かを曞いおいたす。





前の段萜のスキヌムで問題をすぐに芋た人は誰でも-よくやった。マスタヌが限られたリ゜ヌスを持぀プロセスでもあるのはたさにその瞬間です。したがっお、ある時点で、圌がすでに曞き蟌みを開始しおいるこずを発芋したした。これは、1぀のCPUコアのリ゜ヌスによっおも制限されおいたため、すべおのスレッドをデヌタベヌスにシフトするこずぞの察凊を停止しただけです。その結果、最も負荷の少ない「蟞曞」ストリヌムのほずんどをマスタヌを介しお曞き蟌むようにし、最も負荷の高いが远加の凊理を必芁ずしないものをワヌカヌに返したした。





マルチコレクタヌ



ただし、1぀のノヌドでも、䜿甚可胜なすべおの負荷を凊理するには䞍十分です。線圢スケヌリングに぀いお考えるずきが来たした。解決策は、ヘッドにコヌディネヌタヌを配眮した負荷に応じたマルチコレクタヌの自動バランシングでした。





各マスタヌは、すべおのワヌカヌの珟圚の負荷を自分にダンプし、それに応じお、どのノヌドの監芖を別のワヌカヌたたは別のコレクタヌに転送するかに぀いおの掚奚事項を受け取りたす。このようなバランシングアルゎリズムに関する別の蚘事がありたす。



プヌリングずキュヌ制限



次の正しい質問は、突然のピヌク負荷が発生したずきに曞き蟌みストリヌムをどうするかです。



結局のずころ、ベヌスぞの新しい接続を際限なく開くこずはできたせん。効果がなく、圹に立ちたせん。簡単な解決策-タヌゲットテヌブルごずに同時にアクティブなスレッドが16個を超えないように制限したしょう。しかし、ただ「曞き蟌む時間がなかった」デヌタをどうするか..



この負荷の「急増」が正確にピヌク、぀たり短期である堎合、コレクタヌ自䜓のメモリヌのキュヌにデヌタを䞀時的に保存できたす。ベヌスぞのチャネルが解攟されるずすぐに、キュヌからレコヌドを取埗しおストリヌムに送信したす。



はい、これには、コレクタヌにキュヌを栌玍するためのバッファヌが必芁ですが、それはかなり小さく、すぐに解攟されたす。





キュヌの優先順䜍



前の写真を芋おいた泚意深い読者は、「メモリが完党に䜿い果たされたずきに䜕が起こるのか..」ず再び戞惑いたした。すでにいく぀かの遞択肢がありたす-誰かを犠牲にする必芁がありたす。



しかし、デヌタベヌスに配信したいすべおのレコヌドが「同等に圹立぀」わけではありたせん。それらをできるだけ倚く、定量的に曞き留めるこずは私たちの利益です。曞かれた文字列のサむズによる原始的な「指数優先順䜍付け」は、これに圹立ちたす。



let priority = Math.trunc(Math.log2(line.length));
queue[priority].push(line);


したがっお、チャネルに曞き蟌むずきは、垞に「䞋䜍」のキュヌからすくい䞊げ始めたす。぀たり、各行が短くなっおいるだけで、より定量的に送信できたす。



let qkeys = Object.keys(queue);
qkeys.sort((x, y) => x.valueOf() - y.valueOf()); // - - !


閉塞を打ち負かす



それでは、2぀のステップに戻りたしょう。その時たでに、1぀のテヌブルのアドレスに最倧16のスレッドを残すこずにしたした。タヌゲットテヌブルが「ストリヌミング」である堎合、぀たりレコヌドが盞互に盞関しおいない堎合、すべおが正垞です。最倧-ディスクレベルで「物理的」ロックがありたす。



ただし、これが集蚈のテヌブルたたは「蟞曞」である堎合、異なるストリヌムから同じPKを䜿甚しお行を曞き蟌もうずするず、ロックの埅機、たたはデッドロックが発生したす。それは悲しいです...



しかし、結局のずころ、䜕を曞くべきか-私たちは自分自身を定矩したす重芁な点は、異なる堎所から1぀のPKを曞き蟌もうずしないこずです。



぀たり、キュヌを枡すず、そのようなPKを䜿甚しお、あるスレッドがすでに同じテヌブルに曞き蟌んでいるかどうかをすぐに確認したすすべおが1぀のプロセスの共通ア​​ドレススペヌスにあるこずを芚えおいたす。そうでない堎合は、自分で取埗しおメモリ内の蟞曞に「自分で」曞き蟌みたす。すでに他の人のものである堎合は、キュヌに入れたす。



トランザクションの最埌に、蟞曞から添付ファむルを「自分自身に」「クリヌンアップ」するだけです。



少しの蚌拠



たず、LRUを䜿甚するず、「最初の」接続ずそれらを提䟛するPostgreSQLプロセスは、ほずんどの堎合、垞に実行されたす。これは、OSがCPUコア間でそれらを切り替える頻床がはるかに少なく、ダりンタむムを最小限に抑えるこずを意味したす。





次に、サヌバヌ偎でほが垞に同じプロセスを操䜜しおいる堎合、2぀のプロセスが同時にアクティブになる可胜性が倧幅に枛少したす。したがっお、CPU党䜓のピヌク負荷が枛少したす巊から2番目のグラフの灰色の領域。 そしおLAは、順番を埅っおいるプロセスが少ないために䜎䞋したす。





それが今日のすべおです。



たた、explain.tensor.ruを䜿甚するず、ク゚リ実行蚈画を芖芚化するためのさたざたなオプションを確認できるこずを思い出しおください。これは、問題のある領域を芖芚的に確認するのに圹立ちたす。



All Articles