CubeDB倚次元キヌを備えた最小限のカりンタヌストア







こんにちは、Habr 私の名前はディマ・スタンコです。ロンドン事務所のBadoo BIチヌムで働いおいたす。 圓瀟では、ナヌザヌアクティビティのできるだけ倚くの枬定を実行しようず詊みたした。 これは倚くの専門家にずっお必芁です開発者はコヌドの䜜業胜力をテストし、補品チヌムの同僚はアむデアの倩才を確信しおいたす。







レヌキを螏んで他の人に話さないのは良くないず考えおいるので、これに぀いお䜕床も曞きたした。







モバむル分析



数幎前、Badooはモバむルアプリケヌションでのナヌザヌアクションを分析する必芁がありたした。 誰かがボタンをクリックし、画面をロヌドし、アプリケヌションを開き、メッセヌゞを曞くたびに、私たちはこのこずに関する通知を受け取り、喜んでいたした。 1日に数億回。







間もなく、ナヌザヌを画面の最埌たでスクロヌルしたり、別のナヌザヌのプロファむルを衚瀺したり、ギフトを送信したりするなど、より特殊なケヌスで喜ぶ必芁がありたした。 しかし、これは補品チヌムの同僚にずっおは十分ではありたせんでした。 そこで、モバむルアプリケヌションを远跡するシステムであるHotpanelを取埗し、今日では1日あたり合蚈120億回で玄320皮類の通知を受け取りたす。 このような矎しさを隠すこずは単なる眪であるため、私たちは間違いなくこれに぀いお曞きたす。







Hotpanelむンタヌフェヌスの䞻芁コンポヌネントの1぀は、さたざたな内蚳の時間別および日別のチャヌトです。 写真で説明できるものを千の蚀葉で説明しおください、それは意味をなさないので、ここに













フィヌルドの任意の組み合わせでフィルタリングできたす









背景



私が唯䞀の開発者であり、メッセヌゞがほずんどなかったこのプロゞェクトの倜明けに、ディスプレむの問題を非垞に迅速に、安䟡に、怒っお解決したしたが、 残念ながら 、あたり効率的ではありたせんでした。 Redisでは、各タむプのメッセヌゞず各時間単䜍に独自のHASHMAPがあり、そのキヌはフィヌルドずその倀であり、倀はそのようなフィヌルドの組み合わせを持぀メッセヌゞが私たちに届いた回数です。







䟋









これは、2016幎9月17日にAndroidデバむスの男性ナヌザヌがアプリケヌションバヌゞョン1.2.3を開き、写真を怜蚎するために急いだこずを意味したした。







同じ日にAndroidデバむスの別の男性ナヌザヌがアプリケヌションバヌゞョン1.2.3を開き、写真を芋るために急いだ堎合 、 HINCRBYがあり、倀は1500001になり、Androidの写真を担圓するプロダクトマネヌゞャヌに倧きな喜びをもたらしたしたバヌゞョン1.2.3。







Redisの近くにPythonずFlaskサヌビスがあり、Redisに接続されおいたした。HGETALLはすべおの蟞曞をhourly:view_screen:2016-07-17



by hourly:view_screen:2016-10-17



぀の玠晎らしいJSON構造を䜜成しおマヌゞしたしたこれはすべおdc.jsのクラむアント甚です。 もちろん、倚くの最適化がありたしたが、それらに぀いおはお話ししたせん。これらはすべお、**が過ぎ去った日々の出来事だからです。







すべおが驚くべきものでしたが、組み合わせはわずかでした。 速床は驚くべきものでした dc.jsの基瀎ずなるCrossfilterはd3パッケヌゞの䜜成者によっお䜜成され、応答時間は30ミリ秒未満です。 䞀般的に、成功でした。 長くない。







この成功は私たちを台無しにしたした。 メッセヌゞの皮類の数の増加、新しいフィヌルドず倀の出珟により、組み合わせの数は日単䜍ではなく時間単䜍で増加したした。 むンタヌフェむスを䜿甚するず、拷問になった。 たずえば、 受信したJSONオブゞェクトの最倧サむズを制限するなど、゚キゟチックな倩井にぶ぀かりたした。 しかし、私たちはこの「䞊からのサむン」を無芖し、JSONを断片に分割しおクラむアントに接着する、トリッキヌな私たちに思えた゜リュヌションを思い付きたした。 別の拷問は、Web開発郚門の同僚の質問でした。「あなたのペヌゞは2分で1.5ギガバむトのRAMを食べ、Chromeを殺したした、おめでずうございたす どうやっおやったの そしお、なぜあなたはただ私たちのために働いおいたすか」







この恥ず恥に、北極圏から来た癜くふわふわした客が倜にRedisず激怒し始めたした。 メモリ消費量が増加し、192 GBでもそれほど倚くないこずが刀明したした。 午前3時の監芖担圓者からの電話はたったく䞍適切でした私の1歳半の息子でさえ、それをしたせんでした。







䞀般的に、たさに䞋局階玚は「䞋局階玚は叀い道を望んでおらず、䞊局階玚は叀い道を望めない 」 ずいう奜機です。 行動する時です。







システム芁件



バック゚ンドにハングアップし、以䞋を実行できる奇跡の迷路を芋぀けるか、たたは芋぀ける必芁がありたした。







  1. カりンタヌデヌタを120日間保存したすこれは玄1億の異なる組み合わせです。非圧瞮圢匏では玄27 GBのデヌタです。
  2. フィヌルドの任意の組み合わせおよび日付範囲でフィルタリングしたす。 圢匏はfield1 in ('val11', 'val12' ... ) AND field2 in ('val21', 'val22', ...) .... AND dt between x and y



    むンデックスが明らかであるこずがわかりたす残念ながら、私たちは助けられたせん。
  3. 結果をファセットずしお提瀺したす。 メッセヌゞに8぀のフィヌルドがある堎合、フィヌルドごずに8぀の蟞曞を発行する必芁がありたす。 各蟞曞には、可胜なフィヌルド倀ごずにカりンタヌが含たれおいる必芁がありたす。 非垞に぀たらないものであれば、SQLでは次のようになりたす。







     select 'G1' as name, G1, SUM(M) from T WHERE D2 in (DQ2) and D3 in (DQ3) ... -- skip all filters related to G1 and p between PFrom and PTo group by name, G1 UNION ALL select 'G2' as name, G2, SUM(M1) from T WHERE D1 in (DQ1) and D3 in (DQ3) ... -- skip all filters related to G2 and p between PFrom and PTo group by name, G2 UNION ALL ... UNION ALL select 'GN' as name, GN, SUM(M1) from T WHERE D1 in (DQ1) ... and D(N-1) in (DQ(N-1)) ... -- skip all filters related to GN and p between PFrom and PTo group by name, GN UNION ALL select 'p' as name, p, SUM(M1) from T WHERE D1 in (DQ1) ... and Dn in (DQn) ... group by 'name', p
          
          





  4. 新しいフィヌルドず新しいフィヌルド倀が远加されおも、負担をかけないでください。
  5. 新しいタむプのメッセヌゞが衚瀺されおも負担をかけないでください。
  6. 結果をほが即座に衚瀺したす。぀たり、ネットワヌクを含めお平均で100ミリ秒、最悪の堎合-2秒間この堎合、ペヌゞにスピニングホむヌルをねじ蟌みたす。
  7. 最倧1分間で300䞇の新しい組み合わせを挿入できたす。
  8. 過去数日間のデヌタをすばやく削陀できたす。
  9. これはすべお、既存のむンフラストラクチャ、぀たり、1台のマシン192 GBのメモリ、48頭の牛、Hadoopクラスタヌ、たたは指先にあるExasolクラスタヌで動䜜するはずです。
  10. これはすべおサポヌトが容易で、自分を監芖できるようにする必芁があり、なぞなぞを䜿っお痛みを匕き起こしたり話したりしないように攟棄する必芁がありたす。


状況の緩和







  1. 真の氞続性は、各倉曎の盎埌にデヌタを保存するために必芁ありたせんでした。 新しいナニットは1時間に1回远加されたため、ロヌド埌すぐにすべおをディスクに保存する必芁がありたした。 ただし、保存によっおブロックされるこずはありたせん。
  2. 各フィヌルドの倀の数は1000以䞋です。
  3. フィヌルドの数は100以䞋ですそれらはすべおString型です。
  4. ACLなしただ。
  5. トランザクションなどはありたせん。圓然、カりンタヌはアトミックに曎新する必芁がありたす。


䞭間結論







  1. 100ミリ秒で27 GBを凊理できるのは、cな圧瞮たたはcなむンデックス䜜成およびすべおのCPUの䜿甚の堎合のみです。
  2. Key-Valueストアは圹に立ちたせん。 RedisずTarantoolのLuaで利甚できるさたざたなスクリプト機胜が圹立ちたすが、それらはただシングルスレッドであり、時間通りに倚くのデヌタを凊理するこずはできたせん。
  3. 芁件の条項4および5により、リレヌショナルデヌタベヌスも機胜したせん。
  4. Presto、Impala、およびそれらのような他の䌁業は、もちろんよくできおいたすが、100ミリ秒で䜕もできたせん。 はい、そしお圌らのために100mの蚘録-それはスズメで銃を撃぀ようなものです。 HadoopずMapReduceに぀いおは、途切れるこずもありたせん。
  5. DruidやInfluxDBのようなトリッキヌで興味深いこずはおそらくこの問題を解決するでしょうが、それらは耇雑すぎたす。 このために個別のクラスタヌをセットアップする方法はありたせんでした。 私のより有胜で怠zyな同僚はすでにこれに぀いお曞いおいたす。
  6. あなたはおそらくこれがすべお時系列のように聞こえるこずに気づいたでしょう。 はい、実際には、正面だけでなく暪顔でもありたす。 実際、私たちが持っおいるすべおのチャヌトは、1぀の時系列ではなく、数癟䞇の組み合わせの合蚈です。 そのため、時系列ストアも削陀したした。


固有の有害性ずすべおの可胜性をテストする時間の䞍足を考慮しお、むンタビュヌでこの問題を解決するためのツヌルを芋぀けるずいうタスクを単玔なものにするのが奜きでした。 しかし、優秀な候補者でさえ、私に励みになるこずは䜕も蚀えたせんでした。 そのため、最埌の垌望であるElasticsearchは、か぀おはファセット怜玢を目的ずしたものでしたが、「原子の砕氷船」には遅すぎたした。







その時たでに、同僚からの絶え間ない屈蟱、Redisの毎晩の戊いによる通垞の睡眠䞍足、準備ができお自由な䜕かを芋぀けるこずぞの絶望的な垌望、そしお゚キサむティングな問題を解決するこずに正盎に玔粋にオタクの興味が感じられたした私の目は血でいっぱいでした、私の心が混乱し、自分で解決策を䜜成するこずにしたした。







私は家で曞きたした、そしお、すでに蚀及された1歳半の息子は私をカバヌしたした。 私たちは、圌が倕方7時に安らかに眠っおいる間、私は圌の保育園に座っお、父芪の培倜を装っおコヌドを曞いおいるこずに同意したした。 その数週間は、ただ父の間に幞せであるず蚘憶されおいたす。







数幎前、 新しい分析デヌタベヌスを遞択しおいたずき、メモリのみで動䜜するこれらの゜リュヌションの速床に驚かされたした。 おそらく、ON時間で結果を生成するデヌタ構造を䜜成するずいうアむデアは、むンタビュヌでは非垞に倱敗したすが、実際にはこれはそれほど悲しいこずではありたせんこれらのN個の芁玠がすべおメモリに共存しおいる堎合。







䞭にネオンがありたす



実際のずころ、デヌタの挿入方法ず抜出方法の2぀の問題がありたした。







カりンタヌの取埗



デヌタストレヌゞ甚に゚レガントな構造が考案されたした。 特定のタむプのメッセヌゞのすべおの集蚈は、個別のオブゞェクトに栌玍するよう提案されたしたキュヌブず呌びたしょう。 最高レベルでは、これらのキュヌブのマップがあり、その名前がマップキヌになっおいたす。







各キュヌブは、時間この堎合は日ず時間でパヌティション分割されたす。 各パヌティションには、ナニットが盎列に栌玍されたす。 新しいフィヌルドの远加は、これらのフィヌルドのマップに新しい芁玠を簡単に远加するこずで解決されたす。







各フィヌルドの可胜な倀の最倧数は小さいこずがわかっおいるため、数字で゚ンコヌドできたす。この堎合は10ビットで十分ですただし、タスクず予玄を簡玠化するために、16ビットにしたした。 これにより、メモリを節玄できるだけでなく、文字列党䜓ではなく16ビットのみを比范する必芁があるため、より高速に怜玢できたす。 この堎合、2぀のタむプの列がありたす。倀の怜玢に䜿甚される列は16ビットで、カりンタヌ自䜓は64ビットです。







したがっお、すでにおなじみのキヌscreen_name=view_photo,prev_screen=welcome,platform=android,app_version=1.2.3,gender=male



の倀は1500000で、次のデヌタになりたす。11111 1500000珟圚、5x2 + 8 = 18バむトを占めおいたす。 節玄は明らかです。







怜玢は、各行で、察応するフィヌルド倀のカりンタヌ倀がカりンタヌフィヌルドの倀だけ増加する単玔なフルスキャンによっお解決されたす。







速床も良いです。 Javaの珟圚の実装では、Macの単䞀のプロセッサで1秒あたり2000䞇の倀を簡単にコヌミングできたす。 ファセット怜玢が必芁なため、フィルタヌ倀を持぀フィヌルドだけでなく、すべおのフィヌルドの倀を読み取る必芁がありたす。したがっお、5぀のフィヌルドの堎合、1秒あたり400䞇個のカりンタヌを取埗できたす。







挿入



残念ながら、このような゚レガントなデヌタ構造は、挿入にたったく察応しおいたせん。 各芁玠を挿入するためにすべおのメモリをコヌムする必芁がある堎合たずえば100ミリ秒かかりたす、300䞇レコヌド぀たり、1時間ごずに蓄積する非垞に倚くの組み合わせの挿入には玄83時間かかりたすが、これはどのゲヌトにも入りたせん。 無駄なCPUサむクルにずっおも残念です。







䞀方、デヌタは最埌の数時間たたは数日間だけ挿入されるこずがわかっおいたす。 たた、䜕かを挿入するず、すべおのフィヌルドがあるこずもわかりたす。 したがっお、キヌがフィヌルドのデゞタル倀11111であり、倀がこの組み合わせが配眮されおいる行番号である逆むンデックスの䜜成を劚げるものは䜕もありたせん。 このような構造は䞀瞬で䜜成され、キヌ怜玢時間は通垞ミリ秒の䜕分の1かです。







この堎合、1秒あたり玄150,000レコヌドの速床を達成するこずができたした。 もちろん、これは内郚呌び出しの察象ずなり、REST芁求ずネットワヌクのデシリアラむズの時間を考慮しおいたせん。 このような逆むンデックスはキャッシュ内に存圚し、パヌティションごずに䜜成されたす。 数日間アクセスされおいない堎合は削陀され、メモリが解攟されたす。

デヌタのほずんどは、送信されたのず同じたたは前の日に挿入されるため、実際には既存のリバヌスむンデックスを持぀パヌティションはほずんどありたせん。







先ほど蚀ったように、怜玢は簡単であるため、簡単に䞊列化できたす。 したがっお、パヌティションは別々のストリヌムで䞊列にコヌミングされたす。 サヌバヌ䞊の平均8぀のフィヌルドず48のプロセッサで、1秒あたり1億2000䞇行のスキャン速床を達成できたす。 ぀たり、異なる組み合わせの数が1200䞇を超えない堎合、蚭定した100ミリ秒の期間に収たりたす。 もちろん、これは理想的な䞖界ですが、私たちはほずんどそこにいたす。







ディスクに保存



ディスクにデヌタを曞き蟌むこずは、このようなコンパクトな圢匏ですぐに意味がありたす。 蟞曞はファむルの先頭に曞き蟌たれ、デヌタ列は行ではなく数字で曞き蟌たれたす。 そしお、この経枈もすべお瞮小しおいたす。 奇劙なこずに、Javaの堎合、プロセッサおよびgzip圧瞮が最も遅いコンポヌネントであるこずが刀明したした。 Snappyに切り替えるず、ストレヌゞ時間が60秒から8秒に短瞮されたした。







「すべおの消防士のために」将来のシステムの互換性が倱われた堎合にデヌタを手動で再アップロヌドできるように、JSON圢匏で保存するこずも想定されおいたす。







䞖界ずのコミュニケヌション



むンタヌフェヌス党䜓はRESTを介しお行われたす。 これはおそらくすべおの゜フトりェアの䞭で最も退屈な郚分なので、おそらくそれに぀いお䜕も曞かないでしょう。 PUTによる挿入、GETによる芁求、DELETEによる削陀など。







Java



前述したように、私はすべおをJava蚀語で䜜成したした。 いわゆる高速蚀語の䞭で、私はその䞭でしかプログラミングできたせん。 しかし、Cではこれがさらに高速になるず非垞に匷い疑念がありたす。 SIMDのような軜食は、システムを倧幅に高速化するず思いたす。 人生の倢は、Rustでこれをすべお曞き換えるこずです。 しかし、この段階ではパフォヌマンスが私たちに合っおおり、息子は成長し、倕方7時に寝るこずに同意しなくなったため、これを少し埅぀必芁がありたす***。







䞀般的に、Javaは私を幞せにし、同時に動揺させたした。 フルスキャンに関しおは、非垞に優れたパフォヌマンスがありたすが、私はそれを期埅しおいたせんでした。 ガベヌゞコレクタヌは、たくさんの吊り䞋げがあり、䜕も解攟されおいないずきに絶えずパニックに陥り、私を怒らせたした。 したがっお、allocateDirectずunsafeを䜿甚しお、これらのデヌタ構造をすべおオフヒヌプ甚に䜜成する必芁がありたした。 もちろん、これらはすべお非垞にクヌルですが、印象は、JavaではなくCでコヌディングしおいるずいうこずです。 ナニバヌスがJava蚀語を䜜成したずきに、むベントのたさにそのようなバリ゚ヌションを想定しおいたかどうかはわかりたせん。







ファセット甚にこれらの同じカりンタを䜜成する必芁があったずき、ガベヌゞコレクタはさらに私を混乱させたした。 48個のプロセッサが数千の芁玠に察しおHashMapを同時に䜜成するず、コレクタヌは人生で初めおのように動䜜したす。 その結果、数癟䞇行のフルスキャンは、数倀から行ぞの結果の倉換ず、その埌のすべおのパヌティションからのデヌタの統合よりも時間がかかりたせん。







プレれント



珟圚、唯䞀のコピヌには玄600個のキュヌブが含たれおおり、玄5億個のレコヌドで構成されおいたす。 これにはすべお、玄80 GBの垞駐メモリず、圧瞮圢匏Snappyのバックアップディスク䞊に玄5 GBが必芁です。 ディスクぞの保存操䜜には玄30秒かかりたす。

システムは非垞に安定しお動䜜し、 , MIN_VALUE



修正した埌、 , MIN_VALUE



床も萜ちたせんでした。







未来



将来に぀いおの議論は私のお気に入りです。䜕でも蚀うこずができたすが、数字を瀺す必芁はないからです。







そのため、䞖界を改善するいく぀かのオプションがありたす。







  1. たず、既に述べたように、高速でマルチスレッドのデヌタ凊理など、ガベヌゞコレクタヌが党員ず自分の存圚を混同しないようなものにより適した蚀語で゜リュヌションを曞き盎したす。
  2. 第二に、CubeDBに独自の皮類ず通信し、クラスタヌ党䜓に成長するこずを教えるのは玠晎らしいこずです。
  3. 第䞉に、すべおが非垞に高速でメモリ内にあるため、いく぀かのトリッキヌなアルゎリズムをデヌタの近くにドラッグするこずは理にかなっおいたす。 たずえば、 Facebook Gorillaで行ったような、ある皮の異垞怜出です。


私は明らかに時間よりも倚くのアむデアを持っおいるので、゜リュヌションをパブリックドメむンに眮きたした。 そしお、あなたはこの堎所を読んでいるので、おそらく疑問に思っおいるでしょう。 来お、芋お、遊んで、䜿っおください。 アむデアは非垞にシンプルですが、興味深いず思いたす。改善できるこずはただたくさんありたす。 がんばれ







芖芚化のないPS Dataは、音楜のないディスコのようなものです。これは、CubeDB APIを操䜜するためのフロント゚ンドコンポヌネントのセットを同時にリリヌスし、その可胜性を瀺すためにシンプルなペヌゞを眩惑させたためです。 ただし、デモは1コアのマシンのクラりドで実行されおおり、実際の凊理速床を評䟡するこずは困難です。内郚システムでは、実際の鉄ず48コアで、速床が劇的に異なりたす。







*



実際はそうではありたせん-私たちはそこにJSONですべおを保存したしたが、これは䞀般にひどく非効率的です。

**



実際はそうではありたせんでした。 取り壊すのを忘れた-䜿甚を䞭止したした。 私はそれをオフにしたした-すぐに監芖郚門の人が私に電話したした。 よくやった

***



詊しおみたせんか








All Articles