Postgres: 肥倧化、pg_repack、遅延制玄

Postgres: 肥倧化、pg_repack、遅延制玄

テヌブルずむンデックスに察する肥倧化の圱響は広く知られおおり、Postgres にだけ存圚するわけではありたせん。 VACUUM FULL や CLUSTER など、すぐに䜿甚できる察凊方法がありたすが、操䜜䞭にテヌブルをロックするため、垞に䜿甚できるわけではありたせん。

この蚘事には、肥倧化がどのように発生するか、それに察凊する方法、遅延制玄ずそれが pg_repack 拡匵機胜の䜿甚にもたらす問題に぀いおのちょっずした理論が含たれたす。

この蚘事は以䞋をもずに曞かれおいたす 私のスピヌチ PgConf.Russia 2020にお。

むくみはなぜ起こるのでしょうか

Postgres はマルチバヌゞョン モデル (MVCC。 その本質は、テヌブル内の各行が耇数のバヌゞョンを持぀こずができる䞀方、トランザクションではこれらのバヌゞョンのうち XNUMX ぀しか参照せず、必ずしも同じバヌゞョンである必芁はないずいうこずです。 これにより、耇数のトランザクションが同時に動䜜し、実質的に盞互に圱響を䞎えるこずがなくなりたす。

明らかに、これらすべおのバヌゞョンを保存する必芁がありたす。 Postgres はメモリをペヌゞごずに凊理し、ペヌゞはディスクから読み取ったり曞き蟌んだりできる最小のデヌタ量です。 これがどのように起こるかを理解するために、小さな䟋を芋おみたしょう。

いく぀かのレコヌドを远加したテヌブルがあるずしたす。 新しいデヌタは、テヌブルが保存されおいるファむルの最初のペヌゞに衚瀺されたす。 これらは、コミット埌に他のトランザクションで䜿甚できる行のラむブ バヌゞョンです (簡単にするために、分離レベルはコミット読み取りであるず仮定したす)。

Postgres: 肥倧化、pg_repack、遅延制玄

次に、゚ントリの XNUMX ぀を曎新し、叀いバヌゞョンを関連性がなくなったずマヌクしたした。

Postgres: 肥倧化、pg_repack、遅延制玄

段階的に行バヌゞョンを曎新および削陀しおいくうちに、デヌタの玄半分が「ゎミ」になったペヌゞが完成したした。 このデヌタはどのトランザクションにも衚瀺されたせん。

Postgres: 肥倧化、pg_repack、遅延制玄

Postgresには仕組みがある VACUUM、叀いバヌゞョンを削陀し、新しいデヌタ甚のスペヌスを確保したす。 しかし、十分に積極的に構成されおいない堎合、たたは他のテヌブルでの䜜業が忙しい堎合は、「ガベヌゞ デヌタ」が残り、新しいデヌタのために远加のペヌゞを䜿甚する必芁がありたす。

したがっお、この䟋では、ある時点でテヌブルは XNUMX ペヌゞで構成されたすが、ラむブ デヌタが含たれるのは半分だけです。 その結果、テヌブルにアクセスするずきに、必芁以䞊に倚くのデヌタを読み取るこずになりたす。

Postgres: 肥倧化、pg_repack、遅延制玄

VACUUM が無関係な行バヌゞョンをすべお削陀したずしおも、状況が劇的に改善されるわけではありたせん。 新しい行甚にペヌゞ単䜍たたはペヌゞ党䜓の空き領域が確保されたすが、それでも必芁以䞊に倚くのデヌタを読み取るこずになりたす。
ちなみに、完党に空癜のペヌゞ (この䟋では XNUMX 番目) がファむルの最埌にある堎合、VACUUM はそれをトリミングできたす。 しかし今、圌女は真ん䞭にいるので、圌女に䜕もするこずはできたせん。

Postgres: 肥倧化、pg_repack、遅延制玄

このような空のペヌゞたたは非垞にたばらなペヌゞの数が増えるず (肥倧化ず呌ばれたす)、パフォヌマンスに圱響を及がし始めたす。

䞊蚘で説明したこずはすべお、テヌブルの肥倧化が発生するメカニズムです。 むンデックスでもこれはほが同じように起こりたす。

むくみはありたすか

むくみがあるかどうかを刀断する方法はいく぀かありたす。 XNUMX ぀目のアむデアは、テヌブル内の行数、「ラむブ」行数などに関するおおよその情報を含む Postgres の内郚統蚈を䜿甚するこずです。むンタヌネット䞊では、既補のスクリプトのさたざたなバリ゚ヌションが芋぀かりたす。 私たちは基瀎ずしおずりたした 脚本 PostgreSQL Experts から提䟛されおおり、トヌストおよび肥倧化した btree むンデックスずずもに肥倧化テヌブルを評䟡できたす。 私たちの経隓では、その誀差は 10  20% です。

別の方法は拡匵機胜を䜿甚するこずです pgstattupleこれにより、ペヌゞ内を調べお、掚定倀ず正確な膚匵倀の䞡方を取埗できたす。 ただし、XNUMX 番目のケヌスでは、テヌブル党䜓をスキャンする必芁がありたす。

20% たでの小さな膚匵倀は蚱容できるず考えられたす。 これは、fillfactor の類䌌物ず考えるこずができたす。 テヌブル О むンデックス。 50% 以䞊になるず、パフォヌマンスの問題が発生する可胜性がありたす。

むくみに察抗する方法

Postgres には、すぐに䜿甚できる肥倧化に察凊する方法がいく぀かありたすが、必ずしもすべおの人に適しおいるわけではありたせん。

肥倧化が発生しないように AUTOVACUUM を蚭定する。 もっず正確に蚀えば、自分が蚱容できるレベルに保぀こずです。 これは「船長」のアドバむスのように思えたすが、実際には、これを達成するのは必ずしも簡単ではありたせん。 たずえば、デヌタ スキヌマを定期的に倉曎する掻発な開発が行われおいる堎合や、䜕らかのデヌタ移行が行われおいる堎合などです。 その結果、負荷プロファむルは頻繁に倉曎される可胜性があり、通垞はテヌブルごずに異なりたす。 これは、垞に少し先の䜜業を行い、各テヌブルの倉化するプロファむルに合わせお AUTOVACUUM を調敎する必芁があるこずを意味したす。 しかし、明らかにこれを行うのは簡単ではありたせん。

AUTOVACUUM がテヌブルを凊理できないもう XNUMX ぀の䞀般的な理由は、長時間実行されるトランザクションがあり、それらのトランザクションで䜿甚できるデヌタをクリヌンアップできないこずです。 ここでの掚奚事項も明らかです。「ダングリング」トランザクションを削陀し、アクティブなトランザクションの時間を最小限に抑えたす。 ただし、アプリケヌションの負荷が OLAP ず OLTP のハむブリッドである堎合は、レポヌトの䜜成などの長期的な操䜜だけでなく、頻繁な曎新や短いク゚リも同時に実行される可胜性がありたす。 このような状況では、負荷を異なる拠点に分散するこずを怜蚎する䟡倀がありたす。そうするこずで、それぞれの拠点をより埮調敎できるようになりたす。

別の䟋ずしお、プロファむルが均䞀であっおも、デヌタベヌスに非垞に高い負荷がかかっおいる堎合、最も積極的な AUTOVACUUM でも察応できず、肥倧化が発生する可胜性がありたす。 スケヌリング (垂盎たたは氎平) が唯䞀の解決策です。

AUTOVACUUM を蚭定したにもかかわらず、肥倧化が続く状況で䜕をすべきか。

チヌム バキュヌムフル テヌブルずむンデックスの内容を再構築し、関連するデヌタのみをそれらに残したす。 肥倧化を解消するために、この機胜は完党に機胜したすが、実行䞭にテヌブルに察する排他ロックが取埗され (AccessExclusiveLock)、このテヌブルに察するク゚リの実行は蚱可されず、遞択さえできなくなりたす。 サヌビスたたはその䞀郚をしばらく停止しおもよい堎合 (デヌタベヌスずハヌドりェアのサむズに応じお数十分から数時間)、このオプションが最適です。 残念ながら、定期メンテナンス䞭は VACUUM FULL を実行する時間がないため、この方法は適しおいたせん。

チヌム CLUSTER VACUUM FULL ず同じ方法でテヌブルの内容を再構築したすが、ディスク䞊でのデヌタの物理的な順序に基づいおむンデックスを指定できたす (ただし、将来的には新しい行の順序は保蚌されたせん)。 特定の状況では、これはむンデックスによる耇数のレコヌドの読み取りなど、倚数のク゚リにずっお優れた最適化になりたす。 このコマンドの欠点は VACUUM FULL の欠点ず同じで、操䜜䞭にテヌブルがロックされたす。

チヌム 再玢匕 前の 12 ぀ず䌌おいたすが、テヌブルの特定のむンデックスたたはすべおのむンデックスを再構築したす。 ロックは少し匱くなりたす。テヌブルに察する ShareLock (倉曎は犁止されたすが、遞択は蚱可されたす)、および再構築されるむンデックスに察する AccessExclusiveLock (このむンデックスを䜿甚するク゚リをブロックしたす)。 ただし、Postgres の XNUMX バヌゞョンではパラメヌタが登堎したした。 同時にこれにより、レコヌドの同時远加、倉曎、削陀をブロックするこずなくむンデックスを再構築できたす。

Postgres の以前のバヌゞョンでは、次を䜿甚しお REINDEX CONCURRENTLY ず同様の結果を達成できたす。 むンデックスを同時に䜜成する。 これにより、厳密なロック (䞊列ク゚リを劚げない ShareUpdateExclusiveLock) を䜿甚せずにむンデックスを䜜成し、叀いむンデックスを新しいむンデックスに眮き換えお、叀いむンデックスを削陀できたす。 これにより、アプリケヌションを劚げるこずなく、むンデックスの肥倧化を解消できたす。 むンデックスを再構築するずきは、ディスク サブシステムに远加の負荷がかかるこずを考慮するこずが重芁です。

したがっお、むンデックスに぀いおは肥倧化を「その堎で」解消する方法があるずしおも、テヌブルに぀いおは存圚したせん。 ここで、さたざたな倖郚拡匵機胜が掻躍したす。 pg_repack (以前の pg_reorg)、 pgコンパクト, pgコンパクトテヌブル その他。 この蚘事では、それらを比范するこずはせず、いく぀かの倉曎を加えお私たち自身が䜿甚しおいる pg_repack に぀いおのみ説明したす。

pg_repack の仕組み

Postgres: 肥倧化、pg_repack、遅延制玄
むンデックスや制限があり、残念ながら肥倧化しおしたった、たったく普通のテヌブルがあるずしたす。 pg_repack の最初のステップは、実行䞭のすべおの倉曎に関するデヌタを保存するログ テヌブルを䜜成するこずです。 トリガヌは、挿入、曎新、削陀のたびにこれらの倉曎を耇補したす。 次に、構造的には元のテヌブルず䌌たテヌブルが䜜成されたすが、デヌタの挿入プロセスが遅くならないように、むンデックスや制限はありたせん。

次に、pg_repack は叀いテヌブルから新しいテヌブルにデヌタを転送し、無関係な行をすべお自動的に陀倖しおから、新しいテヌブルのむンデックスを䜜成したす。 これらすべおの操䜜の実行䞭に、倉曎がログ テヌブルに蓄積されたす。

次のステップでは、倉曎を新しいテヌブルに転送したす。 移行は数回繰り返しお実行され、ログ テヌブルに残っおいる゚ントリが 20 未満になるず、pg_repack は匷力なロックを取埗し、最新のデヌタを移行し、Postgres システム テヌブル内の叀いテヌブルを新しいテヌブルに眮き換えたす。 これは、テヌブルで䜜業できない唯䞀か぀非垞に短い時間です。 この埌、叀いテヌブルずログのあるテヌブルが削陀され、ファむル システム内のスペヌスが解攟されたす。 プロセスは完了です。

理論的にはすべおが玠晎らしく芋えたすが、実際にはどうなるでしょうか? pg_repack を負荷なしず負荷䞋でテストし、途䞭で停止した堎合 (぀たり、Ctrl+C を䜿甚した堎合) の動䜜を確認したした。 すべおの怜査結果は陜性でした。

私たちは食料品店に行きたしたが、すべおが期埅通りにはいきたせんでした。

初のパンケヌキ発売

最初のクラスタヌで、䞀意制玄の違反に関する゚ラヌを受け取りたした。

$ ./pg_repack -t tablename -o id
INFO: repacking table "tablename"
ERROR: query failed: 
    ERROR: duplicate key value violates unique constraint "index_16508"
DETAIL:  Key (id, index)=(100500, 42) already exists.

この制限には自動生成された名前、index_16508 が付けられたした。これは pg_repack によっお䜜成されたした。 その構成に含たれる属性に基づいお、それに察応する「私たちの」制玄を決定したした。 問題は、これが完党に通垞の制限ではなく、延期された制限であるこずが刀明したした (遅延制玄)、぀たりその怜蚌は SQL コマンドよりも埌で実行されるため、予期しない結果が生じたす。

遅延制玄: 遅延制玄が必芁な理由ずその仕組み

延期された制限に関するちょっずした理論。
簡単な䟋を考えおみたしょう。ディレクトリ内の車の名前ず順序ずいう XNUMX ぀の属性を持぀車のテヌブル リファレンス ブックがありたす。
Postgres: 肥倧化、pg_repack、遅延制玄

create table cars
(
  name text constraint pk_cars primary key,
  ord integer not null constraint uk_cars unique
);



XNUMX 台目ず XNUMX 台目の車を亀換する必芁があるずしたす。 簡単な解決策は、最初の倀を XNUMX 番目の倀に曎新し、XNUMX 番目の倀を最初の倀に曎新するこずです。

begin;
  update cars set ord = 2 where name = 'audi';
  update cars set ord = 1 where name = 'bmw';
commit;

しかし、このコヌドを実行するず、テヌブル内の倀の順序が䞀意であるため、制玄違反が予想されたす。

[23305] ERROR: duplicate key value violates unique constraint “uk_cars”
Detail: Key (ord)=(2) already exists.

どうすれば別の方法で実行できたすか? オプション 1: テヌブルに存圚しないこずが保蚌されおいる泚文に、「-XNUMX」などの远加の倀眮換を远加したす。 プログラミングでは、これを「XNUMX ぀の倉数の倀を XNUMX 番目の倉数を介しお亀換する」ず呌びたす。 この方法の唯䞀の欠点は、远加の曎新が必芁なこずです。

オプション 1: 泚文倀に敎数ではなく浮動小数点デヌタ型を䜿甚するようにテヌブルを再蚭蚈したす。 次に、倀を 2.5 から XNUMX に曎新するず、最初の゚ントリは自動的に XNUMX 番目ず XNUMX 番目の゚ントリの間に「立ちたす」。 この解決策は機胜したすが、XNUMX ぀の制限がありたす。 たず、倀がむンタヌフェむスのどこかで䜿甚されおいる堎合は機胜したせん。 次に、デヌタ型の粟床に応じお、すべおのレコヌドの倀を再蚈算する前に可胜な挿入の数が制限されたす。

オプション XNUMX: 制玄を延期しお、コミット時にのみチェックされるようにしたす。

create table cars
(
  name text constraint pk_cars primary key,
  ord integer not null constraint uk_cars unique deferrable initially deferred
);

最初のリク゚ストのロゞックにより、コミット時にすべおの倀が䞀意であるこずが保蚌されるため、リク゚ストは成功したす。

もちろん、䞊で説明した䟋は非垞に合成的なものですが、アむデアを明らかにしおいたす。 私たちのアプリケヌションでは、遅延制玄を䜿甚しお、ナヌザヌがボヌド䞊の共有りィゞェット オブゞェクトを同時に操䜜するずきに競合を解決するロゞックを実装したす。 このような制限を䜿甚するず、アプリケヌション コヌドを少し単玔にするこずができたす。

䞀般に、制玄のタむプに応じお、Postgres には制玄をチェックするための XNUMX ぀の粒床レベル (行レベル、トランザクション レベル、匏レベル) がありたす。
Postgres: 肥倧化、pg_repack、遅延制玄
出所 嘆く

CHECK ず NOT NULL は垞に行レベルでチェックされたす。衚からわかるように、その他の制限に぀いおは、さたざたなオプションがありたす。 もっず読むこずができたす ここで.

簡単に芁玄するず、倚くの状況で遅延制玄を䜿甚するず、コヌドが読みやすくなり、コマンドが枛りたす。 ただし、゚ラヌが発生した瞬間ずそれを発芋した瞬間が時間的に分離されおいるため、デバッグ プロセスが耇雑になるずいう代償を払わなければなりたせん。 もう XNUMX ぀の考えられる問題は、リク゚ストに遅延制玄が含たれる堎合、スケゞュヌラが垞に最適な蚈画を構築できるずは限らないこずです。

pg_repackの改善

遅延制玄ずは䜕かに぀いお説明したしたが、それらは私たちの問題ずどのように関係するのでしょうか? 先ほど受け取った゚ラヌを思い出しおください。

$ ./pg_repack -t tablename -o id
INFO: repacking table "tablename"
ERROR: query failed: 
    ERROR: duplicate key value violates unique constraint "index_16508"
DETAIL:  Key (id, index)=(100500, 42) already exists.

これは、デヌタがログ テヌブルから新しいテヌブルにコピヌされるずきに発生したす。 これは奇劙に芋えるので... ログ テヌブルのデヌタは、゜ヌス テヌブルのデヌタずずもにコミットされたす。 元のテヌブルの制玄を満たしおいる堎合、新しいテヌブルで同じ制玄に違反する可胜性はありたすか?

結局のずころ、問題の根本は pg_repack の前のステップにあり、むンデックスのみを䜜成したすが、制玄は䜜成したせん。叀いテヌブルには䞀意の制玄があり、新しいテヌブルは代わりに䞀意のむンデックスを䜜成したした。

Postgres: 肥倧化、pg_repack、遅延制玄

ここで、制玄が通垞で遅延されおいない堎合、代わりに䜜成される䞀意のむンデックスはこの制玄ず同等であるこずに泚意するこずが重芁です。 Postgres の䞀意の制玄は、䞀意のむンデックスを䜜成するこずで実装されたす。 ただし、遅延制玄の堎合、むンデックスは遅延できず、SQL コマンドの実行時に垞にチェックされるため、動䜜は同じではありたせん。

したがっお、問題の本質はチェックの「遅延」にありたす。元のテヌブルではコミット時に発生し、新しいテヌブルでは SQL コマンドの実行時に発生したす。 これは、チェックが䞡方のケヌスで同じように実行されるこず、぀たり垞に遅延されるか、垞に即時にチェックが実行されるこずを確認する必芁があるこずを意味したす。

それで、私たちはどんなアむデアを持っおいたのでしょうか

deferred ず同様のむンデックスを䜜成したす

最初のアむデアは、䞡方のチェックを即時モヌドで実行するこずです。 これにより、いく぀かの誀怜出制限が生成される可胜性がありたすが、そのような制限がほずんどない堎合、そのような競合はナヌザヌにずっお通垞の状況であるため、ナヌザヌの䜜業には圱響したせん。 たずえば、XNUMX 人のナヌザヌが同時に同じりィゞェットの線集を開始し、XNUMX 番目のナヌザヌのクラむアントが、そのりィゞェットが最初のナヌザヌによっお線集のためにすでにブロックされおいるずいう情報を受け取る時間がない堎合に発生したす。 このような状況では、サヌバヌは XNUMX 番目のナヌザヌを拒吊し、クラむアントは倉曎をロヌルバックしおりィゞェットをブロックしたす。 少し埌、最初のナヌザヌが線集を完了するず、XNUMX 番目のナヌザヌはりィゞェットがブロックされなくなったずいう情報を受け取り、アクションを繰り返すこずができるようになりたす。

Postgres: 肥倧化、pg_repack、遅延制玄

チェックが垞に非遅延モヌドであるこずを保蚌するために、元の遅延制玄ず同様の新しいむンデックスを䜜成したした。

CREATE UNIQUE INDEX CONCURRENTLY uk_tablename__immediate ON tablename (id, index);
-- run pg_repack
DROP INDEX CONCURRENTLY uk_tablename__immediate;

テスト環境では、予想される゚ラヌがわずか数件だけ発生したした。 成功 本番環境で pg_repack を再床実行したずころ、5 時間の䜜業で最初のクラスタヌで XNUMX ぀の゚ラヌが発生したした。 これは蚱容できる結果です。 ただし、すでに XNUMX 番目のクラスタヌでぱラヌの数が倧幅に増加しおおり、pg_repack を停止する必芁がありたした。

なぜそうなったのでしょうか? ゚ラヌが発生する可胜性は、同時に同じりィゞェットを䜿甚しおいるナヌザヌの数によっお異なりたす。 どうやら、その時点では、最初のクラスタヌに保存されおいるデヌタの競合倉曎は、他のクラスタヌに比べおはるかに少なかったようです。 私たちはただ「幞運だった」だけです。

その考えはうたくいきたせんでした。 その時点で、他の XNUMX ぀の解決策が芋぀かりたした。それは、アプリケヌション コヌドを曞き盎しお遅延制玄をなくすか、pg_repack に遅延制玄を凊理するように「教える」こずです。 私たちはXNUMX番目のものを遞びたした。

新しいテヌブルのむンデックスを元のテヌブルの遅延制玄に眮き換えたす。

改蚂の目的は明らかです。元のテヌブルに遅延制玄がある堎合、新しいテヌブルにはむンデックスではなくそのような制玄を䜜成する必芁がありたす。

倉曎をテストするために、簡単なテストを䜜成したした。

  • 遅延制玄ず XNUMX ぀のレコヌドを持぀テヌブル。
  • 既存のレコヌドず競合するデヌタをルヌプに挿入したす。
  • 曎新を実行したす。デヌタは競合しなくなりたした。
  • 倉曎をコミットしたす。

create table test_table
(
  id serial,
  val int,
  constraint uk_test_table__val unique (val) deferrable initially deferred 
);

INSERT INTO test_table (val) VALUES (0);
FOR i IN 1..10000 LOOP
  BEGIN
    INSERT INTO test_table VALUES (0) RETURNING id INTO v_id;
    UPDATE test_table set val = i where id = v_id;
    COMMIT;
  END;
END LOOP;

pg_repack の元のバヌゞョンは最初の挿入時に垞にクラッシュしたしたが、倉曎されたバヌゞョンぱラヌなしで動䜜したした。 玠晎らしい。

運甚環境に移行するず、ログ テヌブルから新しいテヌブルにデヌタをコピヌする同じフェヌズで再び゚ラヌが発生したす。

$ ./pg_repack -t tablename -o id
INFO: repacking table "tablename"
ERROR: query failed: 
    ERROR: duplicate key value violates unique constraint "index_16508"
DETAIL:  Key (id, index)=(100500, 42) already exists.

兞型的な状況: テスト環境ではすべおが動䜜するのに、本番環境では動䜜しない?!

APPLY_COUNT ず XNUMX ぀のバッチの結合点

コヌドを文字通り XNUMX 行ず぀分析し始め、重芁な点を発芋したした。デヌタはログ テヌブルから新しいテヌブルにバッチで転送され、APPLY_COUNT 定数はバッチのサむズを瀺しおいたした。

for (;;)
{
num = apply_log(connection, table, APPLY_COUNT);

if (num > MIN_TUPLES_BEFORE_SWITCH)
     continue;  /* there might be still some tuples, repeat. */
...
}

問題は、元のトランザクションのデヌタ (耇数の操䜜が制玄に違反する可胜性がある) が転送されるず、最終的に XNUMX ぀のバッチの結合点に到達する可胜性があるこずです。コマンドの半分は最初のバッチでコミットされ、残りの半分はコミットされたす。 XNUMX番目に。 ここで、運次第ですが、チヌムが最初のバッチで䜕も違反しなければ、すべお問題ありたせんが、違反した堎合は、゚ラヌが発生したす。

APPLY_COUNT は 1000 レコヌドに等しいため、テストが成功した理由が説明されおいたす。テストでは「バッチ ゞャンクション」のケヌスがカバヌされおいたせんでした。 挿入ず曎新ずいう 500 ぀のコマンドを䜿甚したため、XNUMX ぀のコマンドの正確に XNUMX トランザクションが垞にバッチに配眮され、問題は発生したせんでした。 XNUMX 番目の曎新を远加した埌、線集が機胜しなくなりたした。

FOR i IN 1..10000 LOOP
  BEGIN
    INSERT INTO test_table VALUES (1) RETURNING id INTO v_id;
    UPDATE test_table set val = i where id = v_id;
    UPDATE test_table set val = i where id = v_id; -- one more update
    COMMIT;
  END;
END LOOP;

したがっお、次のタスクは、XNUMX ぀のトランザクションで倉曎された元のテヌブルのデヌタが、XNUMX ぀のトランザクション内で新しいテヌブルに配眮されるこずを確認するこずです。

バッチ凊理の拒吊

そしお、やはり解決策は XNUMX ぀ありたした。 たず、バッチぞの分割を完党に攟棄し、XNUMX ぀のトランザクションでデヌタを転送したしょう。 この゜リュヌションの利点はそのシンプルさです。必芁なコヌドの倉曎は最小限で枈みたした (ちなみに、叀いバヌゞョンでは、pg_reorg はたったく同じように動䜜したした)。 しかし、問題がありたす。私たちは長期にわたるトランザクションを䜜成しおいたす。これは、前述したように、新たな肥倧化の出珟に察する脅嚁です。

XNUMX 番目の解決策はより耇雑ですが、おそらくより正確です。テヌブルにデヌタを远加したトランザクションの識別子を䜿甚しおログ テヌブルに列を䜜成したす。 その埌、デヌタをコピヌするずきに、この属性によっおデヌタをグルヌプ化し、関連する倉曎が䞀緒に転送されるようにするこずができたす。 バッチは耇数のトランザクション (たたは XNUMX ぀の倧きなトランザクション) から圢成され、そのサむズはこれらのトランザクションで倉曎されたデヌタの量によっお異なりたす。 異なるトランザクションからのデヌタはランダムな順序でログ テヌブルに入力されるため、以前のように順番に読み取るこずはできなくなるこずに泚意するこずが重芁です。 tx_id によるフィルタリングを䜿甚した各リク゚ストの seqscan はコストがかかりすぎるため、むンデックスが必芁ですが、曎新のオヌバヌヘッドによりメ゜ッドの速床も䜎䞋したす。 䞀般に、い぀ものように、䜕かを犠牲にする必芁がありたす。

そこで、より簡単な最初のオプションから始めるこずにしたした。 たず、長時間のトランザクションが実際に問題ずなるかどうかを理解する必芁がありたした。 叀いテヌブルから新しいテヌブルぞの䞻なデヌタ転送も 1 ぀の長いトランザクションで発生するため、質問は「このトランザクションをどれくらい増やすか?」ずいうものに倉わりたした。 最初のトランザクションの継続時間は、䞻にテヌブルのサむズによっお決たりたす。 新しいものの持続時間は、デヌタ転送䞭にテヌブルに蓄積される倉曎の数によっお異なりたす。 負荷の匷さに぀いお。 pg_repack の実行はサヌビス負荷が最小限のずきに行われ、倉曎の量はテヌブルの元のサむズに比べお䞍釣り合いに小さかったです。 新しいトランザクションの時間は無芖できるず刀断したした (比范のために、平均しお 2 時間 3  XNUMX 分です)。

実隓結果は肯定的でした。 本番環境でも起動したす。 わかりやすくするために、実行埌のデヌタベヌスの XNUMX ぀のサむズを瀺す図を次に瀺したす。

Postgres: 肥倧化、pg_repack、遅延制玄

私たちはこの解決策に完党に満足しおいたので、XNUMX 番目の解決策を実装しようずはしたせんでしたが、拡匵機胜の開発者ず話し合う可胜性を怜蚎しおいたす。 残念ながら、珟圚のリビゞョンはただ公開の準備ができおいたせん。これは、独自の遅延制限に関する問題を解決しただけであり、本栌的なパッチの堎合は他のタむプのサポヌトを提䟛する必芁があるためです。 将来的にはこれができるようになるこずを期埅しおいたす。

おそらく、なぜ私たちは pg_repack の修正ずいうこの話に関䞎し、たずえばその類䌌物を䜿甚しなかったのかず疑問に思われるかもしれたせん。 私たちもある時点でこれに぀いお考えたしたが、遅延制玄のないテヌブルで以前にこれを䜿甚したずいう前向きな経隓が、問題の本質を理解しお修正しようずする動機になりたした。 さらに、他の゜リュヌションを䜿甚する堎合もテストの実斜に時間がかかるため、たずその゜リュヌションの問題を解決するこずに努め、劥圓な時間内に解決できないこずがわかったら、類䌌の゜リュヌションを怜蚎し始めるこずにしたした。 。

所芋

私たち自身の経隓に基づいお掚奚できるこず:

  1. お腹の匵りを芳察しおください。 監芖デヌタに基づいお、自動バキュヌムがどの皋床適切に構成されおいるかを理解できたす。
  2. AUTOVACUUM を調敎しお膚匵を蚱容レベルに保ちたす。
  3. 肥倧化が䟝然ずしお進行しおおり、すぐに䜿甚できるツヌルを䜿甚しおそれを克服できない堎合は、倖郚拡匵機胜を䜿甚するこずを恐れないでください。 重芁なのは、すべおを適切にテストするこずです。
  4. ニヌズに合わせお倖郚゜リュヌションを倉曎するこずを恐れないでください。堎合によっおは、独自のコヌドを倉曎するよりも効果的で、さらに簡単な堎合もありたす。

出所 habr.com

コメントを远加したす