ClickHouseスケヌリング、移行管理、PHPからクラスタヌぞのリク゚スト送信

前の蚘事で、 media2瀟でClickHouse DBMSを実装および䜿甚した経隓を共有したした。 珟圚の蚘事では、同じ物理サヌバヌ内でデヌタを保存および凊理できなくなったずきに分析されるデヌタ量ず負荷の増加に䌎っお発生するスケヌリングの問題に察凊したす。 たた、 DDLク゚リをClickHouseクラスタヌに移行するために開発したツヌルに぀いおも説明したす。







2぀の断片、2぀のレプリカ









ClickHouseは 、異なるデヌタセンタヌにあるクラスタヌで動䜜するように特別に蚭蚈されたした。 DBMSは、数癟のノヌドに線圢にスケヌリングされたす。 したがっお、たずえば、執筆時点でのYandex.Metricaは、400以䞊のノヌドのクラスタヌです。







ClickHouseは、すぐに䜿甚できるシャヌディングずレプリケヌションを提䟛し、テヌブルごずに個別に柔軟に構成できたす。 レプリケヌションにはApache ZooKeeperが必芁ですバヌゞョン3.4.5以降を掚奚。 信頌性を高めるために、5ノヌドのZKクラスタヌアンサンブルを䜿甚したす。 クォヌラムを提䟛するには、奇数のZKノヌド3たたは5などを遞択する必芁がありたす。 ZKはSELECT操䜜では䜿甚されたせんが、たずえば、ALTERク゚リで䜿甚されお列を倉曎し、各レプリカの指瀺を保存するこずに泚意しおください。







シャヌディング



ClickHouseのシャヌディングを䜿甚するず、クラスタヌ内のすべおのノヌドに分散しおクラスタヌ内のデヌタのチャンクを曞き蟌みおよび保存し、クラスタヌ内のすべおのノヌドでデヌタを䞊列凊理読み取りしお、スルヌプットを向䞊させ、埅ち時間を短瞮できたす。 たずえば、GROUP BY ClickHouseを䜿甚したク゚リでは、リモヌトノヌドで集玄が実行され、集玄関数の䞭間状態がリク゚ストの開始ノヌドに枡され、そこで集玄されたす。







シャヌディングには、デヌタを栌玍しない特別な分散゚ンゞンが䜿甚されたすが、SELECTク゚リをシャヌドテヌブルデヌタを含むテヌブルに委任し、受信デヌタの埌続凊理を行いたす。 シャヌドぞのデヌタの曞き蟌みは、2぀のモヌドで実行できたす。1分散テヌブルずオプションのシャヌディングキヌを䜿甚するか、2シャヌドテヌブルに盎接入力し、そこから分散テヌブルを介しおデヌタを読み取りたす。 これらのモヌドをさらに詳しく考えおみたしょう。







最初のモヌドでは、デヌタはシャヌドキヌを䜿甚しお分散テヌブルに曞き蟌たれたす。 最も単玔なケヌスでは、ランダム化キヌは乱数、぀たりrand関数を呌び出した結果である堎合がありたす。 ただし、ハッシュ関数の倀をテヌブルのフィヌルドからシャヌディングキヌずしお取埗するこずをお勧めしたす。これにより、䞀方では小さなデヌタセットを䞀方のシャヌドにロヌカラむズでき、他方ではクラスタヌ内の異なるシャヌドでそのようなセットをかなり均等に分散できたす。 たずえば、ナヌザヌのセッション識別子sess_idを䜿甚するず、同じシャヌドの1人のナヌザヌにペヌゞ衚瀺をロヌカラむズできたすが、異なるナヌザヌのセッションはクラスタヌ内のすべおのシャヌドに均等に分散されたすsess_idフィヌルドの倀に適切な分垃がある堎合。 シャヌディングキヌは、非数倀たたは耇合にするこずもできたす。 この堎合、組み蟌みのハッシュ関数cityHash64を䜿甚できたす。 考慮モヌドでは、クラスタヌノヌドの1぀に曞き蟌たれたデヌタは、シャヌディングキヌを䜿甚しお必芁なシャヌドに自動的にリダむレクトされたすが、トラフィックが増加したす。







より耇雑な方法は、ClickHouseの倖郚から必芁なシャヌドを蚈算し、シャヌドテヌブルに盎接曞き蟌むこずです。 ここでの困難は、利甚可胜なノヌドシャヌドのセットを知る必芁があるずいう事実によるものです。 ただし、この堎合、蚘録はより効率的になり、シャヌディングメカニズム目的のシャヌドを決定するはより柔軟になりたす。







耇補



ClickHouseはデヌタ耇補をサポヌトし、レプリカのデヌタ敎合性を確保したす。 デヌタ耇補には、MergeTreeファミリヌの特別な゚ンゞンが䜿甚されたす。









倚くの堎合、レプリケヌションはシャヌディングず組み合わせお䜿甚​​されたす。 たずえば、6ノヌドのクラスタヌには、2぀のレプリカを持぀3぀のシャヌドが含たれる堎合がありたす。 レプリケヌションはシャヌディングメカニズムに䟝存せず、個々のテヌブルのレベルで機胜するこずに泚意しおください。







デヌタはどのレプリカテヌブルにも曞き蟌むこずができ、ClickHouseはすべおのレプリカ間でデヌタを自動的に同期したす。







ClickHouseクラスタヌの構成䟋



䟋ずしお、4぀のノヌドch63.smi2, ch64.smi2, ch65.smi2, ch66.smi2



さたざたな構成を怜蚎したす。 蚭定は、構成ファむル/etc/clickhouse-server/config.xmlに含たれおいたす。







1぀の断片ず4぀のレプリカ



1぀の断片ず4぀のレプリカ







 <remote_servers> <!-- One shard, four replicas --> <repikator> <shard> <!-- replica 01_01 --> <replica> <host>ch63.smi2</host> </replica> <!-- replica 01_02 --> <replica> <host>ch64.smi2</host> </replica> <!-- replica 01_03 --> <replica> <host>ch65.smi2</host> </replica> <!-- replica 01_04 --> <replica> <host>ch66.smi2</host> </replica> </shard> </repikator> </remote_servers>
      
      





テヌブル䜜成スキヌムの䟋







スキヌム







指定された構成のテヌブルを䜜成するSQLク゚リの䟋







 CREATE DATABASE IF NOT EXISTS dbrepikator ; CREATE TABLE IF NOT EXISTS dbrepikator.anysumming_repl_sharded ( event_date Date DEFAULT toDate(event_time), event_time DateTime DEFAULT now(), body_id Int32, views Int32 ) ENGINE = ReplicatedSummingMergeTree('/clickhouse/tables/{repikator_replica}/dbrepikator/anysumming_repl_sharded', '{replica}', event_date, (event_date, event_time, body_id), 8192) ; CREATE TABLE IF NOT EXISTS dbrepikator.anysumming_repl AS dbrepikator.anysumming_repl_sharded ENGINE = Distributed( repikator, dbrepikator, anysumming_repl_sharded , rand() )
      
      





この構成の利点









短所









1぀のレプリカに4぀の砎片



1぀のレプリカに4぀の砎片







 <remote_servers> <!-- Four shards, one replica --> <sharovara> <!-- shard 01 --> <shard> <!-- replica 01_01 --> <replica> <host>ch63.smi2</host> </replica> </shard> <!-- shard 02 --> <shard> <!-- replica 02_01 --> <replica> <host>ch64.smi2</host> </replica> </shard> <!-- shard 03 --> <shard> <!-- replica 03_01 --> <replica> <host>ch65.smi2</host> </replica> </shard> <!-- shard 04 --> <shard> <!-- replica 04_01 --> <replica> <host>ch66.smi2</host> </replica> </shard> </sharovara> </remote_servers>
      
      





指定された構成のテヌブルを䜜成するSQLク゚リの䟋







 CREATE DATABASE IF NOT EXISTS testshara ; CREATE TABLE IF NOT EXISTS testshara.anysumming_sharded ( event_date Date DEFAULT toDate(event_time), event_time DateTime DEFAULT now(), body_id Int32, views Int32 ) ENGINE = ReplicatedSummingMergeTree('/clickhouse/tables/{sharovara_replica}/sharovara/anysumming_sharded_sharded', '{replica}', event_date, (event_date, event_time, body_id), 8192) ; CREATE TABLE IF NOT EXISTS testshara.anysumming AS testshara.anysumming_sharded ENGINE = Distributed( sharovara, testshara, anysumming_sharded , rand() )
      
      





この構成の利点









欠点









2぀の断片、2぀のレプリカ



2぀の断片、2぀のレプリカ







 <remote_servers> <!-- Two shards, two replica --> <pulse> <!-- shard 01 --> <shard> <!-- replica 01_01 --> <replica> <host>ch63.smi2</host> </replica> <!-- replica 01_02 --> <replica> <host>ch64.smi2</host> </replica> </shard> <!-- shard 02 --> <shard> <!-- replica 02_01 --> <replica> <host>ch65.smi2</host> </replica> <!-- replica 02_02 --> <replica> <host>ch66.smi2</host> </replica> </shard> </pulse> </remote_servers>
      
      





指定された構成のテヌブルを䜜成するSQLク゚リの䟋







 CREATE DATABASE IF NOT EXISTS dbpulse ; CREATE TABLE IF NOT EXISTS dbpulse.normal_summing_sharded ( event_date Date DEFAULT toDate(event_time), event_time DateTime DEFAULT now(), body_id Int32, views Int32 ) ENGINE = ReplicatedSummingMergeTree('/clickhouse/tables/{pulse_replica}/pulse/normal_summing_sharded', '{replica}', event_date, (event_date, event_time, body_id), 8192) ; CREATE TABLE IF NOT EXISTS dbpulse.normal_summing AS dbpulse.normal_summing_sharded ENGINE = Distributed( pulse, dbpulse, normal_summing_sharded , rand() )
      
      





この構成は、最初ず2番目の䟋から最高の品質を実珟したす。









Ansibleクラスタヌの構成䟋



ansibleのクラスタヌ構成は次のようになりたす。







 - name: "pulse" shards: - { name: "01", replicas: ["ch63.smi2", "ch64.smi2"]} - { name: "02", replicas: ["ch65.smi2", "ch66.smi2"]} - name: "sharovara" shards: - { name: "01", replicas: ["ch63.smi2"]} - { name: "02", replicas: ["ch64.smi2"]} - { name: "03", replicas: ["ch65.smi2"]} - { name: "04", replicas: ["ch66.smi2"]} - name: "repikator" shards: - { name: "01", replicas: ["ch63.smi2", "ch64.smi2","ch65.smi2", "ch66.smi2"]}
      
      





ClickHouseクラスタヌを操䜜するためのPHPドラむバヌ



前の蚘事で、 ClickHouse甚のオヌプン゜ヌスPHPドラむバヌに぀いお既に説明したした。







ノヌドの数が倚くなるず、クラスタヌ管理が䞍䟿になりたす。 したがっお、DDLク゚リをClickHouseクラスタヌに移行するためのシンプルで十分に機胜的なツヌルを開発したした。 次に、その機胜の䟋を簡単に説明したす。







クラスタヌに接続するには、 ClickHouseDB\Cluster



クラスが䜿甚されたす。







 $cl = new ClickHouseDB\Cluster( ['host'=>'allclickhouse.smi2','port'=>'8123','username'=>'x','password'=>'x'] );
      
      





allclickhouse.smi2



DNSレコヌドには、すべおのノヌドのIPアドレスがリストされおいたす ch63.smi2, ch64.smi2, ch65.smi2, ch66.smi2



。これにより、 ラりンドロビンDNSメカニズムを䜿甚できたす。







ドラむバヌはクラスタヌに接続し、DNSレコヌドにリストされおいる各ノヌドにping芁求を送信したす。







すべおのクラスタヌノヌドぞの最倧接続時間の蚭定は、次のように構成されたす。







 $cl->setScanTimeOut(2.5); // 2500 ms
      
      





クラスタレプリカのステヌタスの確認は、次のように実行されたす。







 if (!$cl->isReplicasIsOk()) { throw new Exception('Replica state is bad , error='.$cl->getError()); }
      
      





ClickHouseクラスタヌの状態は、次のように確認されたす。









ZKクラスタヌぞのク゚リが実行されるデヌタを受信するずきにlog_max_index, log_pointer, total_replicas, active_replicas



の倀を枛算しない堎合、ク゚リの実行速床を䞊げるこずができたす。







軜量怜蚌の堎合、ドラむバヌに特別なフラグを蚭定する必芁がありたす。







 $cl->setSoftCheck(true);
      
      





䜿甚可胜なすべおのクラスタヌのリストを取埗するには、次のようにしたす。







 print_r($cl->getClusterList()); // result // [0] => pulse // [1] => repikator // [2] => sharovara
      
      





たずえば、䞊蚘で説明したクラスタヌの構成を取埗するには、次のようにしたす。







 foreach (['pulse','repikator','sharovara'] as $name) { print_r($cl->getClusterNodes($name)); echo "> $name , count shard = ".$cl->getClusterCountShard($name)." ; count replica = ".$cl->getClusterCountReplica($name)."\n"; } //: //> pulse , count shard = 2 ; count replica = 2 //> repikator , count shard = 1 ; count replica = 4 //> sharovara , count shard = 4 ; count replica = 1
      
      





クラスタヌ名たたはシャヌドテヌブルからノヌドのリストを取埗する







 $nodes=$cl->getNodesByTable('sharovara.body_views_sharded'); $nodes=$cl->getClusterNodes('sharovara');
      
      





クラスタヌの各ノヌドにリク゚ストを送信しお、テヌブルのサむズたたはすべおのテヌブルのサむズを取埗したす。







 foreach ($nodes as $node) { echo "$node > \n"; print_r($cl->client($node)->tableSize('test_sharded')); print_r($cl->client($node)->tablesSize()); } //    $cl->getSizeTable('dbName.tableName');
      
      





クラスタテヌブルのリストを取埗したす。







 $cl->getTables()
      
      





クラスタヌ内のリヌダヌの定矩







 $cl->getMasterNodeForTable('dbName.tableName') //     is_leader=1
      
      





たずえば、構造の削陀たたは倉曎に関連するリク゚ストは、 is_leader



フラグがis_leader



れたノヌドに送信is_leader



たす。







クラスタヌ内のテヌブルのデヌタを消去する







 $cl->truncateTable('dbName.tableName')`
      
      





DDLク゚リ移行ツヌル



圓瀟は、 MyBatis Migrationsを䜿甚しお、リレヌショナルDBMSのDDLク゚リを移行したす。







Habréの移行ツヌルに぀いおは、すでに次のように曞いおいたす。









ClickHouseクラスタヌを䜿甚するには、同様のツヌルが必芁でした。







執筆時点では、ClickHouseにはDDLク゚リに関連付けられた倚くの機胜制限がありたす。 匕甚 







INSERT、ALTERが耇補されたす詳现に぀いおは、ALTERク゚リの説明を参照しおください。 ク゚リテキストではなく、圧瞮デヌタが耇補されたす。 CREATE、DROP、ATTACH、DETACH、RENAMEリク゚ストはレプリケヌトされたせん。぀たり、同じサヌバヌを参照したす。 CREATE TABLEク゚リは、ク゚リが実行されるサヌバヌに新しいレプリケヌトテヌブルを䜜成したす。 たた、他のサヌバヌにそのようなテヌブルが既にある堎合、新しいレプリカを远加したす。 DROP TABLEク゚リは、ク゚リが実行されるサヌバヌ䞊にあるレプリカを削陀したす。 RENAMEク゚リは、レプリカの1぀にあるテヌブルの名前を倉曎したす。぀たり、異なるレプリカにある耇補されたテヌブルには、異なる名前を付けるこずができたす。

ClickHouse開発チヌムはこの方向での䜜業を既に発衚しおいたすが、珟圚は倖郚ツヌルでこの問題を解決する必芁がありたす。 DDLク゚リをClickHouseクラスタヌに移行するためのphpMigrationsClickhouseツヌルの簡単なプロトタむプを䜜成したした。 そしお、私たちの蚈画はphpMigrationsClickhouseをPHP蚀語から抜象化するこずです。







他のプログラミング蚀語で実装できるphpMigrationsClickhouseで珟圚䜿甚されおいるアルゎリズムに぀いお説明したす。







珟圚、 phpMigrationsClickhouseの移行手順は以䞋で構成されおいたす。









次のコヌドを含むPHPファむルを䜜成したす。







 $cluster_name = 'pulse'; $mclq = new \ClickHouseDB\Cluster\Migration($cluster_name); $mclq->setTimeout(100);
      
      





ロヌルする必芁があるSQLク゚リを远加したす。







 $mclq->addSqlUpdate(" CREATE DATABASE IF NOT EXISTS dbpulse "); $mclq->addSqlUpdate(" CREATE TABLE IF NOT EXISTS dbpulse.normal_summing_sharded ( event_date Date DEFAULT toDate(event_time), event_time DateTime DEFAULT now(), body_id Int32, views Int32 ) ENGINE = ReplicatedSummingMergeTree('/clickhouse/tables/{pulse_replica}/pulse/normal_summing_sharded', '{replica}', event_date, (event_date, event_time, body_id), 8192) ");
      
      





゚ラヌの堎合にロヌルバックを実行するSQLク゚リを远加したす。







 $mclq->addSqlDowngrade(' DROP TABLE IF EXISTS dbpulse.normal_summing_sharded '); $mclq->addSqlDowngrade(' DROP DATABASE IF EXISTS dbpulse ');
      
      





ロヌリング移行には2぀の戊略がありたす。









゚ラヌが発生した堎合、次のオプションが可胜です。









クラスタヌの状態が䞍明な堎合の゚ラヌは、特別な堎所を取りたす。









移行を実行する際のPHPコヌドの動䜜の原則は次のずおりです。







 //   IP-   $node_hosts=$this->getClusterNodes($migration->getClusterName()); //  downgrade- $sql_down=$migration->getSqlDowngrade(); //  upgrade- $sql_up=$migration->getSqlUpdate(); //  upgrade-    ,   ,  downgrade- $need_undo=false; $undo_ip=[]; foreach ($sql_up as $s_u) { foreach ($node_hosts as $node) { //  upgrade- $state=$this->client($node)->write($s_u); if ($state->isError()) { $need_undo = true; } else { // OK } if ($need_undo) { //   ,    $undo_ip[$node]=1; break; } } } //    upgrade-     if (!$need_undo) { return true; // OK }
      
      





゚ラヌが発生した堎合、ダりングレヌド芁求がクラスタヌのすべおのノヌドに送信されたす。







 foreach ($node_hosts as $node) { foreach ($sql_down as $s_u) { try{ $st=$this->client($node)->write($s_u); } catch (Exception $E) { //       downgrade- } } }
      
      





ClickHouseでの経隓に関する䞀連の資料を継続したす。







結論ずしお、小さな調査を実斜したいず思いたす。








All Articles