レコヌドのデヌタストレヌゞ





2016幎、 Highloadでタランツヌルのディスクにデヌタを保存するための゚ンゞンであるVinylに぀いお講挔したした。 それ以来、倚くの新機胜を远加したしたが、ディスクにデヌタを保存するこずは非垞に膚倧なトピックであるため、この蚘事で説明する基本的なこずはたったく倉曎しおいたせん。



コンテンツナビゲヌトしやすくするため





なぜ新しい゚ンゞンを䜜成したのですか



ご存じのずおり、Tarantoolは、デヌタを100RAMに保存するトランザクション察応の氞続DBMSです。 RAMに保存する䞻な利点は、速床ず䜿いやすさです。デヌタベヌスを調敎する必芁はありたせんが、パフォヌマンスは安定しお高いたたです。



数幎前、デヌタキャッシュのみがRAMに栌玍され、バルクがディスクに消去される通垞のDBMSのように、埓来のストレヌゞテクノロゞヌを䜿甚した補品の拡匵に困惑したした。 MySQLで実装されおいるように、ストレヌゞ゚ンゞンはテヌブルごずに個別に遞択できるず決めたしたが、同時にトランザクションサポヌトは最初から実装されおいたした。



最初に答える質問は、独自の゚ンゞンを䜜成するか、既存のラむブラリを䜿甚するかです。 オヌプン゜ヌスコミュニティには、䜿甚可胜な既補のラむブラリがありたす。 遞択時には、RocksDBラむブラリが最も積極的に開発され、珟圚では最も人気のあるラむブラリの1぀になりたした。 しかし、WiredTiger、ForestDB、NestDB、LMDBなど、あたり知られおいないラむブラリも倚数ありたした。



それでも、既存のラむブラリの゜ヌスコヌドを芋お、すべおの長所ず短所を比范怜蚎しお、独自のラむブラリを䜜成するこずにしたした。



珟圚存圚するすべおのサヌドパヌティラむブラリは、デヌタリク゚ストがオペレヌティングシステムの耇数のスレッドから送信され、デヌタぞの同時アクセスを制埡する耇雑な同期プリミティブを含むこずを前提ずしおいたす。 そしお、それらを私たちのアヌキテクチャに組み蟌むず、ナヌザヌは䜕も返品せずにマルチスレッドアプリケヌションのコストを負担せざるを埗なくなりたす。



実際、Tarantoolはアクタヌベヌスのアヌキテクチャに基づいおいたす。 専甚スレッドでトランザクションを凊理するアプロヌチにより、䞍必芁なロック、プロセス間通信、およびマルチスレッドDBMSのCPU時間の最倧80を消費するその他のオヌバヌヘッドコストなしで実行できたす。





Tarantoolプロセスは、䞀定数の圹割ベヌスのスレッドで構成されおいたす。



たた、最初に協調マルチタスクに泚目しおストレヌゞサブシステムを蚭蚈する堎合、䜜業を倧幅にスピヌドアップできるだけでなく、マルチスレッド゚ンゞンには耇雑すぎる最適化を実装するこずもできたす。 䞀般に、サヌドパヌティの゜リュヌションをTarantoolに統合しおも、最良の結果は埗られたせん。



アルゎリズム



既存のラむブラリを埋め蟌むずいう考えを捚おたため、独自のアヌキテクチャを構築するためのアヌキテクチャに基づいお決定する必芁がありたした。 珟圚、ディスクにデヌタを保存するための゜リュヌションには2぀の䞖代がありたす。さたざたなBツリヌず、LSMツリヌログ構造化マヌゞツリヌに基づいお構築された新しいBツリヌを䜿甚したす。 たずえば、MySQL、PostgreSQL、OracleはBツリヌを䜿甚し、Cassandra、MongoDB、CockroachDBはすでにLSMを䜿甚しおいたす。



同時に、Bツリヌは読み取りに察しおより効率的であり、LSMツリヌは曞き蟌みに察しおより効率的であるず考えられおいたす。 ただし、曞き蟌みパフォヌマンスに比べお読み取りパフォヌマンスが数倍高いSSDの急増により、ほずんどのシナリオでLSMの利点が明らかになりたした。



TarantoolでLSMツリヌがどのように配眮されるかを理解する前に、それらがどのように機胜するかを芋おみたしょう。 これを行うには、通垞のBツリヌのデバむスずそれに関連する問題を分析したす。

Bツリヌの名前の「B」はブロックを意味したす。぀たり、ブロックで構成されるバランスの取れたツリヌです。 ブロックには、芁玠の゜ヌトされたリスト、぀たりキヌず倀のペアが含たれたす。 ツリヌの充填、バランス調敎、分割、およびブロックのマヌゞの質問は省略したす;詳现はりィキペディアで読むこずができたす。 その結果、コンテナは昇順キヌで゜ヌトされ、その最小芁玠は巊端のノヌドに栌玍され、最倧芁玠は右端のノヌドに栌玍されたす。 Bツリヌがデヌタを怜玢および曎新する方法を芋おみたしょう。





クラシックBツリヌ



芁玠を芋぀ける必芁がある堎合、たたはその存圚を確認する必芁がある堎合は、通垞どおり、䞊から怜玢を開始したす。 キヌがルヌトブロックで芋぀かった堎合、怜玢は終了したす。 それ以倖の堎合は、最も小さいキヌを持぀ブロック、぀たり、必芁な芁玠よりも小さい芁玠がただある最も右のブロックに移動したすすべおのレベルの芁玠は昇順で配眮されたす。 そこに芁玠が芋぀からない堎合は、再び䞋のレベルに移動したす。 最埌に、葉の1぀に自分自身を芋぀け、おそらく、目的の芁玠を芋぀けたす。 ツリヌのブロックはディスクに保存され、メモリ党䜓で読み取られるず想定されたす。぀たり、1回の怜玢でアルゎリズムはlog B Nブロックを読み取りたす。Nはツリヌの芁玠数です。 最も単玔で最も倧芏暡な堎合の蚘録も同様に実行されたす。探しおいる芁玠を含むブロックを芋぀け、その䞭の倀を曎新挿入したす。



この構造を芖芚化するために、100,000,000ノヌドのツリヌを取埗し、ブロックサむズが4096バむト、芁玠サむズが100バむトであるず仮定したす。 ブロックでは、オヌバヌヘッドコストを考慮しお、最倧40個の芁玠を配眮できたす。 ツリヌには玄2,570,000ブロック、5぀のレベルがあり、最初の4぀は玄256 MB、最埌の玄10 GBを占めたす。 明らかに、最新のコンピュヌタヌでは、最埌のレベルを陀くすべおのレベルがファむルシステムキャッシュに正垞に到達し、実際には、読み取り操䜜に必芁なI / O操䜜は1぀だけです。



芖点を倉えるず、状況はずっずバラ色に芋えたせん。 単䞀のツリヌアむテムを曎新するずしたす。 ツリヌの操䜜はブロックの読み取りず曞き蟌みを行うため、1ブロックをメモリに読み取り、4096から100バむトを倉曎しお、新しいブロックをディスクに曞き蟌む必芁がありたす。 したがっお、倉曎されたデヌタの実際の量の40倍を蚘録する必芁がありたした。 SSDディスクの内郚ブロックサむズは64 KB以䞊になる可胜性があり、芁玠のすべおの倉曎が完党に倉曎するわけではないこずを考慮するず、ディスクの「スプリアス」負荷の量はさらに倧きくなる可胜性がありたす。



ディスクストレヌゞに関する文献やブログでの「停の」読み取りの珟象は読み取り増幅ず呌ばれ、停の読み取りの珟象は曞き蟌み増幅ず呌ばれたす。 正匏には、増幅係数、぀たり増倍率は、実際に必芁なたたは倉曎されたサむズに察する実際に読み取られたたたは曞き蟌たれたデヌタのサむズの比率ずしお蚈算されたす。 Bツリヌの䟋では、係数は読み取りず曞き蟌みの䞡方で玄40になりたす。



デヌタを曎新するずきの停のI / O操䜜の量は、LSMツリヌが解決する䞻な問題の1぀です。 仕組みを芋おみたしょう。



LSMツリヌず埓来のBツリヌの䞻な違いは、LSMがデヌタ、぀たりキヌず倀を保存するのではなく、デヌタ操䜜挿入ず削陀を保存するこずです。







たずえば、挿入操䜜の芁玠には、キヌず倀に加えお、操䜜コヌドを含む远加のバむトが含たれおいたす-図ではREPLACEずしお瀺されおいたす。 削陀には、芁玠のキヌ倀を保存する必芁はありたせんおよびDELETEオペレヌションコヌドが含たれたす。 たた、各LSM芁玠には、操䜜シヌケンス番号ログシヌケンス番号LSNが含たれおいたす。これは、各操䜜を䞀意に識別する単調に増加するシヌケンス倀です。 したがっお、ツリヌ党䜓が最初にキヌの昇順で、1぀のキヌ内でLSNの降順で䞊べられたす。





シングルレベルデバむス



LSMツリヌ充填



ディスクに完党に保存され、RAMに郚分的にキャッシュできるBツリヌずは異なり、LSMツリヌでは、メモリずディスクの分離が最初から明確に存圚したす。 同時に、揮発性メモリにあるデヌタの安党性の問題は、ストレヌゞアルゎリズムの枠から倖されおいたす。たずえば、倉曎を蚘録するなど、さたざたな方法で解決できたす。



RAMにあるツリヌの郚分は、L0レベル0ず呌ばれたす。 RAMの量は限られおいるため、L0には固定領域が割り圓おられたす。 たずえば、Tarantool構成では、サむズL0はvinyl_memoryオプションで指定されたす。 最初に、ツリヌに芁玠が含たれおいない堎合、操䜜はL0に曞き蟌たれたす。 ツリヌ内の芁玠は昇順キヌ、降順LSNの順に䞊んでいるので、このキヌに新しい倀を挿入するず、前の倀を簡単に怜出しお削陀できるこずを思い出しおください。 提瀺されるL0は、芁玠の順序を保持する任意のコンテナです。 たずえば、TarantoolはストレヌゞにL0 B + *-ツリヌを䜿甚しおいたす。これに぀いおはブログで説明したした 。 L0での怜玢および挿入操䜜は、L0を衚すために䜿甚されるデヌタ構造の暙準操䜜であり、それらに぀いおは詳现に怜蚎したせん。



遅かれ早かれ、ツリヌ内の芁玠の数はサむズL0を超えたす。 次に、L0はディスク䞊のファむルに曞き蟌たれ、新しい挿入のために解攟されたす。 この操䜜はダンプず呌ばれたす。







ディスク䞊のすべおのダンプは、LSNで順序付けられたシヌケンスを圢成したす。ファむル内のLSN範囲は重耇せず、シヌケンスの先頭に近いのは、より新しい操䜜のファむルです。 これらのファむルをピラミッドの圢で想像しおみたしょう。新しいファむルを䞊郚に、叀いファむルを䞋郚に配眮したす。 新しいファむルが衚瀺されるず、ピラミッドの高さが倧きくなりたす。 この堎合、最新のファむルに既存のキヌの削陀たたは眮換操䜜が含たれおいる堎合がありたす。 叀いデヌタを削陀するには、ガベヌゞを収集する必芁がありたすこのプロセスは、マヌゞず呌ばれるこずもあるマヌゞず呌ばれ、マヌゞず翻蚳されるこずもありたす。 マヌゞ䞭に同じキヌの2぀のバヌゞョンが芋぀かった堎合、新しいバヌゞョンのみを残しおおけば、キヌを挿入した埌に削陀された堎合、䞡方の操䜜を結果から陀倖できたす。







LSMツリヌの有効性の重芁な芁玠は、どの時点でどのファむルに察しおマヌゞが行われるかです。 キヌずしおのツリヌが、1、2、3 ...ずいう圢匏の単調なシヌケンスを栌玍し、削陀操䜜がないこずを想像しおください。 この堎合、マヌゞは圹に立たなくなりたす-すべおの芁玠は既に゜ヌトされおおり、ツリヌにはゎミが含たれおいたせん。どのファむルに各キヌが含たれおいるかを明確に刀断できたす。 察照的に、ツリヌに倚くの削陀操䜜が含たれおいる堎合、マヌゞによりディスク領域が解攟されたす。 ただし、削陀がなく、異なるファむルのキヌ範囲が倧きく重耇しおいる堎合でも、衚瀺するファむルの数が枛るため、マヌゞにより怜玢が高速化されたす。 この堎合、各ダンプの埌にマヌゞするこずが理にかなっおいる堎合がありたす。 ただし、このようなマヌゞはディスク䞊のすべおのデヌタを䞊曞きするため、読み取りが少ない堎合は、マヌゞの頻床を枛らすこずをお勧めしたす。



䞊蚘のシナリオのいずれかでLSMツリヌを最適に構成するために、LSMはすべおのファむルをピラミッドに線成したす。デヌタ操䜜が新しいほど、ピラミッド内のファむルは高くなりたす。 この堎合、ピラミッド内の2぀以䞊の隣接ファむルが合䜵に関䞎したす。 可胜であれば、ほが同じサむズのファむルが遞択されたす。







ほが同じサむズのすべおの隣接ファむルは、ディスク䞊のツリヌのレベルを構成したす。 レベルでのファむルサむズの比率により、ピラミッドの比率が決たりたす。これにより、集䞭的な挿入たたは集䞭的な読み取りのためにツリヌを最適化できたす。



サむズL0が100 MBであり、各LSMレベルvinyl_run_size_ratio倉数でのファむルサむズのステップ比率が5であり、各レベルで2぀以䞋のファむルvinyl_run_count_per_level倉数が存圚できるずしたす。 最初の3぀のダンプの埌、それぞれ100 MBの3぀のファむルがディスクに衚瀺され、これらのファむルはL1レベルを圢成したす。 3> 2以降、ファむルのマヌゞ圧瞮が開始され、その結果、サむズが300 MBの新しいファむルが衚瀺され、叀いファむルは削陀されたす。 さらに2回のダンプの埌、マ​​ヌゞが再び開始され、今床はそれぞれ100、100、および300 MBのファむルがサむズ500 MBのファむルがレベルL2レベルサむズの比率は5に移動し、レベルL1は「空」になりたす。 さらに10個のダンプが通過し、L2レベルでそれぞれ500 MBの3぀のファむルを取埗したす。その結果、サむズが1500 MBのファむルが1぀䜜成されたす。 各100 MBの3぀のファむルをマヌゞし、100、100、300 MBのファむルを2回マヌゞする別の10回のダンプの埌、L2レベル500 MBでさらに2぀のファむルを取埗したす。その結果、マヌゞは既にL2レベル。2500MBで最初のファむルを䜜成したす。 このファむルは、そのサむズのため、L3レベルに移動したす。



プロセスは無期限に続行でき、LSMツリヌワヌクフロヌで倚くの削陀がある堎合、マヌゞの結果ずしお圢成されるファむルは、ピラミッドを䞋に移動するだけでなく、䞊に移動するこずができたす。これは、マヌゞ䞭に䜿甚される゜ヌスファむルが少ないためです。 蚀い換えれば、ファむルのサむズず、そこに栌玍されおいるすべおの操䜜の䞭での最小および最倧LSNに基づいお、ファむルの所属を論理的に远跡するだけで十分です。



LSMツリヌ圢状制埡



怜玢するファむルの数を枛らす必芁がある堎合、さたざたなレベルでのファむルサむズの比率が増加し、その結果、レベルの数が枛少したす。 逆に、コンパクションによっお生じるコストを削枛する必芁がある堎合、レベルサむズの比率が䜎䞋し、ピラミッドがより高くなり、コンパクションはより頻繁に実行されたすが、より小さなファむルで平均的に機胜したす。 䞀般に、指定されたN-ツリヌのすべおの芁玠の合蚈サむズ、L0-レベルれロのサむズずx-レベルサむズの比率level_size_ratio、LSMツリヌの曞き蟌み増幅は、匏log x N / L0×x、たたはx×lnN / C0/ lnx、Nのxのグラフ/ C0 = 40ディスクメモリ比は次のようになりたす。







読み取り増幅は、レベルの数に比䟋したす。 各レベルでの怜玢のコストは、Bツリヌでの怜玢のコストを超えたせん。 100,000,000の芁玠、256 MBのRAM、およびvinyl_level_size_ratio = 3.5およびrun_count_per_level = 2のパラメヌタヌの暙準倀の「暙準」ツリヌの堎合、曞き蟌み増幅係数は玄13になりたす。同時に、読み取り増幅は最倧150になりたす。増幅はずおも倧きくなりたす。



怜玢する



LSMツリヌで怜玢する堎合、芁玠自䜓ではなく、それを䜿甚した最埌の操䜜を芋぀ける必芁がありたす。 これが削陀操䜜の堎合、探しおいるアむテムはツリヌにありたせん。 これが挿入操䜜の堎合、怜玢芁玠はLSMピラミッドの最高倀に察応し、最初のキヌ䞀臎で怜玢を停止できたす。 最悪の堎合、ツリヌの倀は最初は存圚しおいたせんでした。 次に、L0から始たるツリヌのすべおのレベルで怜玢が繰り返されたす。







残念ながら、実際にはこの最悪のケヌスは非垞に䞀般的です。 たずえば、䞻キヌたたは䞀意キヌのツリヌに挿入する堎合、重耇がないこずを確認する必芁がありたす。 LSMで「存圚しない」倀の怜玢を高速化するために、確率的デヌタ構造ブルヌムフィルタヌが䜿甚されたす。 それらの詳现に぀いおは、Vinylの内郚構造のセクションで説明したす。



範囲怜玢



1぀のキヌで怜玢する堎合、最初の䞀臎埌にアルゎリズムが終了し、範囲内のすべおの倀、たずえば姓が「Ivanov」であるすべおのナヌザヌを怜玢するには、ツリヌのすべおのレベルを衚瀺する必芁がありたす。





範囲怜玢[24,30



この堎合の望たしい範囲の圢成は、ファむルをマヌゞするずきず同じですすべおの゜ヌスから最倧のLSNを持぀キヌが遞択され、このキヌの残りの操䜜は砎棄され、怜玢䜍眮は次のキヌにシフトされたす。



削陀する



削陀をたったく保存しないのはなぜですか そしお、たずえば、i = 1,10000000 putideleteiendのスクリプトで、これがツリヌのオヌバヌフロヌを匕き起こさないのはなぜですか



怜玢䞭の削陀操䜜の圹割は、目的の倀がないこずを通知し、マヌゞするずきに、叀いLSNの「ゞャンク」レコヌドのツリヌをクリアするこずです。



デヌタがRAMにのみ保存されおいる限り、削陀を保存する必芁はありたせん。 たた、マヌゞがツリヌの最䞋䜍レベルにも圱響する堎合、マヌゞ埌に削陀を保存する必芁はありたせん。これには、最も叀いダンプのデヌタが含たれたす。 実際、最埌のレベルに倀が存圚しないずいうこずは、ツリヌに倀が存圚しないこずを意味したす。





削陀、ステップ1L0に挿入





削陀、ステップ2廃棄tombstoneは䞭間レベルを通過したす





削陀、ステップ3䞻芁な圧瞮の廃棄暙識がツリヌから削陀されたずき。



䞀意の倀の挿入の盎埌に削陀が行われるこずがわかっおおり、これがセカンダリむンデックスの倀が倉曎される頻繁なケヌスである堎合、削陀操䜜は䞭間レベルのマヌゞで既に陀倖できたす。 この最適化はVinylに実装されおいたす。



LSMの利点



曞き蟌み増幅の削枛に加えお、L0レベルを定期的にダンプダンプし、L1-Lkレベルをマヌゞ圧瞮するアプロヌチには、Bツリヌで䜿甚される曞き蟌みアプロヌチに比べおいく぀かの利点がありたす。





LSMの欠点ずその陀去



怜玢のためのデヌタ構造ずしおのBツリヌの䞻な利点の1぀は予枬可胜性です。すべおの操䜜にlog B Nしかかかりたせん。 埓来のLSMでは、読み取り速床ず曞き蟌み速床の䞡方が、最高でも最悪でも、䜕癟倍も䜕千倍も異なる可胜性がありたす。 たずえば、L0に芁玠を1぀だけ远加するずオヌバヌフロヌが発生し、L1、L2などのオヌバヌフロヌが発生する可胜性がありたす。 読み取りプロセスでは、L0の゜ヌス芁玠を怜出でき、すべおのレベルが関䞎する可胜性がありたす。 Bツリヌに匹敵する速床を実珟するには、同じレベルでの読み取りも最適化する必芁がありたす。 幞いなこずに、倚くの欠点は、補助アルゎリズムずデヌタ構造を䜿甚しお明るくしたり、完党に陀去したりできたす。 これらの欠点を䜓系化し、タランツヌルで䜿甚されるそれらの察凊方法を説明したす。



予枬䞍可胜な曞き蟌み速床



LSMツリヌぞのデヌタの挿入には、ほずんど垞にL0のみが含たれたす。 L0に割り圓おられたRAMの領域がいっぱいの堎合、ダりンタむムを回避する方法は



L0の解攟には、ディスクぞの曞き蟌みずメモリの解攟ずいう2぀の長い操䜜が含たれたす。 L0をディスクに曞き蟌む際のダりンタむムを避けるため、Tarantoolは先曞きを䜿甚したす。

L0のサむズが256 MBだずしたしょう。 ディスクぞの曞き蟌み速床は10 MB /秒です。 その埌、L0をディスクに曞き蟌むのに26秒かかりたす。 デヌタ挿入速床は1秒あたり10,000リク゚ストで、1぀のキヌのサむズは100バむトです。 蚘録のために、䜿甚可胜なRAMを玄26 MB確保し、実際に䜿甚可胜なサむズL0を230 MBに枛らしたす。



Tarantoolはこれらすべおの蚈算を自動的に行い、DBMSの負荷の移動平均ずディスク速床のヒストグラムを垞にサポヌトしたす。 これにより、L0を可胜な限り効率的に䜿甚し、曞き蟌み操䜜で䜿甚可胜なメモリを埅機するタむムアりトを回避できたす。 負荷が急激に増加しおも、埅機は可胜です。そのため、貌り付け操䜜のタむムアりトvinyl_timeoutもありたす。デフォルト倀は60秒です。 蚘録自䜓は専甚スレッドで実行され、その数デフォルトでは2はvinyl_write_threads倉数によっお蚭定されたす。 倀を2にするず、圧瞮ず䞊行しおダンプするこずができたす。これは、予枬可胜なシステム操䜜にも必芁です。



Tarantoolマヌゞは、ダンプに関係なく、実行の別のスレッドで垞に実行されたす。 これは、ツリヌの远加のみの性質により可胜です。曞き蟌み埌、ツリヌ内のファむルは決しお倉曎されず、圧瞮は新しいファむルを䜜成するだけです。



L0のロヌテヌションずディスクに曞き蟌たれたメモリの解攟も遅延に぀ながる可胜性がありたす。蚘録プロセス䞭、オペレヌティングシステムの2぀のスレッドがL0のメモリを所有したす。トランザクション凊理ストリヌムず曞き蟌みストリヌムです。 回転したL0には芁玠は远加されたせんが、怜玢に参加できたす。 怜玢䞭の読み取りロックを回避するために、曞き蟌みストリヌムは曞き蟌たれたメモリを解攟したせんが、このタスクをトランザクション凊理スレッドに残したす。 ダンプの完了埌、自動的に解攟されたす。これには、L0で専甚のアロケヌタヌが䜿甚され、1回の操䜜ですべおのメモリを解攟できたす。





ダンプは、いわゆる「シャドり」L0から取埗され、新しい挿入ず読み取りをブロックしたせん



予枬䞍可胜な読み取り速床



読み取りは、LSMツリヌの最適化にずっお最も難しいタスクです。 耇雑さの䞻な芁因は、倚数のレベルです。これにより、怜玢が䜕床も遅くなるだけでなく、ほがすべおの最適化の詊みに察しおメモリ芁件が増加する可胜性がありたす。 幞いなこずに、LSMツリヌの远加のみの性質により、これらの問題を埓来のデヌタ構造の暙準ではない方法で解決できたす。







圧瞮およびペヌゞネヌションむンデックス


Bツリヌでのデヌタの圧瞮は、実装するのが難しいタスクであるか、本圓に䟿利なツヌルずいうよりもマヌケティングツヌルです。 圧瞮の実装の難しさに関する詳现は、MySQLずPostgreSQLの実装を比范したAlexei Kopytovの投皿にありたす。 LSMの圧瞮は次のように機胜したす。



ダンプたたはマヌゞでは、1぀のファむル内のすべおのデヌタをペヌゞに分割したす。 ペヌゞサむズはvinyl_page_size構成オプションによっお蚭定されたす。これは、むンデックスごずに個別に倉曎できたす。 ペヌゞは、vinyl_page_sizeで指定されたバむト数を厳密に占有する必芁はありたせん。栌玍されおいるデヌタに応じお、ペヌゞはわずかに倧きくなったり小さくなったりする堎合がありたす。 これにより、ペヌゞにボむドが含たれるこずはありたせん。 圧瞮には、Facebookのzstdストリヌムアルゎリズムが䜿甚されたす。 各ペヌゞの最初のキヌずファむル内のペヌゞのオフセットは、いわゆるペヌゞむンデックスに远加されたす。これは、目的のペヌゞをすばやく芋぀けるこずができる個別のファむルです。 ダンプたたはマヌゞ埌、䜜成されたファむルのペヌゞむンデックスもディスクに曞き蟌たれたす。 すべおの.indexファむルはRAMにキャッシュされたす。 これにより、.runファむルから1回の読み取りで目的のペヌゞを芋぀けるこずができたすこのファむル名拡匵子は、ダンプたたはマヌゞの結果のファむルのVinylで䜿甚されたす。 ペヌゞ内のデヌタは゜ヌトされおいるため、読み取りず圧瞮解陀埌、目的のキヌを簡単なバむナリ怜玢で芋぀けるこずができたす。 個別のスレッドが読み取りず解凍を担圓し、その数はvinyl_read_threads蚭定オプションで決定されたす。



Tarantoolは、すべおのファむルに単䞀の圢匏を䜿甚したす。 たずえば、.runファむルのデヌタ圢匏は、.xlogファむル、぀たりログファむルの圢匏ず同じです。 これにより、バックアップずリカバリ、および倖郚ツヌルの䜜業が簡玠化されたす。



ブルヌムフィルタヌ


ペヌゞむンデックスを䜿甚するず、単䞀のファむルを怜玢するずきに衚瀺されるペヌゞ数を枛らすこずができたすが、ツリヌのすべおのレベルで怜玢する必芁がなくなるわけではありたせん。 デヌタの䞍足をチェックする必芁がある重芁な特別な堎合があり、すべおのレベルを衚瀺するこずは避けられたせん䞀意のむンデックスぞの挿入。 デヌタが既に存圚する堎合、䞀意のむンデックスぞの挿入は倱敗したす。 LSMツリヌでトランザクションが完了する前に゚ラヌを返す唯䞀の方法は、挿入する前に怜玢するこずです。 DBMSのこれらの皮類の枬定倀は、「非衚瀺」たたは「疑䌌」枬定倀ず呌ばれるクラス党䜓を圢成したす。



非衚瀺の読み取りに぀ながる別の操䜜は、セカンダリむンデックスの䜜成に䜿甚される倀の曎新です。 セカンダリキヌは、デヌタが異なる順序で栌玍される通垞のLSMツリヌです。 ほずんどの堎合、すべおのデヌタをすべおのむンデックスに栌玍しないために、このキヌに察応する倀は完党にプラむマリむンデックスキヌず倀の䞡方を栌玍するむンデックスはカバヌたたはクラスタヌず呌ばれたすにのみ栌玍され、フィヌルドのみがセカンダリむンデックスに栌玍されたすセカンダリむンデックス、およびプラむマリむンデックスに含たれるフィヌルドの倀を䜜成したした。 次に、セカンダリキヌの䜜成に䜿甚される倀を倉曎した堎合、たずセカンダリむンデックスから叀いキヌを削陀しおから、新しいキヌを挿入する必芁がありたす。 曎新䞭の叀い倀は䞍明です。䞻キヌから「内郚」で読み取る必芁があるのはたさにこれです。



䟋



update t1 set city='Moscow' where id=1







特に存圚しない倀の堎合、ディスクからの読み取り回数を枛らすために、ほずんどすべおのLSMツリヌは確率的デヌタ構造を䜿甚したす。 Tarantoolも䟋倖ではありたせん。 クラシックブルヌムフィルタヌは、いく぀かの通垞3〜5ビットマップのコレクションです。 曞き蟌み時には、いく぀かのハッシュ関数がキヌごずに蚈算され、ハッシュ倀に察応するビットが各配列に蚭定されたす。 ハッシュするず衝突が発生する可胜性があるため、䞀郚のビットを2回眮くこずができたす。 興味深いのは、すべおのキヌを曞き蟌んだ埌に付加されなかったビットです。 怜玢では、遞択したハッシュ関数も蚈算されたす。 ビットマップの少なくずも1぀にビットがない堎合、ファむルの倀は欠萜しおいたす。 ブルヌムフィルタヌがトリガヌされる確率は、ベむズの定理によっお決たりたす。各ハッシュ関数は独立したランダム倉数であるため、すべおのビット配列で同時に衝突する確率は非垞に小さくなりたす。



Tarantool Bloom Filtersを実装する䞻な利点は、セットアップが簡単なこずです。 むンデックスごずに独立しお倉曎できる唯䞀の構成パラメヌタヌはbloom_fprfprは停陜性率を衚したすず呌ばれ、デフォルトでは0.05たたは5です。 このパラメヌタヌに基づいお、Tarantoolは郚分キヌず完党キヌの䞡方を怜玢するための最適なサむズのブルヌムフィルタヌを自動的に構築したす。 ブルヌムフィルタヌ自䜓は、ペヌゞむンデックスず共に.indexファむルに保存され、RAMにキャッシュされたす。



キャッシング


倚くの人々は、すべおのパフォヌマンスの問題に察しお䞇胜薬をキャッシュするこずを怜蚎するこずに慣れおいたす。 理解できない状況では、キャッシュを远加したす。 Vinylでは、キャッシュをディスクの党䜓的な負荷を軜枛する手段ずみなし、その結果、キャッシュにヒットしなかったリク゚ストに察しおより予枬可胜な応答時間を取埗したす。 Vinylは、トランザクションシステム甚のナニヌクなタむプのキャッシュ、レンゞタプルキャッシュを実装しおいたす。 たずえばRocksDBやMySQLずは異なり、このキャッシュはペヌゞを保存したせんが、ディスクから読み蟌んですべおのレベルでマヌゞした埌の既補のむンデックス倀の範囲を保存したす。 これにより、単䞀のキヌず䞀連のキヌの䞡方のリク゚ストにキャッシュを䜿甚できたす。 ホットデヌタのみがキャッシュに栌玍され、たずえばペヌゞのデヌタは栌玍されないためデヌタの䞀郚のみがペヌゞで芁求できる、RAMが最も最適に䜿甚されたす。 キャッシュサむズは、vinyl_cache構成倉数によっお決たりたす。



ガベヌゞコレクション管理



おそらく、この堎所に到達したので、あなたはすでに焊点を倱い始めおおり、十分な量のドヌパミンが必芁です。 䌑憩を取る時間です。残りに察凊するためには、真剣な努力が必芁です。



Vinylでは、1぀のLSMツリヌのデバむスはパズルの䞀郚にすぎたせん。 Vinylは、1぀のテヌブルスペヌスに察しおも耇数のLSMツリヌを䜜成および管理したす各むンデックスに1぀のツリヌ。 ただし、単䞀のむンデックスでさえ、倚数のLSMツリヌで構成できたす。 理由を理解しおみたしょう。



暙準的な䟋を考えおみたしょう各100バむトの100,000,000レコヌド。 しばらくしお、LSMの最䞋䜍レベルで、10 GBのファむルがある堎合がありたす。 最埌のレベルのマヌゞ䞭に、䞀時ファむルを䜜成したす。これも玄10 GBを占有したす。 䞭間レベルのデヌタもスペヌスを占有したす。ツリヌは同じキヌを䜿甚しお耇数の操䜜を保存できたす。 合蚈で10 GBの有甚なデヌタを保存するには、最倧30 GBの空き領域が必芁になる堎合がありたす。10GBが最終レベル、10 GBが䞀時ファむル、10 GBがその他すべおです。 たた、デヌタが1 GBではなく1 TBの堎合はどうなりたすか 空きディスク容量を垞に有甚なデヌタの数倍にするこずは、経枈的に実珟䞍可胜であり、1TBファむルの䜜成には数十時間かかる堎合がありたす。 事故やシステムの再起動が発生した堎合、操䜜を新たに開始する必芁がありたす。



別の問題を怜蚎しおください。 朚の䞻キヌが単調なシヌケンス、たずえば時系列であるず想像しおください。 この堎合、メむンの挿入はキヌ範囲の右偎になりたす。 すでに巚倧なファむルの末尟に数癟䞇のレコヌドを远加するためだけに再マヌゞするこずは意味がありたせん。

そしお、挿入が䞻にキヌ範囲の䞀郚で発生し、他の郚分から読み取る堎合はどうなりたすか この堎合、ツリヌの圢状を最適化するにはどうすればよいですか 高すぎるず、読み取りに圱響し、曞き蟌みが䜎すぎたす。



Tarantoolは、むンデックスごずに1぀だけでなく、倚数のLSMツリヌを䜜成するこずにより、問題を「ファクタリング」したす。 各サブツリヌのおおよそのサむズはvinyl_range_size倉数によっお蚭定され、デフォルトは1 GBであり、サブツリヌ自䜓は範囲ず呌ばれたす。





ランキングを䜿甚した倧芏暡なLSMツリヌの因数分解



最初、むンデックスには芁玠がほずんどありたせんが、1぀の範囲で構成されおいたす。 いっぱいになるず、合蚈ボリュヌムがvinyl_range_sizeを超える堎合がありたす。 この堎合、分割操䜜が実行されたす-ツリヌを2぀の等しい郚分に分割したす。 分離は、ツリヌに栌玍されおいるキヌ範囲の䞭倮の芁玠によっお発生したす。 たずえば、最初にツリヌが-inf ... + infの党範囲を栌玍しおいる堎合、䞭間キヌXで分割した埌、2぀のサブツリヌを取埗したす。1぀は-infからX、もう1぀はXから+ infのすべおのキヌを栌玍したす。 したがっお、挿入たたは読み取りの際に、どのサブツリヌを参照するかが明確にわかりたす。 ツリヌに削陀があり、隣接する範囲のそれぞれが「重量を倱った」堎合、逆の操䜜が実行されたす-合䜓。 隣接する2぀のツリヌを1぀に結合したす。



分割ず合䜓は、マヌゞ、新しいファむルの䜜成、その他の重い操䜜には぀ながりたせん。 LSMツリヌは単なるファむルのコレクションです。 Vinylでは、どのファむルがどのサブツリヌに属しおいるかを簡単に远跡できる特別なメタデヌタゞャヌナルを実装しおいたす。 ログには.vylog暩限があり、.xlogファむルの圢匏ず互換性があり、.xlogファむルず同様に、すべおのチェックポむントで自動的にロヌテヌションされたす。 分割たたは合䜓を䌎うファむルの䜜成を回避するために、䞭間゚ンティティ-スラむスを導入したした。 これは、メタデヌタログに排他的に保存されるキヌ倀の範囲を持぀ファむルぞのリンクです。 ファむルぞのリンクの数がれロになるず、ファむルは削陀されたす。 たた、分割たたは合䜓が必芁な堎合、Tarantoolは新しいツリヌごずにスラむスオブゞェクトを䜜成し、叀いスラむスオブゞェクトを削陀し、これらの操䜜をメタデヌタログに曞き蟌みたす。 文字通り、メタデヌタログには、<tree id、slice id>たたは<slice id、file id、min、max>の圢匏のレコヌドが保存されたす。



したがっお、ツリヌを2぀のサブツリヌに分割するずいう難しい䜜業は、圧瞮されるたで遅延され、自動的に実行されたす。



キヌの範囲党䜓をサブ範囲範囲に分割するアプロヌチの倧きな利点は、L0のサむズず各サブツリヌのダンプおよび圧瞮プロセスを独立しお制埡できるこずです。 その結果、これらのプロセスは制埡可胜で予枬可胜です。 個別のメタデヌタログを䜿甚するず、truncateやdropなどの操䜜の実装も簡玠化されたす。ビニヌルでは、メタデヌタログず排他的に動䜜し、ガベヌゞ削陀がバックグラりンドで実行されるため、即座に凊理されたす。



高床なビニヌル機胜



アップサヌト



前に、LSMツリヌが保存する2぀の操䜜、぀たり削陀ず眮換に぀いおのみ蚘述したした。 他の党員がどのように衚珟されおいるかを芋おみたしょう。 挿入は眮換を䜿甚しお衚すこずができたす。同じキヌを持぀芁玠がないこずを確認するだけです。 曎新を実行するには、ツリヌから叀い倀を事前に読み取る必芁があるため、この操䜜は眮換ずしおツリヌに簡単に曞き蟌むこずができたす。これにより、このキヌの将来の読み取りが高速化されたす。 さらに、曎新は新しい倀を返す必芁があるため、隠れた枬定倀を避けるこずはできたせん。



Bツリヌでは、非衚瀺の読み取りのコストはほずんどかかりたせん。ブロックを曎新するには、いずれにしおも、ディスクから読み取る必芁がありたす。 LSMツリヌの堎合、非衚瀺の読み取りに぀ながらない特別な曎新操䜜を䜜成するずいうアむデアは非垞に魅力的です。



このような操䜜には、キヌにただデヌタがない堎合に挿入する必芁があるデフォルト倀ず、倀が存圚する堎合に実行する必芁がある曎新操䜜のリストの䞡方が含たれおいる必芁がありたす。 トランザクションの段階で、Tarantoolは操䜜党䜓をLSMツリヌにのみ保存し、マヌゞ䞭にのみ「実行」したす。





操䜜アップサヌト



残念ながら、操䜜をマヌゞ段階に延期した堎合、゚ラヌを凊理するための適切なオプションはありたせん。 そのため、Tarantoolはツリヌに曞き蟌む前に、可胜な限りupsert操䜜を怜蚌するように努めおいたすが、䞀郚のチェックは、叀いデヌタのみを䜿甚しお実行できたす。 たずえば、曎新によっお文字列に数倀が远加されたり、存圚しないフィヌルドが削陀されたりした堎合。



同様のセマンティクスを持぀操䜜は、PostgreSQLやMongoDBを含む倚くの補品に存圚したす。 しかし、それらのすべおにおいお、曎新ず眮換を組み合わせた構文䞊の砂糖にすぎず、DBMSに隠された読み取りを実行する必芁性を軜枛するこずはありたせん。 その理由は、ストレヌゞのデヌタ構造ずしおのLSMツリヌの盞察的な新芏性だず思いたす。



アップサヌトは非垞に重芁な最適化であり、実装されたずきに倚くの血を飲みたしたが、その適甚性は限られおいるこずを認めなければなりたせん。 テヌブルに二次キヌたたはトリガヌがある堎合、隠された読み取り倀を避けるこずはできたせん。 セカンダリキヌを必芁ずしないスクリプトがあり、トランザクションの完了埌に曎新しおも゚ラヌが発生しないこずは間違いありたせん。この操䜜はあなたのためです。



この挔算子に関連する話をしたいず思いたす。 Vinylは成長を始めたばかりで、最初に本番環境でアップサヌトを開始したした。 アップサヌトの理想的な条件は、キヌの巚倧なセット、倀ずしおの珟圚の時間です。 曎新操䜜は、キヌを挿入するか、珟圚の時刻を曎新したす。 読み取り操䜜はたれです。 ストレステストは優れた結果を瀺したした。



しかし、数日間の操䜜の埌、TarantoolプロセスはCPUの100を消費し始め、システムパフォヌマンスはほがれロたで䜎䞋したした。



掘り始めたした。 キヌによるリク゚ストの分散は、テスト環境で芋たものずは倧きく異なるこずが刀明したした。 それは...たあ、非垞に䞍均䞀でした。 文字通り、キヌのほずんどは1日に1〜2回曎新され、それらのデヌタベヌスは明らかに「スモヌク」されたした。 しかし、キヌははるかに熱かった-1日あたり䜕䞇もの曎新。 Tarantoolは、この䞀連の曎新で玠晎らしい仕事をしたした。 しかし、䜕䞇ものupsert'ovのキヌで読むず、光を消すこずができたした。 「最埌の」倀を返すために、Tarantoolは毎回䜕䞇ものupsertコマンドのストヌリヌを読んで「倱う」必芁がありたした。 アップサヌトを蚭蚈する際、レベルのマヌゞ䞭にこれが自動的に行われるこずを期埅しおいたしたが、マヌゞには至らず、L0メモリが十分にあり、LSMツリヌはディスクにプッシュするこずを急いでいたせんでした。



数十個以䞊のupsert'ovを蓄積したキヌの「先読み」読み取り倀を提䟛するバックグラりンドプロセスを远加し、その埌、upsert'ovのスタック党䜓を読み取り倀で眮き換えるこずにより、問題を解決したした。



二次キヌ



曎新操䜜だけでなく、非衚瀺の読み取りを最適化するずいう深刻な問題がありたす。 眮換でも、セカンダリキヌがある堎合、叀い倀を匷制的に読み取る必芁がありたす。セカンダリむンデックスから個別に削陀する必芁があり、新しい芁玠を挿入しおもこれが行われない堎合があり、むンデックスにゎミが残りたす。







セカンダリむンデックスが䞀意でない堎合、それらからゎミを削陀するこずもマヌゞフェヌズに転送できたす。これはTarantoolで行いたす。



取匕



LSMツリヌの远加のみの性質により、Vinylで完党にシリアル化可胜なトランザクションを実装できたした。 読み取り専甚リク゚ストは叀いバヌゞョンのデヌタを䜿甚し、曞き蟌みをブロックしたせん。 トランザクションマネヌゞャ自䜓は䟝然ずしお非垞に単玔です。埓来の分類では、MVTOクラスを実装し、最初に完了したトランザクションが競合に勝ちたす。 それらに固有のロックやデッドロックはありたせん。 奇劙なこずに、これは利点よりも䞍利な点です。パラレル実行では、ロックの適切なタむミングでトランザクションの䞀郚を「保持」するこずにより、成功したトランザクションの数を増やすこずができたす。 圓面の蚈画におけるトランザクションマネヌゞャヌの開発。 珟圚のリリヌスでは、アルゎリズムを100正確で予枬可胜なものにするこずに重点を眮いおいたす。 たずえば、トランザクションマネヌゞャは、いわゆるギャップロックをサポヌトする数少ないNoSQL環境の1぀です。



おわりに



この蚘事では、ディスク゚ンゞンの配眮方法を説明しようずしたした。 その䜜業䞭に、Tarantoolプロゞェクトは真剣に成熟したした。今日ではMail.Ru Groupや他のむンタヌネット䌁業で䜿甚されおいるだけでなく、銀行、通信䌚瀟、および産業郚門の䌁業のサヌバヌの゚ンタヌプラむズ版も販売およびサポヌトしおいたす。 今日、ビニヌル付きのTarantoolの安定バヌゞョンは、Mail.Ru Groupずその倖郚の䞡方でテストされおおり、圓瀟のWebサむトからダりンロヌドできたす 。



T +䌚議は、2018幎6月21日にMail.Ruグルヌプオフィスで開催されたす。これは、私たちにずっお初めおのむンメモリコンピュヌティング䌚議です。 その䞊で、Vinylのチュヌニングずモニタリングに぀いお詳しく説明したす。 私たちはチケットを売っおお金を皌ぐずいう目暙を持っおいたせんが、䌚議は支払われたす。 今日のTarantoolは、産業レベルの゜リュヌションを䜜成するために自信を持っお䜿甚できる数少ないロシアのオヌプン゜ヌス゜リュヌションの1぀であるため、このカンファレンスには倚くの開発者が集たるず確信しおいたす。 そのため、䌚議䞭に、可胜な限り専門的にすべおを行うこずも決定したした。



Tarantoolプロゞェクトは急速に成長しおいたす。 そしお、䞖界クラスのDBMSを䞀緒に䜜成するために、志を同じくする人々を垞に探しおいたす。 この蚘事に蚘茉されおいるトピックに匷い関心があり、私たちの目暙が重芁で興味深いず思われる堎合は、必ずご連絡ください。 私たちには倚くの仕事がありたす。



All Articles