メモリ内のDBMSでのク゚リの非同期凊理、たたはシングルコアで毎秒100䞇のトランザクションを凊理する方法







こんにちは 前回の2回の蚘事では、RAM内のDBMSがデヌタの安党性をどのように提䟛するかに぀いお説明したした。 ここずここで芋぀けるこずができたす。



この蚘事では、RAMのDBMSパフォヌマンスの問題に觊れたいず思いたす。 指定されたキヌに埓っお倀が単玔に倉化する堎合、最も単玔なナヌスケヌスからパフォヌマンスの議論を始めたしょう。 さらに簡単にするために、サヌバヌ郚分が存圚しない、぀たり ネットワヌク䞊でクラむアントずサヌバヌの察話は発生したせんこれを行った理由はさらに明確になりたす。 したがっお、DBMSそれを呌び出すこずができる堎合は、アプリケヌションのRAMに完党にありたす。



デヌタベヌスサヌバヌがない堎合は、アプリケヌションのメモリ内のハッシュテヌブルにキヌず倀のペアを保存しおいる可胜性がありたす。 C / C ++では、このデヌタ構造は次のようになりたす。



std::unordered_map







この構造の速床を確認するために、次の内容の1.cpp



ファむルを䜜成したした。



 #include <map> #include <unordered_map> #include <iostream> const int SIZE = 1000000; int main() { std::unordered_map<int,int> m; m.reserve(1000000); long long c = 0; for (int i = 0; i < SIZE;++i) c += m[i*i] += i; std::cout << c << std::endl; }
      
      





それからコンパむルしお実行したした



 g++ -std=c++11 -O3 1.cpp -o 1 MacBook-Air-anikin:Downloads anikin$ time ./1
      
      





そしお、次の結果を埗たした



 real 0m0.465s user 0m0.422s sys 0m0.032s
      
      





これから䜕を孊ぶこずができたすか 私の調査結果は次のずおりです。



  1. 私はC / C ++が倧奜きです。
  2. 私は叀き良きMacBook Airが倧奜きです実際、動䜜は遅くなりたすが、それは別の話です。
  3. -O3



    最適化フラグを䜿甚し-O3



    。 䜿甚するのを恐れる人もいたすが、無駄です。そうしないず、パフォヌマンスが䜎䞋するからです。 これを実蚌するために、次のようなコマンドを実行したしょう。



     MacBook-Air-anikin:Downloads anikin$ g++ -std=c++11 1.cpp -o 1 MacBook-Air-anikin:Downloads anikin$ time ./1
          
          





    そしお、 -O3



    なしの結果-O3



    2倍悪いこずを確認しおください



     real 0m0.883s user 0m0.835s sys 0m0.033s
          
          



  4. ほずんどの堎合、アプリケヌションはナヌザヌモヌドで機胜したした。 カヌネルモヌドで費やされた短い時間は、おそらくハッシュテヌブル甚のペヌゞの事前割り圓おそしお-O3



    、この時間を最適化したせんでした、 mmapシステムコヌルの実行、および実行可胜ファむルのダりンロヌドに費やされたず考えられたす。
  5. このアプリケヌションは、玄100䞇のキヌをハッシュテヌブルに挿入したす。 ここで、単語ずは、乗算i * i䞭のオヌバヌフロヌによっお匕き起こされる繰り返しのために、実際にはハッシュテヌブルに100䞇未満のキヌが存圚する可胜性があるこずを意味したす。 したがっお、新しいデヌタを挿入するず、既存のデヌタが曎新されたす。 ただし、ハッシュテヌブルには正確に100䞇の操䜜がありたす。
  6. アプリケヌションは100䞇個のキヌを挿入し、玄0.5秒でシャットダりンしたす。 1秒あたり玄200䞇回のキヌず倀のペアの挿入が生成されたす。


埌者の芳察は特に興味深い。 std::unordered_map



で衚されるRAMにキヌず倀のペア甚のストレヌゞ゚ンゞンが既にあり、そのような叀き良きMacBook Airの1぀のコアで毎秒200䞇回の操䜜を実行できるず仮定できたす。



 MacBook-Air-anikin:Downloads anikin$ uname -a Darwin MacBook-Air-anikin.local 13.4.0 Darwin Kernel Version 13.4.0: Mon Jan 11 18:17:34 PST 2016; root:xnu-2422.115.15~1/RELEASE_X86_64 x86_64
      
      





敎数のキヌず倀を䜿甚したこずに泚意しおください。 文字列を䜿甚するこずはできたしたが、割り圓おずコピヌがテスト結果に圱響を䞎えたくないずいう理由だけで実行したせんでした。 文字列に察する別の匕数 std::unordered_map<std::string, 
>



堎合、衝突の可胜性が高くなり、パフォヌマンスが䜎䞋したす。



RAMのハッシュテヌブルは、1぀のコアで1秒あたり200䞇の操䜜を実行できるこずがわかりたすが、RAMのDBMSに぀いお話しおいたこずを思い出したす。 RAM内のDBMSずRAM内のハッシュテヌブルの違いは䜕ですか DBMSはサヌバヌアプリケヌションであり、ハッシュテヌブルはラむブラリです。 DBMSは、ハッシュテヌブルずその他のものです。 そしお、これには、少なくずもサヌバヌ自䜓のストラップが含たれたす。



std::unordered_map<int, int>



基づいおサヌバヌアプリケヌションを䜜成したしょう。 玠朎なアプロヌチは次のようになりたす。



  1. メむンストリヌムの接続を受け入れたす。
  2. 受信した接続ごずに新しいスレッドを䜜成したすたたは事前䜜成されたスレッドのプヌルを開始したす。
  3. 同期プリミティブミュヌテックスなどを䜿甚しお、 std::unordered_map



    を保護したす。
  4. デヌタの安党性を忘れないでください-各曎新操䜜をトランザクションログに蚘録したす。


アプリケヌションコヌドを曞くこずに飜き飜きしたくないので、すでにこれを行っおいるず想像しおみたしょう。 「接続ごずに個別のスレッド」MySQL、MariaDB、Postgresなどの原則に基づいお配眮された任意のデヌタベヌスサヌバヌを䜿甚したす。1コアで最倧で数䞇のク゚リを実行できたす16たたは32で栞サヌバヌにずっおは、1秒あたり100䞇回の操䜜になりたす。 これはさたざたなベンチマヌクでよく知られおいたす。 ネットワヌクで芋぀けるこずができた埓来のDBMSの䞭で最高のパフォヌマンスむンゞケヌタヌは、1秒あたり玄100䞇のリク゚ストであり、20コアのコンピュヌタヌで実行されるMariaDBに属したす。 詳现な蚈算に぀いおは、 こちらをご芧ください 。 簡単な蚈算により、コアあたり1秒あたり5䞇のリク゚ストを取埗したす。 おそらく䞖界最高のスペシャリストによっお最適化された垂堎で最高のDBMSの1぀は、1぀のコアで1秒あたり50,000件の単玔なク゚リ実際にはキヌ怜玢のみを凊理したす。



50,000および200侇std::unordered_map



ず比范した堎合、40倍の差がありたす。 どうですか デヌタ構造にサヌバヌを远加しお、他のアプリケヌションにリモヌトアクセスできるようにしたした。パフォヌマンスが40倍䜎䞋したした。 繰り返したすが、これは最も単玔な操䜜のベンチマヌクであり、すべおがキャッシュ内にあり、DBMSは䞖界最高のスペシャリストによっお調敎され、最倧スルヌプットに蚭定されおおり、DBMSのオヌバヌヘッドを最小限に抑えおいたす。マルチレベルアヌキテクチャを忘れお、すべおのビゞネスロゞックずDBMSロゞックを1぀のプロセス内の1぀のアプリケヌションに蚘述する方が適切です。 もちろん、これは冗談でした。 デヌタベヌスサヌバヌを最適化するこずをお勧めしたす。



䞊蚘のアヌキテクチャを備えたサヌバヌがトランザクションを凊理するずきに䜕が起こるかに぀いおのシステムコヌルのプリズムを芋おみたしょう。



  1. ネットワヌクからリク゚ストを読み取りたす。
  2. ハッシュテヌブルロック。
  3. ハッシュテヌブルのロックを解陀したす。
  4. トランザクションログに曞き蟌みたす。
  5. ネットワヌクぞの蚘録。


芁求ごずに、少なくずも5぀のDBMSぞのシステムコヌルを受け取りたす。 各呌び出しを行うには、カヌネルモヌドを開始および終了する必芁がありたす。



カヌネルモヌドを開始および終了するず、モヌドが切り替わり、ある皋床の䜜業が必芁になりたす。 詳现は、たずえばここで読むこずができたす 。 さらに、モヌドの切り替えによりコンテキストの切り替えが発生し、コピヌず遅延がさらに倧きくなる可胜性がありたす。 詳现に぀いおは、 こちらをご芧ください 。



システムコヌルのすべおの悪を瀺すために私は正しい、私はシステムコヌルが倧奜きですが、遅いので悪甚しないようにしおいたす、別のプログラムを䜜成したしたCで



 #include <stdio.h> #include <fcntl.h> #include <unistd.h> int main() { int fd = open(“/dev/zero”, O_RDONLY); for (int i = 0; i < 1000000; ++i) { unsigned char c; if (read(fd, &c, 1) == -1) { fprintf(stderr, “error on read\n”); break; } } close(fd); return 0; }
      
      





このプログラムは、ファむル/dev/zero



から100䞇バむトの読み取りのみを生成し/dev/zero



。 テスト結果は次のずおりです。



 MacBook-Air-anikin:Downloads anikin$ time ./2 real 0m0.639s user 0m0.099s sys 0m0.495s
      
      





たず、プログラムはほずんどすべおの時間をカヌネルモヌドで䜿甚したす。 次に、1秒間に玄150䞇のシステムコヌルを行いたす。 ハッシュテヌブルのパフォヌマンスは1秒間に玄200䞇回であったこずを思い出しおください。 奇劙なこずに、 読み取りシステムコヌルはハッシュテヌブルを怜玢するよりも30遅くなりたす。 そしお、これはこの呌び出しの単玔さにもかかわらず、圌はディスクたたはネットワヌクにアクセスせず、単にれロを返したした。



䞊蚘で曞いたように、デヌタベヌスサヌバヌを䜿甚する堎合、ハッシュテヌブルには怜玢操䜜ごずに少なくずも5぀のシステムコヌルがありたす。 これは、システムコヌルの堎合に少なくずも5 * 1.3 =6.5倍の時間が必芁であるこずを意味したす 状況を皎務プレヌンに転送するず、システムコヌルは85の皎金のようになりたす。 85の絊䞎皎を歓迎したすか 獲埗した100ルヌブルのうち15ルヌブルしか受け取らなかったら これに぀いお考えた埌、 読み取り 、 曞き蟌み、およびその他のシステムコヌルに戻りたしょう。 ネットワヌクバッファからの読み取り、Linuxカヌネルでのメモリブロックの割り圓お、内郚カヌネル構造の怜玢ず倉曎など、さたざたなタスクを実行したす。 したがっお、85以䞊の皎金は実際には非垞に少なく芋えたす。 芁求を凊理するずきにMySQLたたはその他の埓来のDBMSが呌び出すシステムの数を確認するには、Linuxでstraceナヌティリティを䜿甚できたす。



したがっお、システムコヌルは悪です。 それらを完党に攟棄し、DBMSロゞック党䜓をカヌネルに転送するこずは可胜ですか 良いように聞こえたすが、難しいです。 おそらく、より実甚的な゜リュヌションがありたす。 以䞋の䟋を芋おください。



 #include <stdio.h> #include <fcntl.h> #include <unistd.h> int main() { int fd = open(“/dev/zero”, O_RDONLY); for (int i = 0; i < 1000; ++i) { unsigned char c[1000]; if (read(fd, &c, 1000) == -1) { fprintf(stderr, “error on read\n”); break; } } close(fd); return 0; }
      
      





結果は次のずおりです。



 MacBook-Air-anikin:Downloads anikin$ time ./2 real 0m0.007s user 0m0.001s sys 0m0.002s
      
      





このプログラムは以前のプログラムずたったく同じです- /dev/zero



ファむルから100䞇バむトをコピヌしたす-ただし、実行時間はわずか7ミリ秒で、639ミリ秒の以前の結果よりほが100倍高速です これはどのように可胜ですか 秘trickは、システムコヌルの数を枛らし、それぞれが実行する䜜業量を増やすこずです。 システムコヌルを適切に䜜業でロヌドすれば、システムコヌルはそれほど悪くないこずがわかりたす。 通話に察しお固定料金を支払うず、ほが無料で䜿甚できたす。 これは倖囜の遊園地に䌌おいたす入堎刞に察しお1回支払い-終日すべおのアトラクションを䜿甚したす。 たあ、たたは䞀日より少し少ないチケットの䟡栌は倉わりたせんが、別のアトラクションの点ではもう少し高䟡になりたす。



そのため、デヌタベヌスサヌバヌの速床を䞊げるには、システムコヌルを枛らし、各コヌル内でより倚くの操䜜を実行する必芁がありたす。 これを達成する方法は リク゚ストずその凊理を組み合わせおみたしょう



  1. 1回の読み取り呌び出しで、ネットワヌクから1000件のリク゚ストを読み取りたす。
  2. ハッシュテヌブルをロックしたす。
  3. 1000件のリク゚ストを凊理したす。
  4. ハッシュテヌブルのロックを解陀したす。
  5. write / writevを1回呌び出すだけで、1000個のトランザクションをログに曞き蟌み たす 。
  6. 1回の曞き蟌み呌び出しでネットワヌクに1000の応答を曞き蟌みたす。


いいね しかし、ちょっず埅っおください、DBMSは通垞、バッチでリク゚ストを凊理したせん少なくずも明瀺的に尋ねられない堎合、オンラむンで動䜜したすリク゚ストが到着するずすぐに、DBMSは最小限の遅延で即座にリク゚ストを凊理したす。 圌女は、1000件のリク゚ストが到着するのを埅぀こずはできたせん。



この問題を解決するには



公共亀通機関を芋おみたしょう。 そこで、この問題は前䞖玀に解決されたした前幎ではない堎合。 バスのスルヌプットが高いため、バスのチケットはタクシヌに乗るよりも安くなりたす。したがっお、1人の乗客の旅行の䟡栌は䜎くなりたす。 ただし、バスたたは特定の郜垂に応じお地䞋鉄の遅延埅機時間は、忙しい䞭心郚のタクシヌの遅延ずほが同じです少なくずも、ニュヌペヌク、モスクワ、パリ、ベルリン、東京でこのパタヌンを芳察しおいたす。 どのように機胜したすか



肝心なのは、100人がバス停に到着するたでバスが埅機しないこずです。 通垞、バス停の乗客は垞に十分です。なぜなら、䞭心郚は街の忙しい郚分だからです読み蟌み䜜業負荷が高い。 したがっお、1぀のバスが停止し、乗客を乗せお車宀がいっぱいになるたで、たたは停留所に誰も残らなくなるたで立ち去りたす。 その埌、次のバスが立ち䞊がり、再び十分な数の乗客を迎えたす。最初のバスの出発から2番目のバスの到着たでの間に、新しい人が停留所に珟れたからです。 バスは満車を埅ちたせん。 それは最小限の遅延で機胜したす人がいたす-それを取り、運転したした。



DBMSが同じように機胜するためには、ネットワヌクサブシステム、トランザクションプロセッサ、およびディスクサブシステムを独立したバスたたは、必芁に応じお地䞋鉄列車ず芋なす必芁がありたす。 これらの各バスは、他の2぀のバスに察しお非同期に動䜜したす。 そしお、これらのバスはそれぞれ、バス停にいるのず同じ数の乗客を乗せたす。 十分な乗客がいない堎合-ええ、はい、高い固定料金のバスはほずんど空なので、プロセッサは非効率的に䜿甚されたす。 䞀方、それは䜕が問題なのですか 既存の負荷に完党に察応したす。 プロセッサは、1秒あたり10,000リク゚ストず1秒あたり100䞇リク゚ストの䞡方で99でロヌドできたすが、どちらの堎合もシステムコヌルの数が同じであるため、応答時間も同様に良奜です。 たた、このむンゞケヌタは、システムコヌルごずに転送されるバむト数よりも重芁です。 プロセッサは垞にロヌドされたすが、驚くべきこずに負荷の䞋でスケヌリングし、実行される倧容量ず小容量の䞡方の負荷を均等に保持したす。 システムコヌルで実行される操䜜の数が100回倉化する堎合でも、応答時間は実質的に倉曎されたせん。 この理由は、1぀のシステムコヌルの非垞に高い固定䟡栌です。



これらすべおを最良の方法で実装する方法は 非同期的に。 Tarantool DBMSの䟋を考えおみたしょう。



  1. Tarantoolには3぀のストリヌムがありたす。ネットワヌクを操䜜するためのストリヌム、トランザクションを凊理するためのストリヌム トランザクション凊理の略語TXを䜿甚したすが、PではなくXがある理由は聞かないでくださいおよびディスクを操䜜するためのストリヌムです。
  2. ネットワヌクスレッドは、ネットワヌクから芁求を読み取りI / Oをブロックせずにネットワヌクバッファヌから読み取るこずができる量、1぀の芁求であるか、1000を超えるか、TXに転送したす。 たた、圌はTXからの応答を受信しお​​ネットワヌクに曞き蟌み、パケットに含たれる応答の数に関係なく、これを1぀のネットワヌクパケットで行いたす。
  3. グルヌプのTXストリヌムは、ネットワヌクで動䜜するためにストリヌムから受信したトランザクションをメモリ内で凊理したす。 メモリヌ内の1぀のグルヌプのトランザクションを凊理するず、ディスクで䜜業するためにそれをストリヌムに転送したす。 同時に、特定のグルヌプにいく぀のトランザクションがあるかに関係なく、グルヌプは次々に転送されたす。 電車を降りおバス停に向かう人だかりのようです。 接近するバスは、すべおの乗客の停留所から1人の乗客たで乗車したす。 誰かがバスの出発前に停車するこずができなかった堎合、次のバスを埅぀必芁がありたす。 バスは1ミリ秒䜙分に埅機したせん。最埌の乗客の埌ろに誰もいない堎合、圌は出発したす。 グルヌプを凊理するず、ディスクを操䜜するためのストリヌムはそれをTXストリヌムに返し、トランザクションをコミットし、このグルヌプに含たれるすべおの芁求をネットワヌクで操䜜するためのストリヌムに返したす。


このようにしお、Tarantoolのシステムコヌルの数を倧幅に削枛したした。 ここでは、システムがどのように動䜜し、単䞀のコアで毎秒100䞇のトランザクションに察凊するかに぀いお詳しく読むこずができたす。



以䞋の画像は、ワヌクフロヌ党䜓を抂略的に瀺しおいたす。









泚意を払う䟡倀がある䞻なこずは、各スレッドが䞊行しお実行され、残りの2぀の䜜業に干枉しないこずです。 䞊列凊理が倚く負荷が高いほど、芁求ごずのシステムコヌルが少なくなり、システムが1秒あたりに凊理できる芁求が倚くなりたす。



同時に、スレッドは他のスレッドを埅機するのではなく、単に珟圚持っおいる䜜業を実行するだけなので、応答時間は十分にありたすが、その間、䜜業の新しい郚分が䞊行しお準備されおいたす。



RAM内のDBMSに぀いおの蚘事がさらに増えたす。 お楜しみに



蚘事の内容に関するすべおの質問は、元のdanikinの著者、メヌルおよびクラりドサヌビスMail.Ru Groupのテクニカルディレクタヌに宛おおください。



All Articles