ClickHouse für fortgeschrittene Benutzer in Fragen und Antworten

Im April trafen sich die Ingenieure von Avito zu einem Online-Meeting mit dem Hauptentwickler von ClickHouse, Alexey Milovidov, und Kirill Shvakov, einem Golang-Entwickler von Integros. Sie diskutierten, wie wir das Datenbankmanagementsystem nutzen und welche Schwierigkeiten dabei auftreten.

Basierend auf dem Treffen haben wir einen Artikel mit Antworten von Experten auf unsere und Zuschauerfragen zu Backups, Resharding von Daten, externen Dictionaries, dem Golang-Treiber und der Aktualisierung von ClickHouse-Versionen zusammengestellt. Dieser könnte für Entwickler nützlich sein, die bereits aktiv mit dem DBMS von Yandex arbeiten und sich für dessen Gegenwart und Zukunft interessieren. Standardmäßig stammen die Antworten von Alexey Milovidov, sofern nicht anders angegeben.

Vorsicht, hinter dem Cut verbirgt sich viel Text. Wir hoffen, dass der Inhalt mit den Fragen Ihnen hilft, sich zurechtzufinden.

ClickHouse für fortgeschrittene Benutzer in Fragen und Antworten

Inhalt

Wenn Sie den Text nicht lesen möchten, können Sie sich die Aufzeichnung der Besprechung ansehen. auf unserem YouTube-Kanal. Die Zeitstempel befinden sich im ersten Kommentar unter dem Video.

ClickHouse wird ständig aktualisiert, aber unsere Daten nicht. Was sollten wir damit tun?

ClickHouse wird ständig aktualisiert, aber unsere Daten, die optimiert final verarbeitet wurden, werden nicht aktualisiert und liegen in der Sicherung.

Angenommen, wir hatten ein Problem und die Daten gingen verloren. Wir beschlossen, uns wiederherzustellen, und stellte sich heraus, dass alte Partitionen, die auf den Backup-Servern gespeichert sind, stark von der derzeit verwendeten Version von ClickHouse abweichen. Was tun in dieser Situation, und ist das überhaupt möglich?

Die Situation, in der Sie Daten aus einem Backup im alten Format wiederhergestellt haben, die in der neuen Version nicht angeschlossen werden, ist unmöglich. Wir achten darauf, dass das Datenformat in ClickHouse immer rückwärtskompatibel bleibt. Das ist viel wichtiger als die Rückwärtskompatibilität in Bezug auf Funktionalität, falls sich das Verhalten einer wenig genutzten Funktion geändert hat. Daten, die auf der Festplatte gespeichert sind, muss die neue Version von ClickHouse stets lesen können. Das ist ein Gesetz.

Was sind derzeit die besten Praktiken für das Backup von Daten aus ClickHouse?

Wie erstellt man Backups unter Berücksichtigung, dass wir optimize final-Operationen, eine riesige Datenbank in Terabyte und Daten haben, die angenommen in den letzten drei Tagen aktualisiert wurden, während mit ihnen keine weiteren Verfahren stattfinden?

Wir können eine eigene Lösung basteln und auf Bash schreiben: Sammle diese Backups so und so. Vielleicht muss man nichts basteln, und das Rad wurde schon lange erfunden?

Zunächst zu den besten Praktiken. Meine Kollegen raten immer, bei Fragen zu Backups an den "Yandex.Cloud"-Dienst zu erinnern, wo dieses Problem bereits gelöst wurde. Also nutzen Sie ihn, wenn es die Möglichkeit gibt.

Es gibt keine vollständige Lösung, die zu hundert Prozent in ClickHouse integriert ist, nur einige Vorlagen, die verwendet werden können. Um eine vollständige Lösung zu erhalten, müssen entweder einige manuelle Anpassungen vorgenommen oder Wrapper in Form von Scripts erstellt werden.

Ich beginne mit den einfachsten Lösungen und gehe zu den komplexesten über, abhängig vom Datenvolumen und der Clustergröße. Je größer der Cluster, desto schwieriger wird die Lösung.

Wenn die Tabelle mit Daten nur einige Gigabyte groß ist, kann das Backup folgendermaßen durchgeführt werden:

  1. Die Tabellenbeschreibung, das heißt die Metadaten, speichern - show create table.
  2. Einen Dump mit dem ClickHouse-Client erstellen - select * from table in eine Datei. Standardmäßig erhalten Sie eine Datei im TabSeparated-Format. Wenn Sie es effizienter möchten, können Sie das Native-Format verwenden.

Wenn das Datenvolumen größer ist, dauert das Backup länger und benötigt viel Platz. Dies wird als logisches Backup bezeichnet, das nicht an das Datenformat von ClickHouse gebunden ist. Sollte es vorhanden sein, können Sie im Extremfall ein Backup nehmen und es in MySQL zum Wiederherstellen laden.

Für fortgeschrittene Fälle bietet ClickHouse die Möglichkeit, einen Snapshot von Partitionen im lokalen Dateisystem zu erstellen. Diese Funktion steht in Form einer Anfrage zur Verfügung alter table freeze partition. Oder einfach alter table freeze – das ist ein Snapshot der gesamten Tabelle.

Der Snapshot wird konsistent für eine Tabelle auf einem Shard erstellt, das heißt, es ist nicht möglich, einen konsistenten Snapshot des gesamten Clusters auf diese Weise zu erstellen. Aber für die meisten Aufgaben ist dies nicht erforderlich, und es reicht aus, den Befehl auf jedem Shard auszuführen und einen konsistenten Snapshot zu erhalten. Er wird in Form von Hardlinks erstellt und benötigt daher keinen zusätzlichen Speicherplatz. Anschließend kopieren Sie diesen Snapshot auf den Backup-Server oder in den Speicher, den Sie für Backups verwenden.

Es ist recht einfach, ein solches Backup wiederherzustellen. Zuerst erstellen Sie die Tabellen nach den bestehenden Tabellenbeschreibungen. Danach kopieren Sie die gespeicherten Partition-Snapshots in das Directory-Detached der entsprechenden Tabellen und führen die Anfrage aus attach partition. Diese Lösung eignet sich durchaus für die ernsthaftesten Datenmengen.

Manchmal braucht man etwas noch Krasseres – in Fällen, in denen Sie Dutzende oder sogar Hunderte Terabyte auf jedem Server und Hunderte von Servern haben. Hier gibt es eine Lösung, die ich bei Kollegen von „Yandex.Metrica“ gesehen habe. Ich würde sie nicht jedem empfehlen – lesen Sie selbst und entscheiden Sie, ob sie geeignet ist oder nicht.

Zuerst müssen mehrere Server mit großen Festplattenspeichern erstellt werden. Anschließend sollten auf diesen Servern mehrere ClickHouse-Server eingerichtet werden, die so konfiguriert sind, dass sie als eine weitere Replik für die gleichen Shards funktionieren. Danach verwenden Sie auf diesen Servern ein Dateisystem oder ein Tool, das Snapshots erstellen kann. Es gibt zwei Varianten. Die erste Variante sind LVM-Snapshots, die zweite Variante ist ZFS auf Linux.

Danach müssen jeden Tag Snapshots erstellt werden, die Platz beanspruchen. Natürlich, wenn sich die Daten ändern, wird der Platzbedarf im Laufe der Zeit steigen. Diese Snapshot kann jederzeit abgerufen und die Daten wiederhergestellt werden – eine seltsame Lösung. Außerdem müssen diese Replikate in der Konfiguration begrenzt werden, damit sie nicht versuchen, zu Leadern zu werden.

Kann man eine kontrollierte Verzögerung der Replikate in den Walen organisieren?

Haben Sie in diesem Jahr vor, Wellen in ClickHouse zu erstellen? Wird es möglich sein, in ihnen kontrollierte Verzögerungen der Replikate zu organisieren? Wir möchten uns mit ihrer Hilfe vor negativen Szenarien mit Alternativen und anderen Änderungen schützen.

Kann man Rollbacks für Alternativen machen? Zum Beispiel in einer bestehenden Welle angeben, dass bis zu diesem Zeitpunkt Änderungen angewendet werden sollen, und ab diesem Zeitpunkt die Anwendung von Änderungen stoppen?

Wenn ein Team in unser Cluster kommt und es kaputt macht, dann haben wir eine bedingte Replik mit einer Verzögerung von einer Stunde, wo wir sagen können, dass wir sie in diesem Moment verwenden werden, aber die letzten zehn Minuten an Änderungen darin nicht anwenden werden?

Zuerst zum kontrollierten Verzögern der Replikate. Es gab einen solchen Antrag von Benutzern, und wir haben ein Issue auf GitHub erstellt mit der Bitte: „Wenn jemand das braucht, liken Sie es, drücken Sie das Herzchen“. Niemand hat geliket, und das Issue wurde geschlossen. Trotzdem kann man bereits jetzt diese Möglichkeit erhalten, indem man ClickHouse konfiguriert. Allerdings nur ab Version 20.3.

ClickHouse führt ständig im Hintergrund die Datenzusammenführung – Merge – durch. Wenn der Merge abgeschlossen ist, wird eine bestimmte Menge an Datenstücken durch ein größeres Stück ersetzt. Dabei bleiben die früheren Datenstücke noch eine gewisse Zeit auf der Festplatte.

Erstens werden sie so lange gespeichert, wie es SELECT-Anfragen gibt, die sie nutzen, um einen nicht blockierenden Betrieb zu ermöglichen. SELECT-Anfragen können problemlos aus den alten Stücken lesen.

Zweitens gibt es auch eine Zeitgrenze – die alten Datenstücke liegen acht Minuten lang auf der Festplatte. Diese Acht Minuten können konfiguriert und sogar auf einen Tag verlängert werden. Das kostet jedoch Speicherplatz: je nach Datenstrom kann sich innerhalb eines Tages nicht nur die Menge verdoppeln, sie kann sogar fünfmal so groß werden. Aber im Ernstfall können Sie den ClickHouse-Server anhalten und alles klären.

Jetzt stellt sich die Frage, wie das vor Altern schützt. Hier lohnt sich ein tieferer Blick, denn in alten Versionen von ClickHouse arbeitete der Alter so, dass er einfach die Stücke direkt änderte. Es gibt ein Datenelement mit bestimmten Dateien, und wir führen zum Beispiel aus, alter drop column. Dann wird diese Spalte physisch aus allen Stücken entfernt.

Doch seit Version 20.3 wurde der Alter-Mechanismus vollständig überarbeitet, und jetzt sind die Datenstücke immer unveränderlich. Sie ändern sich überhaupt nicht – die Alters arbeiten jetzt ähnlich wie die Merges. Anstatt ein Stück vor Ort zu ändern, erstellen wir ein neues. In dem neuen Stück werden die Dateien, die sich nicht geändert haben, zu Hardlinks, und wenn wir eine Spalte gelöscht haben, wird sie einfach im neuen Stück nicht mehr vorhanden sein. Das alte Stück wird standardmäßig nach acht Minuten gelöscht, und hier können die oben genannten Einstellungen angepasst werden.

Das gilt auch für Altern vom Typ Mutationen. Wenn Sie die alter delete oder alter update-Befehle ausführen, wird das Stück nicht geändert, sondern ein neues erstellt. Anschließend wird das alte gelöscht.

Was ist zu tun, wenn sich die Tabellenstruktur geändert hat?

Wie bekomme ich ein Backup wiederhergestellt, das mit einem alten Schema erstellt wurde? Und die zweite Frage beschäftigt sich mit dem Fall von Snapshots und Dateisystemwerkzeugen. Eignet sich hier Btrfs anstelle von ZFS unter Linux LVM?

Wenn Sie attach partition Wenn die Partitionen eine andere Struktur haben, wird ClickHouse Ihnen sagen, dass das nicht erlaubt ist. Die Lösung ist wie folgt. Erstens – erstellen Sie eine temporäre Tabelle vom Typ MergeTree mit der alten Struktur, fügen Sie die Daten mit attach hinzu und führen Sie die Anfrage alter an. Dann können Sie entweder die Daten kopieren oder verschieben und erneut attach ausführen, oder die Anfrage verwenden. alter table move partition.

Jetzt die zweite Frage – kann man Btrfs verwenden? Zunächst, wenn Sie LVM haben, sind LVM-Snapshots ausreichend, und das Dateisystem kann ext4 sein, das spielt keine Rolle. Bei Btrfs hängt alles von Ihrer Erfahrung im Betrieb ab. Es handelt sich um ein ausgereiftes Dateisystem, aber es gibt trotzdem einige Bedenken, wie es in der Praxis in einem bestimmten Szenario funktionieren wird. Ich würde davon abraten, es zu verwenden, wenn Sie Btrfs nicht in der Produktion haben.

Was sind momentan die besten Praktiken im Resharding von Daten?

Die Frage des Re-Shardings ist komplex und vielschichtig. Hier kann man sofort auf mehrere Arten antworten. Man kann von einer Seite herangehen und sagen – in ClickHouse gibt es keine eingebaute Möglichkeit für Re-Sharding. Aber ich fürchte, diese Antwort wird niemanden zufriedenstellen. Also kann man von der anderen Seite sagen, dass es in ClickHouse viele Möglichkeiten gibt, Daten umzuschichten.

Wenn der Speicher im Cluster zur Neige geht oder er mit der Last nicht zurechtkommt, fügen Sie neue Server hinzu. Diese Server sind jedoch standardmäßig leer, auf ihnen sind keine Daten, und es erfolgt keine Lastenverteilung. Sie müssen die Daten umverteilen, damit sie gleichmäßig auf dem neuen, vergrößerten Cluster verteilt werden.

Der erste Weg, wie man das machen kann, ist, einen Teil der Partitionen mit einer Anfrage auf die neuen Server zu kopieren. alter table fetch partition. Zum Beispiel hatten Sie Partitionen nach Monaten, und Sie nehmen den ersten Monat des Jahres 2017 und kopieren ihn auf den neuen Server, dann – den dritten Monat auf einen anderen neuen Server. Und so machen Sie weiter, bis es einigermaßen gleichmäßig verteilt ist.

Der Transfer kann nur für die Partitionen durchgeführt werden, die sich beim Schreiben nicht ändern. Für neue Partitionen muss das Schreiben deaktiviert werden, da deren Transfer nicht atomar ist. Andernfalls erhalten Sie Duplikate oder Lücken in den Daten. Dennoch ist dieser Ansatz praktikabel und funktioniert ziemlich effektiv. Über das Netzwerk werden bereits fertige komprimierte Partitionen übertragen, das heißt, die Daten werden nicht erneut komprimiert oder umcodiert.

Diese Methode hat einen Nachteil, der von dem Sharding-Schema abhängt, das Sie verwendet haben, sowie von Ihrem Sharding-Schlüssel. In Ihrem Beispiel für den Fall mit Metriken ist der Sharding-Schlüssel der Hash des Pfades. Wenn Sie eine Select-Anfrage an die verteilte Tabelle senden, erfolgt diese sofort an alle Shards des Clusters, um die Daten abzurufen.

Das bedeutet, dass es für Sie im Grunde genommen irrelevant ist, welche Daten auf welchem Shard gelandet sind. Wichtig ist, dass die Daten für einen bestimmten Pfad auf einem Shard liegen, und welcher genau, spielt keine Rolle. In diesem Fall eignet sich das Übertragen fertiger Partitionen hervorragend, denn bei Select-Anfragen erhalten Sie— sowohl vor als auch nach dem Sharding — vollständige Daten.

Es gibt jedoch auch kompliziertere Fälle. Wenn Sie auf Anwendungsebene sich auf ein spezielles Sharding-Schema verlassen, um sicherzustellen, dass dieser Kunde auf einem bestimmten Shard liegt, können Sie die Anfrage direkt dorthin senden, anstatt an die verteilte Tabelle. Oder Sie verwenden eine relativ neue Version von ClickHouse und haben die Einstellung optimize skip unused shardsaktiviert. In diesem Fall wird während der Select-Anfrage der Ausdruck im WHERE-Abschnitt analysiert und ermittelt, auf welche Shards gemäß dem Sharding-Schema zugegriffen werden muss. Dies funktioniert vorausgesetzt, dass die Daten tatsächlich entsprechend diesem Sharding-Schema angeordnet sind. Wenn Sie sie manuell verschoben haben, kann die Übereinstimmung variieren.

Das ist also Methode Nummer eins. Ich warte auf Ihre Antwort, ob diese Methode für Sie geeignet ist, oder ob wir weitermachen sollen.

Wladimir Kolobajew, leitender Systemadministrator bei Avito: Alexej, die Methode, die Sie erwähnt haben, eignet sich nicht sehr gut, wenn es darum geht, die Last, auch beim Lesen, gleichmäßig zu verteilen. Wir können eine monatliche Partition nehmen und den vorherigen Monat auf einen anderen Knoten verschieben, aber wenn die Anfrage nach diesen Daten kommt, belasten wir nur diesen einen Knoten. Wir möchten jedoch den gesamten Cluster belasten, denn andernfalls wird eine Zeit lang die gesamte Leselast von nur zwei Shards verarbeitet.

Alexej Milovidov: Die Antwort hier ist seltsam – ja, schlecht, aber es könnte funktionieren. Ich werde erklären, wie genau. Es ist wichtig, das Lastszenario zu betrachten, das hinter Ihren Daten steht. Wenn es sich um Überwachungsdaten handelt, kann man fast sicher sagen, dass die überwiegende Mehrheit der Anfragen auf frische Daten abzielt.

Sie haben neue Server aufgestellt, die alten Partitionen verschoben, aber auch geändert, wie frische Daten aufgezeichnet werden. Und die frischen Daten werden über das gesamte Cluster verteilt. So werden bereits nach fünf Minuten die Anfragen für die letzten fünf Minuten gleichmäßig das Cluster belasten, und nach einem Tag werden die Anfragen für den Tag gleichmäßig das Cluster belasten. Leider werden die Anfragen für den letzten Monat nur auf einen Teil der Server im Cluster gehen.

Aber häufig werden Sie keine Anfragen speziell für Februar 2019 haben. Wahrscheinlich, wenn die Anfragen ins Jahr 2019 gehen, dann werden sie für das gesamte Jahr 2019 sein – für einen größeren Zeitraum und nicht für einen kleinen Bereich. Solche Anfragen können das Cluster ebenfalls gleichmäßig belasten. Aber insgesamt ist Ihre Anmerkung völlig richtig, dass dies eine ad hoc Lösung ist, die die Daten nicht vollständig gleichmäßig verteilt.

Ich habe noch einige Punkte, um auf die Frage zu antworten. Einer davon betrifft, wie man anfangs das Sharding-Schema so gestaltet, dass es weniger schmerzhaft ist, neu zu sharden. Das ist möglicherweise nicht immer möglich.

Zum Beispiel haben Sie Überwachungsdaten. Die Überwachungsdaten wachsen aus drei Gründen. Erstens – die Ansammlung historischer Daten. Zweitens – das Wachstum des Traffics. Und drittens – die Zunahme der Dinge, die überwacht werden. Es kommen neue Mikroservices und Metriken hinzu, die gespeichert werden müssen.

Möglicherweise ist das größte Wachstum einer dieser Gründe – die Zunahme der Nutzung der Überwachung. In diesem Fall sollten Sie sich das Lastverhalten ansehen, was die Hauptanfragen zu select sind. Die Hauptanfragen zu select werden wahrscheinlich auf einem bestimmten Teilmenge der Metriken abzielen.

Zum Beispiel die Nutzung von CPU auf bestimmten Servern durch einen bestimmten Dienst. Es gibt also eine bestimmte Teilmenge von Schlüsseln, über die Sie diese Daten abrufen. Und die Anfrage nach diesen Daten ist wahrscheinlich ziemlich einfach und wird in wenigen Millisekunden ausgeführt. Dies wird für Monitoring-Dienste und Dashboards verwendet. Ich hoffe, ich verstehe das richtig.

Wladimir Kolobajew: Es geht darum, dass wir sehr oft auf historische Daten zugreifen, da wir in Echtzeit die aktuelle Situation mit historischen vergleichen. Und es ist wichtig für uns, schnell Zugang zu einem großen Datenvolumen zu haben, und ClickHouse kommt damit hervorragend zurecht.

Sie haben absolut recht, die meisten Leseanfragen erfahren wir am letzten Tag, wie jede Monitoring-System. Aber auch die historische Datenlast ist ziemlich hoch. Sie stammt hauptsächlich vom Alarming-System, das alle dreißig Sekunden zu ClickHouse geht und sagt: „Gib mir die Daten der letzten sechs Wochen. Und jetzt erstelle mir aus diesen Daten einen gleitenden Durchschnitt, und lass uns den aktuellen Wert mit dem historischen vergleichen.“

Ich wollte sagen, dass wir für solche sehr frischen Anfragen eine kleine Tabelle haben, in der wir nur zwei Tage Daten speichern, und die Hauptanfragen gehen in diese. In die große sharded Tabelle senden wir nur große historische Anfragen.

Alexej Milovidov: Leider ist das für Ihr Szenario schlecht anwendbar, aber ich werde die Beschreibung zweier schlechterm und komplizierter Sharding-Schemata erzählen, die man nicht verwenden sollte, aber die im Dienst meiner Freunde genutzt werden.

Es gibt einen Hauptcluster mit Ereignissen von „Yandex.Metrica“. Ereignisse sind Seitenaufrufe, Klicks und Übergänge. Die meisten Anfragen gehen an eine bestimmte Website. Sie öffnen den Dienst „Yandex.Metrica“, haben eine Website – avito.ru, gehen in den Bericht und es erfolgt eine Anfrage zu Ihrer Website.

Aber es gibt auch andere Anfragen – analytische und globale, die interne Analysten stellen. Zur Sicherheit möchte ich bemerken, dass interne Analysten nur Anfragen zu den „Yandex“-Diensten stellen. Dennoch machen die „Yandex“-Dienste einen beträchtlichen Anteil aller Daten aus. Das sind keine Anfragen zu bestimmten Zählern, sondern zu breiteren Filterungen.

Wie organisiert man die Daten so, dass sowohl durch einen einzelnen Zähler alles effizient funktioniert als auch die globalen Anfragen? Die Komplexität liegt auch darin, dass die Anzahl der Anfragen an ClickHouse im Cluster "Metrics" mehrere tausend pro Sekunde beträgt. Dabei handelt es sich um nicht triviale Anfragen, beispielsweise kann ein einzelner ClickHouse-Server nicht mehrere tausend pro Sekunde bewältigen.

Die Clustergröße beträgt über sechshundert Server. Wenn man einfach eine verteilte Tabelle über dieses Cluster zieht und mehrere tausend Anfragen dorthin sendet, wird es noch schlimmer, als sie an einen einzelnen Server zu senden. Auf der anderen Seite lehnen wir die Möglichkeit ab, dass die Daten gleichmäßig verteilt sind und wir von allen Servern anfragen.

Es gibt eine diametral entgegengesetzte Möglichkeit. Stellen Sie sich vor, wir shardieren die Daten nach Websites, und die Anfrage für eine Website geht an einen Shard. Nun kann das Cluster durchaus zehntausend Anfragen pro Sekunde bewältigen, aber auf einem Shard wird eine bestimmte Anfrage zu langsam sein. Sie kann nicht mehr in Bezug auf die Bandbreite skaliert werden. Besonders wenn es sich um die Website avito.ru handelt. Ich werde kein Geheimnis verraten, wenn ich sage, dass Avito eine der meistbesuchten Websites im russischen Internet ist. Es wäre wahnsinnig, sie auf einem Shard zu verarbeiten.

Deshalb ist das Sharding-Schema komplexer gestaltet. Das gesamte Cluster ist in eine bestimmte Anzahl von Clusterteilen unterteilt, die wir Schichten nennen. Innerhalb jedes Clusterteils gibt es zwischen zehn und mehreren Dutzend Shards. Insgesamt gibt es neununddreißig solcher Clusterteile.

Wie wird das alles skaliert? Die Anzahl der Clusterteile bleibt konstant – vor einigen Jahren waren es neununddreißig, und das ist auch heute noch so. Aber innerhalb jedes Teils erhöhen wir allmählich die Anzahl der Shards mit zunehmenden Datenmengen. Und das Sharding-Schema insgesamt sieht so aus – die Aufteilung in diese Clusterteile erfolgt nach Websites, und um zu verstehen, welche Website auf welchem Cluster angesiedelt ist, wird eine separate Metadatenbank in MySQL verwendet. Eine Website – in einem Clusterteil. Und innerhalb davon erfolgt das Sharding nach den Nutzeridentifikatoren.

Bei der Aufzeichnung teilen wir sie nach dem Rest der Division der Besucheridentifikatoren auf. Aber beim Hinzufügen eines neuen Shards ändert sich das Sharding-Schema, wir teilen weiterhin auf, jedoch beim Rest der Division durch eine andere Zahl. Das bedeutet, dass ein Besucher tatsächlich auf mehreren Servern platziert werden kann, und darauf sollte man nicht setzen. Dies wurde ausschließlich gemacht, um die Daten besser zu komprimieren. Bei Anfragen gehen wir auf die verteilte Tabelle, die den Cluster abfragt und sich an Dutzende von Servern wendet. So ein merkwürdiges Schema.

Aber meine Erzählung wäre unvollständig, wenn ich nicht sage, dass wir dieses Schema abgelehnt haben. Im neuen Schema haben wir alles geändert und alle Daten mithilfe von clickhouse-copier kopiert.

Im neuen Schema werden alle Websites in zwei Kategorien unterteilt – große und kleine. Ich weiß nicht, wie dort die Schwelle gewählt wurde, aber in der Folge stellt sich heraus, dass große Websites in einem Cluster gespeichert werden, der 120 Shards mit je drei Replikaten enthält – also 360 Server. Und das Sharding-Schema ist so, dass jede Anfrage sofort an alle Shards geht. Wenn Sie jetzt in „Yandex.Metrica“ eine beliebige Berichtseite für avito.ru öffnen, wird die Anfrage an 120 Server gesendet. Es gibt nur wenige große Websites im russischen Internet. Dadurch gibt es nicht tausend Anfragen pro Sekunde, sondern sogar weniger als hundert. All dies wird gemächlich von der verteilten Tabelle verarbeitet, die jeder von ihnen mithilfe von 120 Servern bearbeitet.

Und der zweite Cluster ist für kleine Websites. Hier basiert das Sharding-Schema auf der Identifikationsnummer der Website, und jede Anfrage geht genau an einen Shard.

In ClickHouse gibt es das Tool clickhouse-copier. Können Sie darüber sprechen?

Ich sage gleich, dass diese Lösung voluminöser und etwas weniger leistungsfähig ist. Der Vorteil besteht darin, dass sie die Daten vollständig gemäß dem Schema verteilt, das Sie angeben. Aber der Nachteil des Tools besteht darin, dass es kein Neuscharding durchführt. Es kopiert Daten von einer Clusterstruktur in eine andere Clusterstruktur.

Das bedeutet, dass Sie für ihre Funktionalität über zwei Cluster verfügen müssen. Diese können auf denselben Servern gehostet werden, dennoch werden die Daten nicht inkrementell verschoben, sondern kopiert.

Zum Beispiel, es gab vier Server, jetzt sind es acht. Sie erstellen auf allen Servern eine neue Distributed-Tabelle, neue lokale Tabellen und starten den clickhouse-copier, wobei Sie ihm das Schema angeben, dass es von dort lesen, das neue Sharding-Schema annehmen und die Daten dorthin verschieben soll. Und auf den alten Servern benötigen Sie anderthalb Mal mehr Platz als jetzt, weil die alten Daten darauf bleiben müssen, und zusätzlich kommt die Hälfte der alten Daten oben drauf. Wenn Sie im Voraus darüber nachgedacht haben, dass die Daten neu shardiert werden müssen und Platz vorhanden ist, dann ist diese Methode geeignet.

Wie funktioniert clickhouse-copier intern? Er zerlegt die gesamte Arbeit in eine Reihe von Aufgaben zur Verarbeitung einer Partition einer Tabelle auf einem Shard. Alle diese Aufgaben können parallel ausgeführt werden, und clickhouse-copier kann auf verschiedenen Maschinen in mehreren Instanzen gestartet werden. Das, was er für eine Partition macht, ist nicht anderes als ein insert select. Die Daten werden gelesen, dekomprimiert, neu shardiert, dann wieder komprimiert und irgendwohin geschrieben, umsortiert. Dies ist eine schwerere Lösung.

Hatten Sie ein Pilotprojekt namens Resharding? Was ist damit passiert?

Sie hatten bereits 2017 ein Pilotprojekt, das Resharding genannt wurde. Es gibt sogar eine Option in ClickHouse. Ich verstehe, dass es nicht funktioniert hat. Können Sie erzählen, warum das so war? Es scheint doch sehr aktuell zu sein.

Das ganze Problem ist, dass bei der Notwendigkeit, Daten vor Ort neu zu sharden, eine sehr komplexe Synchronisation erforderlich ist, um dies atomar zu machen. Als wir uns ansahen, wie diese Synchronisation funktioniert, wurde klar, dass es grundlegende Probleme gibt. Und diese grundlegenden Probleme sind nicht nur theoretisch, sondern zeigen sich sofort in der Praxis, und zwar in einer sehr einfachen Erklärung – es funktioniert einfach nicht.

Kann man alle Teile der Daten vor dem Verschieben auf langsame Festplatten zusammenführen?

Frage zu TTL mit der Option move to slow disk im Kontext von Merges. Gibt es eine Möglichkeit, außer über cron, alle Teile vor der Verschiebung auf langsame Festplatten in einem zu verschmelzen?

Die Antwort auf die Frage, ob man irgendwie alle Teile vor deren Transfer automatisch zusammenfügen kann, ist nein. Ich denke, das ist nicht notwendig. Man kann auch alle Teile nicht in einem verschmelzen, sondern einfach darauf setzen, dass sie automatisch auf langsame Festplatten verschoben werden.

Wir haben zwei Kriterien für die Migration. Das erste ist die Füllung. Wenn auf dem aktuellen Speicherlevel weniger als ein bestimmter Prozentsatz freier Speicher vorhanden ist, wählen wir einen Block aus und verschieben ihn auf den langsameren Speicher. Besser gesagt, nicht auf den langsameren, sondern auf den nächsten – je nach Ihren Einstellungen.

Das zweite Kriterium ist die Größe. Es geht darum, große Blöcke zu verschieben. Sie können die Schwelle für den freien Speicher auf der schnellen Festplatte einstellen, und die Daten werden automatisch verschoben.

Wie kann man auf die neuen Versionen von ClickHouse migrieren, wenn man die Kompatibilität nicht im Voraus überprüfen kann?

Dieses Thema wird regelmäßig diskutiert im Telegram-Chat ClickHouse unter Berücksichtigung verschiedener Versionen, und dennoch. Wie sicher ist es, von Version 19.11 auf 19.16 und beispielsweise von 19.16 auf 20.3 zu aktualisieren? Wie kann man am besten auf neue Versionen umsteigen, ohne die Möglichkeit zu haben, die Kompatibilität im Voraus in einer Sandbox zu überprüfen?

Hier sind einige "goldene" Regeln. Die erste ist, lesen Sie das Changelog. Es ist umfangreich, aber dort gibt es spezielle Punkte zu rückwärtsinkompatiblen Änderungen. Man sollte diese Punkte nicht als roten Alarm betrachten. Normalerweise sind das kleinere Inkompatibilitäten, die mit bestimmten Randfunktionen zusammenhängen, die Sie höchstwahrscheinlich nicht nutzen.

Zweitens – wenn keine Möglichkeit besteht, die Kompatibilität in einer Sandbox zu überprüfen, und Sie sofort in der Produktion aktualisieren möchten, lautet die Empfehlung – tun Sie es nicht. Erstellen Sie zunächst eine Sandbox und testen Sie. Wenn es keine Testumgebung gibt, bedeutet das wahrscheinlich, dass Sie nicht sehr groß sind, also können Sie einen Teil der Daten auf Ihren Laptop kopieren und dort prüfen, ob alles korrekt funktioniert. Sie könnten sogar mehrere Replikate lokal auf Ihrem Rechner hochziehen. Oder Sie können irgendwo in der Nähe die neue Version installieren und einen Teil der Daten dort hochladen – das heißt, eine improvisierte Testumgebung schaffen.

Eine weitere Regel ist, in der Woche nach der Veröffentlichung einer Version nicht zu aktualisieren, um Bugs in der Produktion zu erfassen und darauf folgende schnelle Fixes zu ermöglichen. Lassen Sie uns die Versionsnummerierung von ClickHouse klären, um nicht durcheinander zu kommen.

Es gibt die Version 20.3.4. Die Zahl 20 steht für das Jahr der Veröffentlichung – 2020. Innerhalb bedeutet das nichts, also lassen wir das beiseite. Weiter geht's mit 20.3. Die zweite Zahl – in diesem Fall 3 – erhöhen wir jedes Mal, wenn wir ein Release mit einer neuen Funktion veröffentlichen. Wenn wir ClickHouse um eine Fähigkeit erweitern möchten, sind wir verpflichtet, diese Zahl zu erhöhen. Das bedeutet, dass ClickHouse in Version 20.4 noch besser funktionieren wird. Die dritte Zahl – 20.3.4. Hier steht die 4 für die Anzahl der Patch-Releases, in denen wir keine neuen Funktionen hinzugefügt haben, aber einige Bugs behoben haben. Und 4 bedeutet, dass wir das viermal gemacht haben.

Man sollte nicht denken, dass dies etwas Schreckliches ist. In der Regel kann der Benutzer die neueste Version installieren, und sie wird ein Jahr lang problemfrei laufen. Aber stellen Sie sich vor, dass eine Funktion zur Verarbeitung von Bitmaps, die von unseren chinesischen Kollegen hinzugefügt wurde, bei falschen Argumenten den Server zum Absturz bringt. Wir sind verpflichtet, das zu beheben. Wir werden eine neue Patch-Version veröffentlichen, und ClickHouse wird stabiler.

Wenn Sie ClickHouse in der Produktion haben und eine neue Version mit zusätzlichen Funktionen herauskommt – zum Beispiel 20.4.1 – eilen Sie nicht, sie sofort am ersten Tag in die Produktion zu bringen. Warum ist sie überhaupt notwendig? Wenn Sie ClickHouse noch nicht verwenden, können Sie es installieren, und höchstwahrscheinlich wird alles gut funktionieren. Aber wenn ClickHouse bereits stabil läuft, beobachten Sie die Patches und Updates – welche Probleme wir beheben.

Kirill Shvakov: Ich möchte ein wenig über Testumgebungen ergänzen. Viele haben große Angst vor Testumgebungen und denken aus irgendeinem Grund, dass, wenn Sie einen sehr großen ClickHouse-Cluster haben, die Testumgebung nicht kleiner oder zumindest zehnmal kleiner sein sollte. Das ist ganz und gar nicht so.

Ich kann aus meiner eigenen Erfahrung sprechen. Ich habe ein Projekt, und dort gibt es ClickHouse. Unsere Testumgebung dafür ist eine kleine virtuelle Maschine in Hetzner für zwanzig Euro, wo alles vollständig eingerichtet ist. Um das zu machen, haben wir eine vollständige Automatisierung in Ansible, und daher spielt es eigentlich keine Rolle, ob wir auf physische Server oder einfach in Virtuellen Maschinen deployen.

Was kann man tun? Es wäre hilfreich, in der ClickHouse-Dokumentation ein Beispiel zu haben, wie man ein kleines Cluster selbst aufbaut – in Docker, in LXC, vielleicht sogar ein Ansible-Playbook zu erstellen, da die Deployments bei verschiedenen Personen unterschiedlich sind. Das würde vieles erleichtern. Wenn man in fünf Minuten ein Cluster aufsetzt, ist es viel einfacher, sich mit den Details vertraut zu machen. So ist es viel angenehmer, denn in eine Produktionsversion zu gehen, die man nicht getestet hat, ist ein Weg ins Nichts. Manchmal funktioniert es, manchmal nicht. Daher ist es schlecht, auf den Erfolg zu hoffen.

Maxim Kotyakov, Senior Backend Engineer bei Avito: Ich möchte etwas zu den Testumgebungen sagen, die Teil des Problems großer Unternehmen sind. Wir haben ein vollständiges Abnahme-Cluster von ClickHouse, das in Bezug auf Datenschemata und Einstellungen eine genaue Kopie dessen ist, was in der Produktion vorhanden ist. Dieses Cluster ist in ziemlich abgedroschenen Containern mit minimalen Ressourcen installiert. Wir schreiben einen gewissen Prozentsatz der Produktionsdaten hinein, Gott sei Dank gibt es die Möglichkeit, den Flow in Kafka zu replizieren. Dort ist alles synchronisiert und skaliert – sowohl in Bezug auf die Leistung als auch auf den Flow, und theoretisch sollte es sich bei gleichen Bedingungen wie die Produktion verhalten. Alles potenziell explosiv geht zuerst auf diesen Stand und reift dort mehrere Tage, bis es bereit ist. Aber natürlich ist diese Lösung teuer, aufwendig und hat nicht unerhebliche Unterhaltungskosten.

Alexej Milovidov: Ich werde erzählen, wie die Testumgebung unserer Freunde von Yandex.Metrica aussieht. Ein Cluster hatte über 600 Server, ein anderer 360, und es gibt noch einen dritten und mehrere Cluster. Die Testumgebung für einen von ihnen besteht einfach aus zwei Shards mit jeweils zwei Replikaten. Warum zwei Shards? Damit es nicht nur einen gibt. Und auch Replikate, damit es diese gibt. Einfach eine gewisse minimale Anzahl, die man sich leisten kann.

Diese Testumgebung ermöglicht es, die Funktionsfähigkeit der Abfragen zu überprüfen und sicherzustellen, dass nichts Größeres kaputt gegangen ist. Aber häufig treten Probleme ganz anderer Art auf, wenn alles funktioniert, aber es einige kleine Änderungen bei der Last gibt.

Ich gebe ein Beispiel. Wir haben uns entschieden, eine neue Version von ClickHouse zu installieren. Diese ist in der Testumgebung bereitgestellt, automatisierte Tests in Yandex.Metrica wurden durchgeführt, die die Daten der alten und neuen Version vergleichen, indem sie den gesamten Workflow durchlaufen. Und natürlich die grünen Tests unseres CI. Andernfalls hätten wir diese Version nicht einmal vorgeschlagen.

Alles ist hervorragend. Wir beginnen mit der Bereitstellung im Produktionsumfeld. Ich erhalte eine Nachricht, dass die Auslastung auf den Grafiken mehrfach gestiegen ist. Wir rollen die Version zurück. Ich schaue mir das Diagramm an und sehe: Die Auslastung ist während der Bereitstellung tatsächlich mehrfach gestiegen und hat sich wieder verringert, sobald wir sie zurückgenommen haben. Dann haben wir die Version zurückgesetzt und die Auslastung ist auf die gleiche Weise gestiegen und genauso wieder gefallen. Die Schlussfolgerung ist also: Die Auslastung ist aufgrund der Bereitstellung gestiegen, nichts Überraschendes.

Danach war es schwierig, die Kollegen zu überzeugen, die neue Version tatsächlich zu installieren. Ich sage: „Alles in Ordnung, rollt sie aus. Haltet die Daumen, es wird alles funktionieren. Momentan ist die Auslastung auf den Grafiken gestiegen, aber alles ist in Ordnung. Bleibt fest“. Insgesamt haben wir das so gemacht, und die Version wurde auf die Produktionsumgebung bereitgestellt. Aber fast bei jeder Bereitstellung treten ähnliche Probleme auf.

Der Kill-Query sollte Anfragen abbrechen, tut dies jedoch nicht. Warum?

Ein Benutzer kam zu mir, irgendein Analyst, und stellte eine Anfrage, die meinen ClickHouse-Cluster überlastete. Eine bestimmte Node oder der gesamte Cluster — je nachdem, in welche Replik oder Shard die Anfrage eingegangen ist. Ich sehe, dass alle CPU-Ressourcen auf diesem Server in den roten Bereich gefallen sind, alles rot. Gleichzeitig antwortet ClickHouse weiterhin auf die Anfragen. Und ich schreibe: „Zeig mir bitte die Prozessliste, welche Anfrage hat dieses Chaos verursacht“.

Ich finde diese Anfrage und schreibe ihm kill. Und ich sehe, dass nichts passiert. Mein Server ist im roten Bereich, ClickHouse gibt mir weiterhin Befehle, zeigt, dass der Server lebt, und alles ist großartig. Aber ich habe eine Leistungsverschlechterung bei allen Benutzeranfragen, die Schreibleistung in ClickHouse beginnt zu sinken, und mein kill query funktioniert nicht. Warum? Ich dachte, dass kill query die Anfragen töten sollte, aber das passiert nicht.

Jetzt wird die Antwort ziemlich seltsam sein. Die Sache ist, dass kill query die Anfragen nicht tötet.

Kill query setzt eine kleine Flagge mit dem Namen „Ich möchte, dass diese Anfrage getötet wird“. Bei der Verarbeitung jedes Blocks schaut die Anfrage auf dieses Flag. Wenn es gesetzt ist, hört die Anfrage auf zu arbeiten. Das bedeutet, dass niemand die Anfrage tötet, sie muss alles selbst überprüfen und anhalten. Und das sollte in allen Fällen funktionieren, wenn die Anfrage im Zustand der Verarbeitung von Datenblöcken ist. Sie verarbeitet den nächsten Datenblock, überprüft das Flag und stoppt.

Das funktioniert nicht, wenn eine Anfrage für eine bestimmte Operation blockiert ist. Wahrscheinlich ist dies jedoch nicht Ihr Fall, da Sie sagen, dass er eine Menge Serverressourcen nutzt. Möglicherweise funktioniert es nicht bei externen Sortierungen und in einigen anderen Details. Aber insgesamt sollte es so nicht sein, das ist ein Bug. Das Einzige, was ich empfehlen kann, ist, ClickHouse zu aktualisieren.

Wie berechnet man die Antwortzeit bei Leseanfragen?

Es gibt eine Tabelle, in der Aggregate für Artikel - verschiedene Zähler - gespeichert sind. Die Anzahl der Zeilen beträgt etwa hundert Millionen. Kann man mit vorhersehbaren Antwortzeiten rechnen, wenn man 1K RPS für 1K Artikel einspeist?

Nach dem Kontext handelt es sich um eine Leseanfrage, da es bei Schreiben keine Probleme gibt - man kann Tausende, Hunderte von Tausenden oder manchmal sogar mehrere Millionen Zeilen einfügen.

Leseanfragen können sehr unterschiedlich sein. In einem select 1 kann ClickHouse etwa zehntausend Anfragen pro Sekunde ausführen, daher erfordern selbst Anfragen nach einem Schlüssel bereits einige Ressourcen. Solche punktgenauen Anfragen sind komplizierter als in irgendeiner Key-Value-Datenbank, da für jedes Lesen ein Datenblock nach dem Index gelesen werden muss. Der Index adressiert nicht jeden Datensatz, sondern jeden Bereich. Das bedeutet, dass der gesamte Bereich gelesen werden muss - das sind standardmäßig 8192 Zeilen. Und der komprimierte Datenblock von 64 Kb muss auf 1 Mb decompressiert werden. Solche punktgenauen Anfragen dauern normalerweise von einigen Millisekunden. Aber das ist die einfachste Variante.

Lassen Sie uns versuchen, einfache Mathematik zu betreiben. Wenn man mehrere Millisekunden mit eintausend multipliziert, erhält man einige Sekunden. Es scheint, als könnte man eintausend Anfragen pro Sekunde nicht verarbeiten, aber in Wirklichkeit kann man das, denn wir haben mehrere Prozessorkerne. Daher kann ClickHouse prinzipiell manchmal 1000 RPS verarbeiten, aber bei kurzen, ganz gezielten Anfragen.

Wenn es notwendig ist, das ClickHouse-Cluster hinsichtlich der Anzahl einfacher Anfragen zu skalieren, empfehle ich das einfachste - die Anzahl der Replikate zu erhöhen und Anfragen an ein zufälliges Replikat zu senden. Wenn ein Replikat fünfhundert Anfragen pro Sekunde bewältigen kann, was durchaus realistisch ist, können drei Replikate eintausendfünfhundert Anfragen bewältigen.

Manchmal kann man natürlich ClickHouse auch auf die maximale Anzahl an punktuellen Lesevorgängen einstellen. Was ist dafür nötig? Erstens – die Granularität des Indexes zu verringern. Dabei sollte man sie nicht auf eins reduzieren, sondern davon ausgehen, dass die Anzahl der Aufzeichnungen im Index mehrere Millionen oder zig Millionen auf dem Server betragen wird. Wenn die Tabelle hundert Millionen Zeilen hat, kann man die Granularität auf 64 festlegen.

Man kann die Größe des komprimierten Blocks verringern. Dafür gibt es Einstellungen. min compress block size, max compress block size. Man kann sie reduzieren, die Daten neu anlegen, und dann werden die punktuellen Abfragen schneller. Aber dennoch ist ClickHouse keine key-value-Datenbank. Eine große Anzahl kleiner Anfragen ist ein Antipattern in der Lastverteilung.

Kirill Shvakov: Ich gebe einen Ratschlag für den Fall, dass es sich um gewöhnliche Kunden handelt. Das ist eine ziemlich standardmäßige Situation, wenn ClickHouse einen Zähler speichert. Ich habe einen Benutzer, der aus diesem oder jenem Land stammt, und ein drittes Feld, und es muss inkrementell etwas erhöht werden. Nehmen Sie MySQL, erstellen Sie einen eindeutigen Schlüssel – in MySQL ist es ein doppelter Schlüssel, in PostgreSQL ein Konflikt – und fügen Sie mit einem Pluszeichen hinzu. Das wird wesentlich besser funktionieren.

Wenn Sie nur wenig Daten haben, macht es wenig Sinn, ClickHouse zu verwenden. Es gibt gewöhnliche Datenbanken, die damit gut umgehen können.

Was kann man in ClickHouse optimieren, um mehr Daten im Cache zu haben?

Stellen wir uns die Situation vor – auf den Servern sind 256 GB RAM vorhanden, im täglichen Betrieb benötigt ClickHouse etwa 60–80 GB, in Spitzenzeiten bis zu 130. Was kann man aktivieren und optimieren, um mehr Daten im Cache zu haben und somit weniger Zugriffe auf die Festplatte zu reduzieren?

In der Regel bewältigt der Page Cache des Betriebssystems diese Aufgabe gut. Wenn Sie einfach den Top-Bereich öffnen und dort cached oder free überprüfen – es steht auch geschrieben, wie viel zwischengespeichert ist – dann kann man sehen, dass der gesamte freie Speicher für den Cache verwendet wird. Und diese Daten werden bei Lesevorgängen nicht von der Festplatte, sondern aus dem RAM gelesen. Dabei kann ich sagen, dass der Cache effizient genutzt wird, weil genau die komprimierten Daten zwischengespeichert werden.

Wenn Sie jedoch einige einfache Anfragen noch weiter beschleunigen möchten, besteht die Möglichkeit, innerhalb von ClickHouse den Cache für unkomprimierte Daten zu aktivieren. Das nennt sich uncompressed cacheIm Konfigurationsdatei config.xml stellen Sie die uncompressed cache size auf den gewünschten Wert ein – ich empfehle nicht mehr als die Hälfte des verfügbaren Arbeitsspeichers, da der Rest für den page cache verwendet wird.

Außerdem gibt es zwei Anfragen auf der Ebene der Einstellungen. Die erste Einstellung ist use uncompressed cache – aktiviert dessen Verwendung. Es wird empfohlen, dies für alle Anfragen zu aktivieren, außer für schwere, die alle Daten lesen und diesen Cache leeren könnten. Die zweite Einstellung ist eine Art Maximierung der Anzahl der Zeilen zur Nutzung des Caches. Sie begrenzt automatisch große Anfragen, sodass sie am Cache vorbeigehen.

Wie kann man die storage_configuration für den Speicher in RAM einstellen?

In der neuen ClickHouse-Dokumentation habe ich einen Abschnitt gefunden, der mit dem data storagezu tun hat. Im Beschreibung gibt es ein Beispiel mit schnellen SSDs.

Es ist interessant, wie man dasselbe mit dem volume hot memory konfigurieren kann. Und noch eine Frage. Wie funktioniert select mit solch einer Datenorganisation? Wird der gesamte Datensatz gelesen oder nur der, der sich auf der Festplatte befindet? Und werden diese Daten im Speicher komprimiert? Und wie funktioniert der prewhere-Bereich mit dieser Datenorganisation?

Diese Einstellung beeinflusst die Speicherung von Datenfragmenten, und deren Format ändert sich nicht.
Lassen Sie uns das genauer betrachten.

Die Speicherung von Daten im Arbeitsspeicher kann konfiguriert werden. Alles, was für die Festplatte konfiguriert wird, ist dessen Pfad. Sie erstellen eine tmpfs-Partition, die unter einem bestimmten Pfad im Dateisystem eingebunden ist. Sie geben diesen Pfad als Speicherort für die heißeste Partition an, dorthin beginnen die Datenfragmente aufzutauchen und geschrieben zu werden, alles läuft reibungslos.

Aber ich empfehle das nicht aufgrund der geringen Zuverlässigkeit, obwohl, wenn Sie mindestens drei Replikate in verschiedenen Rechenzentren haben, es möglich ist. Falls etwas passiert, können die Daten wiederhergestellt werden. Stellen Sie sich vor, der Server wird plötzlich abgeschaltet und wieder eingeschaltet. Die Partition wird erneut eingebunden, aber dort ist Leere. Der ClickHouse-Server erkennt beim Start, dass diese Fragmente fehlen, obwohl sie gemäß den Metadaten von ZooKeeper vorhanden sein sollten. Er sieht sich an, auf welchen Replikaten sie vorhanden sind, fordert sie an und lädt sie herunter. Auf diese Weise werden die Daten wiederhergestellt.

In diesem Sinne unterscheidet sich die Speicherung von Daten im RAM prinzipiell nicht von der Speicherung auf der Festplatte, da die Daten beim Schreiben auf die Festplatte auch zunächst im Page Cache landen und physisch zeitverzögert geschrieben werden. Das hängt von der Art der Einbindung des Dateisystems ab. Aber vorsichtshalber möchte ich sagen, dass ClickHouse kein fsync beim Insert durchführt.

Dabei werden die Daten im RAM genau im gleichen Format gespeichert wie auf der Festplatte. Eine Select-Abfrage wählt genau so die Teile aus, die gelesen werden müssen, wählt die erforderlichen Datenbereiche in Blöcken aus und liest sie. Und Prewhere funktioniert absolut genauso, unabhängig davon, ob die Daten im RAM oder auf der Festplatte waren.

Bis zu welcher Anzahl von eindeutigen Werten ist Low Cardinality effektiv?

Low Cardinality ist clever aufgebaut. Es bildet Datenwörterbücher, aber diese sind lokal. Erstens gibt es für jeden Block eigene Wörterbücher, zweitens können sie sogar innerhalb eines Blocks für jeden Bereich unterschiedlich sein. Wenn die Anzahl der einzigartigen Werte eine Schwelle erreicht – ich glaube, eine Million – wird das Wörterbuch einfach abgelehnt und ein neues erstellt.

Die allgemeine Antwort: Für jeden lokalen Bereich – sagen wir, für jeden Tag – ist Low Cardinality bis zu einer Million einzigartiger Werte effektiv. Danach gibt es einfach einen Fall-Back, bei dem viele verschiedene Wörterbücher genutzt werden, anstatt nur eines. Es wird ungefähr so funktionieren wie eine normale Spalte vom Typ String, vielleicht etwas weniger effizient, aber eine ernsthafte Verschlechterung der Leistung wird nicht eintreten.

Was sind die besten Praktiken für die Volltextsuche in einer Tabelle mit fünf Milliarden Zeilen?

Es gibt verschiedene Antwortmöglichkeiten. Die erste ist zu sagen, dass ClickHouse kein System für Volltextsuchen ist. Dafür gibt es spezielle Systeme wie z.B. Elasticsearch und Sphinx. Trotzdem treffe ich immer häufiger auf Menschen, die sagen, dass sie von Elasticsearch zu ClickHouse wechseln.

Warum passiert das? Sie erklären es damit, dass Elasticsearch bei bestimmten Volumina anfängt, mit der Last nicht mehr zurechtzukommen, insbesondere was den Aufbau von Indizes betrifft. Die Indizes werden zu umfangreich, und wenn man die Daten einfach nach ClickHouse überträgt, ergibt es sich, dass sie in mehrfacher Hinsicht effektiver gespeichert werden. Dabei waren die Suchanfragen oft nicht so, dass man in allen Datenvolumen einen bestimmten Satz unter Berücksichtigung der Morphologie finden musste, sondern ganz andere. Zum Beispiel, um in den Protokollen der letzten Stunden nach einer bestimmten Bytefolge zu suchen.

In diesem Fall erstellen Sie in ClickHouse einen Index, dessen erstes Feld das Datum mit der Zeit ist. Die größte Datenbeschränkung erfolgt genau nach dem Datumsbereich. Innerhalb des gewählten Datumsbereichs kann in der Regel sogar eine Volltextsuche mit der bruteforce-Methode mittels like durchgeführt werden. Der like-Operator in ClickHouse ist der effizienteste like-Operator, den Sie finden können. Wenn Sie einen besseren finden, lassen Sie es mich wissen.

Aber trotzdem ist like ein Full Scan. Und der Full Scan kann nicht nur in Bezug auf die CPU, sondern auch auf die Festplatte langsam sein. Wenn Sie plötzlich ein Terabyte Daten pro Tag haben und Sie an einem Tag nach einem bestimmten Wort suchen, müssen Sie ein Terabyte scannen. Und es wird höchstwahrscheinlich auf herkömmlichen Festplatten gespeichert sein, sodass diese am Ende so stark belastet werden, dass Sie sich nicht mehr per SSH auf diesen Server einloggen können.

In diesem Fall möchte ich noch einen weiteren kleinen Trick anbieten. Er gehört zur Kategorie der experimentellen Techniken – vielleicht funktioniert er, vielleicht nicht. In ClickHouse gibt es Volltextindizes in Form von trigrammatischen Bloom-Filtern. Unsere Kollegen von der Firma Arenadata haben diese Indizes bereits getestet, und oft funktionieren sie genau so, wie es vorgesehen ist.

Um sie richtig zu verwenden, sollten Sie genau verstehen, wie sie funktionieren: Was ist ein trigrammatischer Bloom-Filter und wie wählt man seine Größe? Ich kann sagen, dass sie bei Anfragen nach seltenen Phrasen oder Substrings, die selten in den Daten vorkommen, helfen werden. In diesem Fall werden die Indizes Teilbereiche auswählen, und es werden weniger Daten gelesen.

Kürzlich wurden in ClickHouse noch fortschrittlichere Funktionen für die Volltextsuche eingeführt. Erstens die Suche nach mehreren Substrings auf einmal, einschließlich Varianten mit Berücksichtigung der Groß- und Kleinschreibung, ohne Berücksichtigung der Groß- und Kleinschreibung, mit Unterstützung für UTF-8 oder nur für ASCII. Wählen Sie die effizienteste, die Sie benötigen.

Es gibt auch die Möglichkeit, mehrere reguläre Ausdrücke in einem Durchgang zu suchen. Sie müssen nicht schreiben X like ein Substring oder X like ein anderer Substring. Schreiben Sie es einfach, und alles wird so effizient wie möglich ausgeführt.

Drittens gibt es jetzt eine ungefähre Suche nach regulären Ausdrücken und eine ungefähre Suche nach Substrings. Wenn jemand ein Wort mit einem Tippfehler geschrieben hat, wird es nach der maximalen Übereinstimmung gesucht.

Wie kann man den Zugang zu ClickHouse für eine große Anzahl von Benutzern besser organisieren?

Erzählen Sie, wie Sie den Zugriff für eine große Anzahl von Nutzern und Analysten am besten organisieren können. Wie bilden Sie eine Warteschlange, priorisieren die maximal gleichzeitigen Abfragen und welche Werkzeuge verwenden Sie dafür?

Wenn der Cluster groß genug ist, wäre es eine gute Lösung, zwei weitere Server einzurichten, die als Einstiegspunkt für die Analysten dienen. Das bedeutet, dass Analysten nicht auf bestimmte Shards des Clusters zugreifen dürfen, sondern einfach zwei leere Server ohne Daten erstellt werden, auf denen die Zugriffsrechte eingerichtet werden. Die Benutzereinstellungen werden bei verteilten Abfragen an die entfernten Server übertragen. Das heißt, Sie konfigurieren alles auf diesen beiden Servern, und die Einstellungen wirken sich auf den gesamten Cluster aus.

Grundsätzlich sind diese Server ohne Daten, aber der Speicherbedarf ist sehr wichtig für die Ausführung von Abfragen. Die Festplatte kann ebenfalls für temporäre Daten verwendet werden, wenn externe Aggregation oder externe Sortierung aktiviert ist.

Es ist wichtig, die Einstellungen zu überprüfen, die mit allen möglichen Limits verbunden sind. Wenn ich jetzt als Analyst auf den Cluster «Yandex.Metrics» zugreife und eine Abfrage stelle, select count from hits, werde ich sofort eine Ausnahme erhalten, dass ich die Abfrage nicht durchführen kann. Die maximale Anzahl an Zeilen, die ich scannen darf, beträgt hundert Milliarden, während es insgesamt im Cluster fünfzig Billionen in einer Tabelle gibt. Das ist die erste Einschränkung.

Angenommen, ich entferne die Einschränkung für die Anzahl der Zeilen und führe die Abfrage erneut aus. Dann sehe ich die folgende Ausnahme - die Einstellung force index by dateist aktiviert. Ich kann die Abfrage nicht ausführen, wenn ich keinen Datumsbereich angegeben habe. Man sollte nicht davon ausgehen, dass die Analysten ihn manuell angeben werden. Ein typischer Fall ist, dass ein Datumsbereich geschrieben wird, wo das Ereignisdatum zwischen einer Woche liegt. Und dann hat man einfach die Klammer nicht richtig gesetzt, und anstelle von und получилось или — или URL match. Wenn keine Einschränkungen bestehen, wird es die URL-Spalte scannen und einfach Tonnen von Ressourcen verschwenden.

Darüber hinaus gibt es in ClickHouse zwei Prioritätseinstellungen. Leider sind sie sehr primitiv. Eine davon heißt einfach priority. Wenn die Priorität ≠ 0 ist und Anfragen mit einer bestimmten Priorität ausgeführt werden, aber gleichzeitig eine Anfrage mit einer Priorität niedrigeren Wertes, was bedeutet, dass es sich um eine höhere Priorität handelt, verarbeitet wird, wird die Anfrage mit dem höheren Prioritätswert, was eine niedrigere Priorität bedeutet, einfach angehalten und während dieser Zeit überhaupt nicht ausgeführt.

Dies ist eine sehr grobe Einstellung und eignet sich nicht für Szenarien mit ständiger Last auf dem Cluster. Aber wenn Sie kurzfristige, wichtige Impulsanfragen haben und das Cluster hauptsächlich im Leerlauf ist, ist diese Einstellung geeignet.

Die nächste Prioritätseinstellung heißt OS-Thread-Priorität. Sie setzt einfach für alle Threads, die Anfragen bearbeiten, den Wert nice für den Linux-Scheduler. Sie funktioniert nicht besonders gut, aber immerhin funktioniert sie. Wenn der minimale Wert nice gesetzt wird - er ist am höchsten in der Größe und bedeutet die niedrigste Priorität - und für Anfragen mit hoher Priorität -19 gesetzt wird, verbraucht die CPU niedrigpriorisierte Anfragen etwa viermal weniger als hochpriorisierte.

Außerdem muss die maximale Ausführungszeit einer Anfrage eingestellt werden - sagen wir, fünf Minuten. Die minimale Ausführungsgeschwindigkeit einer Anfrage - das ist das Wichtigste. Diese Einstellung gibt es schon lange, und sie ist notwendig, um nicht nur zu behaupten, dass ClickHouse nicht bremst, sondern um dies auch zu erzwingen.

Stellen Sie sich vor, Sie stellen ein: Wenn eine Anfrage weniger als eine Million Zeilen pro Sekunde verarbeitet - das geht nicht. Das beschämt unseren guten Namen, unsere gute Datenbank. Lassen Sie uns das einfach verbieten. Es gibt tatsächlich zwei Einstellungen. Eine heißt min execution speed – in Zeilen pro Sekunde, und die zweite heißt timeout before checking min execution speed - standardmäßig fünfzehn Sekunden. Das heißt, fünfzehn Sekunden sind in Ordnung, und danach, wenn es langsam ist, einfach eine Ausnahme auslösen – die Anfrage abbrechen.

Außerdem müssen Quoten eingestellt werden. In ClickHouse gibt es eine eingebaute Quotenfunktion, die den Ressourcenverbrauch zählt. Leider nicht für physische Ressourcen wie CPU, Festplatten, sondern für logische - die Anzahl der verarbeiteten Anfragen, Zeilen und gelesenem Byte. Man kann beispielsweise maximal einhundert Anfragen in fünf Minuten und tausend Anfragen pro Stunde einstellen.

Warum ist das wichtig? Weil ein Teil der Analyseanfragen manuell direkt aus dem ClickHouse-Client ausgeführt wird. Und alles wird gut sein. Aber wenn Sie in Ihrem Unternehmen fortgeschrittene Analysten haben, werden sie ein Skript schreiben, und im Skript könnte ein Fehler sein. Und dieser Fehler könnte dazu führen, dass die Anfrage in einer Endlosschleife ausgeführt wird. Davor muss man sich schützen.

Kann man die Ergebnisse einer Anfrage an zehn Kunden weitergeben?

Wir haben mehrere Benutzer, die gerne gleichzeitig mit sehr großen Anfragen kommen. Die Anfrage ist groß und wird insgesamt schnell ausgeführt, aber aufgrund der vielen gleichzeitigen Anfragen wird es sehr schmerzhaft. Kann eine Anfrage, die zehnmal hintereinander gekommen ist, einmal ausgeführt werden, und das Ergebnis zehn Kunden übergeben werden?

Das Problem ist, dass wir keine Ergebnisse aus dem Cache oder dem Cache für Zwischendaten haben. Es gibt einen Page-Cache des Betriebssystems, der es ermöglicht, die Daten nicht erneut von der Festplatte zu lesen, aber leider müssen die Daten trotzdem erneut entpackt, deserialisiert und verarbeitet werden.

Ich würde gerne irgendwie vermeiden, entweder indem ich die Zwischendaten cachi oder ähnliche Anfragen in eine Warteschlange einordne und die Ergebniskasse hinzufüge. Momentan haben wir einen Pull-Request in Entwicklung, der einen Anfragen-Cache hinzufügt, jedoch nur für Unterabfragen in den Abschnitten 'in' und 'join' – also ist die Lösung unvollständig.

Dennoch haben wir auch eine solche Situation. Besonders das klassische Beispiel sind Anfragen mit Pagination. Es gibt einen Bericht, der mehrere Seiten hat, und es läuft eine Anfrage mit limit 10. Dann dasselbe, aber limit 10,10. Dann die nächste Seite. Und es stellt sich die Frage, warum wir das alles jedes Mal berechnen? Aber derzeit gibt es keine Lösung, und das kann man nicht vermeiden.

Es gibt eine alternative Lösung, die als Sidecar neben ClickHouse installiert wird – ClickHouse Proxy.

Kirill Shvakov: Im ClickHouse Proxy gibt es einen integrierten Ratenlimitierer und einen integrierten Ergebniscache. Dort wurden viele Einstellungen vorgenommen, weil eine ähnliche Aufgabe gelöst wurde. Der Proxy ermöglicht es, Anfragen zu limitieren, sie in einer Warteschlange anzuordnen und einzustellen, wie lange der Anfragen-Cache hält. Wenn die Anfragen wirklich identisch waren, wird der Proxy sie mehrere Male zurückgeben, während er nur einmal zum ClickHouse geht.

Nginx hat auch einen Cache in der kostenlosen Version, und das wird ebenfalls funktionieren. Nginx hat sogar Einstellungen, dass, wenn Anfragen gleichzeitig eintreffen, er andere verlangsamt, bis eine ausgeführt ist. Aber die Konfiguration in ClickHouse Proxy ist viel besser gemacht. Sie wurde speziell für ClickHouse und diese Anfragen konzipiert, daher passt sie besser. Und die Installation ist einfach.

Wie geht man mit asynchronen Operationen und materialisierten Sichten um?

Es gibt das Problem, dass Operationen mit dem Replacing-Engine asynchron sind – zuerst werden die Daten geschrieben, dann erfolgt deren Zusammenführung. Wenn unter der Tabelle eine materialisierte Tabelle mit Aggregaten lebt, werden Duplikate dort geschrieben. Und wenn keine komplizierte Logik vorhanden ist, werden die Daten dupliziert. Was kann man dagegen tun?

Es gibt eine offensichtliche Lösung – einen Trigger für eine bestimmte Klasse von Materialized Views bei der asynchronen Zusammenführungsoperation zu implementieren. Gibt es irgendwelche "silbernen Kugeln", Pläne zur Implementierung solcher Funktionen?

Man sollte sich mit der Funktionsweise der Deduplication beschäftigen. Das, was ich jetzt erläutern werde, betrifft die Frage nicht, aber es ist sicher gut, daran zu denken.

Beim Einfügen in eine replizierte Tabelle gibt es eine vollständige Deduplication der eingefügten Blöcke. Wenn Sie denselben Block erneut eingefügt haben, der die gleiche Anzahl der gleichen Zeilen in der gleichen Reihenfolge enthält, werden die Daten dedupliziert. Sie erhalten ein "Ok" als Antwort auf den Insert, aber tatsächlich wird nur ein Block von Daten aufgezeichnet, und er wird nicht dupliziert.

Das ist wichtig für die Klarheit. Wenn Sie während des Einfügens ein "Ok" erhalten haben, bedeutet das, Ihre Daten wurden eingefügt. Wenn Sie einen Fehler von ClickHouse erhalten haben, wurden sie nicht eingefügt und das Einfügen muss wiederholt werden. Aber wenn die Verbindung während des Einfügens unterbrochen wurde, wissen Sie nicht, ob die Daten eingefügt wurden oder nicht. Die einzige Möglichkeit ist, das Einfügen erneut zu wiederholen. Wenn die Daten tatsächlich eingefügt wurden und Sie sie erneut eingefügt haben, gibt es eine Deduplication der Blöcke. Diese ist notwendig, um Duplikate zu vermeiden.

Es ist auch wichtig, wie es für materialisierte Sichten funktioniert. Wenn die Daten beim Einfügen in die Haupttabelle dedupliziert wurden, werden sie auch nicht in die materialisierte Sicht gelangen.

Jetzt zur Frage. Sie haben eine kompliziertere Situation, da Sie Duplikate einzelner Zeilen aufzeichnen. Das bedeutet, dass nicht die gesamte Charge dupliziert wird, sondern spezifische Zeilen, die im Hintergrund zusammengeführt werden. In der Tat werden die Daten in der Haupttabelle zusammengeführt, und in die materialisierte Sicht gehen die nicht zusammengeführten Daten, und bei Mergen passiert mit den materialisierten Sichten nichts. Denn die materialisierte Sicht ist nichts anderes als ein Trigger für Inserts. Bei anderen Vorgängen passiert nichts Zusätzliches mit ihr.

Ich kann hier leider nichts Positives beitragen. Man muss nur eine spezifische Lösung für diesen Fall suchen. Zum Beispiel, kann man auch in der materialisierten Sicht einen Replacing durchführen, und möglicherweise wird die Methode zur Deduplication auch hier funktionieren. Aber leider nicht immer. Wenn sie aggregierend ist, wird es nicht funktionieren.

Kirill Shvakov: Auch bei uns gab es mal das Problem des 'Konstrukteurens'. Es gab Anzeigen und bestimmte Daten, die wir in Echtzeit zeigen konnten – das sind einfach nur Anzeigen. Diese duplizieren sich selten, aber wenn das passiert, führen wir sie trotzdem später zusammen. Und es gab Dinge, die man nicht duplizieren konnte – Klicks und all diese Geschichte. Aber man wollte sie auch fast sofort zeigen.

Wie wurden die materialisierten Sichten erstellt? Es gab Sichten, in die direkt geschrieben wird – es erfolgt eine Aufnahme in die Rohdaten, und es wird in Views geschrieben. Dort sind die Daten zu einem bestimmten Zeitpunkt nicht ganz korrekt, sie werden dupliziert und so weiter. Und es gibt einen zweiten Teil der Tabelle, der genau wie die materialisierten Sichten aussieht, also strukturell genau gleich ist. In regelmäßigen Abständen zählen wir die Daten neu, erfassen die Daten ohne Duplikate und schreiben sie in diese Tabellen.

Wir gingen über die API – in ClickHouse wird es so nicht funktionieren. Die API schaut: Wenn ich ein Datum der letzten Hinzufügung in die Tabelle habe, wo garantiert bereits korrekte, berechnete Daten sind, und sie führt eine Abfrage an einer Tabelle und einer anderen Tabelle durch. Aus einer Abfrage wählt sie bis zu einem bestimmten Zeitpunkt aus, und aus der anderen ergänzt sie, was noch nicht berechnet wurde. Und das funktioniert, aber nicht mit den Mitteln eines einzelnen ClickHouse.

Wenn Sie ein API haben - für Analysten, für Benutzer - dann ist das im Prinzip eine Option. Sie zählen immer nach, Sie überprüfen immer erneut. Das kann einmal täglich oder zu einer anderen Zeit erfolgen. Sie wählen selbst den Bereich, der für Sie nicht notwendig und nicht kritisch ist.

ClickHouse hat viele Protokolle. Wie kann ich alles sehen, was in diesem Moment mit dem Server passiert?

In ClickHouse gibt es eine sehr große Menge an verschiedenen Protokollen, und diese Zahl steigt. In den neuen Versionen sind einige davon sogar standardmäßig aktiviert, in den älteren Versionen müssen sie beim Upgrade aktiviert werden. Dennoch werden es immer mehr. Ich würde gerne sehen, was gerade mit meinem Server passiert, vielleicht auf einem konsolidierten Dashboard.

Haben Sie in Ihrem Team ClickHouse oder in den Teams Ihrer Freunde, die eine Funktionalität für vorgefertigte Dashboards unterstützen, die diese Protokolle in Form eines fertigen Produkts anzeigen? Im Endeffekt ist es toll, Protokolle in ClickHouse einfach so anzuschauen. Aber es wäre wirklich großartig, wenn es bereits in Form eines Dashboards vorbereitet wäre. Das würde mir sehr gefallen.

Es gibt Dashboards, aber sie sind nicht standardisiert. In unserem Unternehmen nutzen etwa 60 Teams ClickHouse, und das Seltsame ist, dass viele von ihnen Dashboards selbst erstellt haben, die sich etwas unterscheiden. Einige Teams verwenden eine interne Installation von „Yandex.Cloud“. Dort gibt es einige fertige Berichte, obwohl nicht alle notwendig sind. Andere haben ihre eigenen.

Meine Kollegen von „Metrik“ haben ihr eigenes Dashboard in Grafana, und ich habe meines für ihren Cluster. Dort sehe ich Dinge wie Cache-Hits für den Caching-Service. Und es ist sogar noch komplizierter, weil wir verschiedene Tools verwenden. Mein Dashboard habe ich mit einem sehr alten Tool erstellt, das Graphite-web heißt. Es ist überhaupt nicht schön. Und ich benutze es bis heute, obwohl Grafana wahrscheinlich bequemer und schöner wäre.

Die grundlegenden Elemente im Dashboard sind identisch. Es handelt sich um systemische Metriken für den Cluster: CPU, Speicher, Festplatte, Netzwerk. Andere sind die Anzahl gleichzeitiger Anfragen, die Anzahl gleichzeitiger Zusammenführungen, die Anzahl der Anfragen pro Sekunde, die maximale Anzahl von Stücken für die Partitionen der MergeTree-Tabellen, die Replikationsverzögerung, die Größe der Replikationswarteschlange, die Anzahl der pro Sekunde eingefügten Zeilen, die Anzahl der pro Sekunde eingefügten Blöcke. Das sind alles Metriken, die nicht aus Logs, sondern aus Metriken stammen.

Wladimir Kolobajew: Alexej, ich möchte etwas korrigieren. Es gibt Grafana. Grafana hat eine Datenquelle, die ClickHouse ist. Das heißt, ich kann aus Grafana direkt Anfragen an ClickHouse stellen. In ClickHouse gibt es eine Tabelle mit Logs, die bei allen gleich ist. Ich möchte in Grafana auf diese Logtabelle zugreifen und die Anfragen sehen, die mein Server sendet. Es wäre großartig, ein solches Dashboard zu haben.

Ich habe es selbst zusammengestellt. Aber ich habe eine Frage – wenn alles standardisiert ist und Grafana von allen verwendet wird, warum gibt es im "Yandex" kein offizielles Dashboard?

Kirill Shvakov: Tatsächlich wird die Datenquelle, die zu ClickHouse gehört, jetzt von Altinity unterstützt. Und ich möchte nur einen Hinweis geben, wo man nachfragen und wen man ansprechen kann. Man kann mit ihnen sprechen, denn "Yandex" macht schließlich ClickHouse und nicht die Geschichte darum. Altinity ist das Hauptunternehmen, das ClickHouse jetzt voranbringt. Sie werden es nicht aufgeben, sondern unterstützen. Denn um ein Dashboard auf der Grafana-Website hochzuladen, muss man sich nur registrieren und es hochladen – da gibt es keine großen Probleme.

Alexej Milovidov: Im letzten Jahr wurden viele Funktionen zur Profilerstellung von Anfragen in ClickHouse hinzugefügt. Es gibt Metriken für jede Anfrage zur Ressourcennutzung. Und ganz neu wurde ein noch niedrigerer Profiler für Anfragen hinzugefügt, um zu sehen, wo jede Millisekunde der Anfrage verbracht wird. Aber um diese Funktionalität nutzen zu können, muss ich den Konsolenclient öffnen und die Anfrage eingeben, die ich ständig vergesse. Ich habe sie irgendwo gespeichert und vergesse ständig, wo genau.

Ich wünschte mir ein Tool, das einfach feststellt, welche schwerwiegenden Anfragen es gibt, gruppiert nach Anfragetypen. Ich klicke auf eine davon, und man sagt mir, dass sie schwerwiegende Auswirkungen hat. Momentan gibt es eine solche Lösung nicht. Es ist wirklich seltsam, dass, wenn ich Leute frage: „Gibt es fertige Dashboards für Grafana?“, ich sage: „Geht auf die Grafana-Website, dort gibt es die Community-Sektion 'Dashboards', und da gibt es ein Dashboard von Dima, ein Dashboard von Kostya. Was das ist, weiß ich nicht, ich habe es selbst nicht genutzt.“

Wie kann ich die Merges beeinflussen, damit der Server nicht in OOM abstürzt?

Ich habe eine Tabelle, die nur eine Partition hat, sie ist ein ReplacingMergeTree. Ich schreibe seit vier Jahren Daten hinein. Ich musste ein Alter durchführen und einige Daten löschen.

Ich habe das getan, und während der Verarbeitung dieser Anfrage wurde der gesamte Speicher auf allen Servern des Clusters verbraucht, und alle Server des Clusters sind gemeinsam in OOM gefallen. Dann sind sie alle zusammen wieder hochgefahren, haben angefangen, den Merge dieser gleichen Operation, dieses Datenblocks, durchzuführen und sind erneut in OOM gefallen. Dann sind sie wieder hochgefahren und wieder abgestürzt. Und das hörte nicht auf.

Es stellte sich heraus, dass es tatsächlich ein Bug war, den die Leute behoben haben. Das ist großartig, vielen Dank. Aber der Nachgeschmack bleibt. Und jetzt, wenn ich daran denke, einen Merge in der Tabelle durchzuführen, habe ich die Frage – warum kann ich nicht irgendwie auf diese Merges Einfluss nehmen? Zum Beispiel, sie in Bezug auf den benötigten Arbeitsspeicher zu begrenzen, oder generell in Bezug auf die Anzahl, die diese spezielle Tabelle verarbeiten wird.

Ich habe eine Tabelle, die 'Metriken' heißt, bearbeite sie bitte in zwei Streams. Es müssen nicht zehn oder fünf Merges parallel durchgeführt werden, mache es in zwei. Ich denke, dass zwei genug Speicher für mich haben, während ich möglicherweise nicht genug für zehn habe, um sie zu verarbeiten. Warum bleibt die Angst? Weil die Tabelle wächst, und irgendwann werde ich in eine Situation kommen, in der es nicht aufgrund eines Bugs ist, sondern weil die Daten in so großer Menge wechseln, dass der Speicher auf dem Server nicht ausreichen wird. Und dann wird der Server beim Merge in OOM fallen. Die Mutation kann ich zurücknehmen, aber die Merges nicht.

Wissen Sie, bei Merges wird der Server nicht in OOM fallen, denn bei einem Merge wird nur eine kleine Datenmenge an RAM benötigt. Daher wird alles gut sein, unabhängig vom Datenvolumen.

Wladimir Kolobajew: Das ist gut. Hier gibt es jedoch einen Punkt: Nachdem ich den Bugfix gemacht habe, habe ich mir die neue Version heruntergeladen und bei einer anderen, kleineren Tabelle, bei der es viele Partitionen gibt, eine ähnliche Operation durchgeführt. Während des Merges wurden auf dem Server etwa 100 GB RAM verbraucht. Ich hatte 150 belegt, 100 verbraucht und hatte daher noch 50 GB frei, somit bin ich nicht in OOM gefallen.

Was schützt mich derzeit davor, in OOM zu fallen, wenn tatsächlich 100 GB RAM benötigt werden? Wie geht man mit der Situation um, wenn plötzlich der RAM während der Merges aufgebraucht ist?

Alexej Milovidov: Es gibt ein Problem, dass der RAM-Verbrauch speziell bei Merges nicht begrenzt ist. Ein weiteres Problem ist, dass, wenn ein Merge angesetzt wird, er durchgeführt werden muss, da er im Replikationslog aufgezeichnet ist. Das Replikationslog sind die Maßnahmen, die erforderlich sind, um die Replikation in einen konsistenten Zustand zu bringen. Wenn keine manuellen Eingriffe vorgenommen werden, die dieses Replikationslog zurücksetzen, muss der Merge auf die eine oder andere Weise durchgeführt werden.

Natürlich wäre es nicht schlecht, eine Einschränkung beim RAM zu haben, die "für alle Fälle" gerade vor OOM schützt. Es wird dem Merge nicht helfen, der wird wieder beginnen, einen bestimmten Schwellenwert erreichen, eine Ausnahme erzeugen und dann wieder anfangen – nichts Gutes wird dabei herauskommen. Aber im Prinzip wäre eine solche Einschränkung nützlich.

Wie wird die Entwicklung des Golang-Treibers für ClickHouse ablaufen?

Der Golang-Treiber, den Kirill Shvakov geschrieben hat, wird jetzt offiziell, soweit ich weiß, vom ClickHouse-Team unterstützt. Er ist im ClickHouse-Repository, er ist jetzt groß und echt.

Eine kleine Anmerkung. Es gibt ein wunderbares und von allen geliebtes Speicherformat unendlicher Ordnung — Vertica. Auch sie haben ihren eigenen offiziellen Python-Treiber, der von den Entwicklern von Vertica unterstützt wird. Es gab mehrmals Situationen, in denen die Versionen des Speichers und des Treibers stark auseinanderliefen, und der Treiber irgendwann nicht mehr funktionierte. Ein weiterer Punkt ist, dass die Unterstützung für diesen offiziellen Treiber, meiner Meinung nach, im System "Nippel" läuft — du schreibst ihnen ein Issue, und es hängt für immer.

Ich habe zwei Fragen. Der Golang-Treiber von Kirill ist momentan die fast standardmäßige Methode, um aus Golang mit ClickHouse zu kommunizieren. Es sei denn, jemand kommuniziert immer noch über das HTTP-Interface, weil er es so mag. Wie wird die Entwicklung dieses Treibers vorangehen? Wird sie mit den Breaking Changes im Speicher selbst synchronisiert? Und wie läuft die Bearbeitung von Issues ab?

Kirill Shvakov: Erstens — wie alles bürokratisch organisiert ist. Dieser Punkt wurde nicht besprochen, daher kann ich darauf nicht antworten.

Um die Frage zu den Issues zu beantworten, braucht es eine kleine Geschichte des Treibers. Ich arbeitete in einem Unternehmen, das viele Daten hatte. Es war eine Werbeplattform mit einer riesigen Anzahl von Ereignissen, die irgendwo gespeichert werden mussten. Irgendwann erschien ClickHouse. Wir haben die Daten dort hineingeleitet, und anfangs lief alles gut, aber dann fiel ClickHouse aus. Zu diesem Zeitpunkt entschieden wir, dass wir es nicht mehr brauchen.

Ein Jahr später kehrten wir zur Idee zurück, ClickHouse zu nutzen, und wir mussten irgendwie Daten dorthin schreiben. Die Rahmenbedingungen waren so — die Hardware war sehr schwach, die Ressourcen waren begrenzt. Aber wir haben immer so gearbeitet, und deshalb schauten wir uns in Richtung des nativen Protokolls um.

Da wir in Go arbeiteten, war klar, dass wir einen Treiber in Go benötigten. Ich widmete dem Projekt praktisch Vollzeit — das war meine Arbeitsaufgabe. Bis zu einem bestimmten Punkt haben wir ihn fertiggestellt, und im Grunde hatte niemand damit gerechnet, dass jemand außer uns ihn verwenden würde. Dann kam CloudFlare mit genau dem gleichen Problem, und eine Zeit lang arbeiteten wir sehr gut zusammen, weil sie die gleichen Herausforderungen hatten. Dabei haben wir sowohl im ClickHouse selbst als auch im Treiber gearbeitet.

Irgendwann habe ich einfach aufgehört, mich darum zu kümmern, da sich meine Aktivitäten in Bezug auf ClickHouse und die Arbeit ein wenig geändert haben. Deshalb werden die Issues nicht geschlossen. Gelegentlich committen Leute in das Repository, die selbst etwas benötigen. Dann schaue ich mir den Pull Request an und manchmal ändere ich sogar selbst etwas, aber das passiert selten.

Ich möchte zum Treiber zurückkehren. Vor ein paar Jahren, als das Ganze anfing, war ClickHouse auch anders und hatte andere Möglichkeiten. Jetzt gibt es ein Verständnis dafür, wie man den Treiber umgestalten kann, damit es gut funktioniert. Sollte das passieren, wird Version 2 in jedem Fall inkompatibel sein aufgrund der angesammelten Hacks.

Wie man das organisiert, weiß ich nicht. Ich selbst habe nicht so viel Zeit. Wenn einige Leute den Treiber weiterentwickeln, kann ich ihnen helfen und erklären, was zu tun ist. Aber eine aktive Beteiligung von Yandex an der Entwicklung des Projekts wurde bisher noch nicht besprochen.

Alexej Milovidov: Tatsächlich gibt es bisher keine Bürokratie bezüglich dieser Treiber. Das einzige ist, dass sie in eine offizielle Organisation überführt wurden, das heißt, dieser Treiber ist als offizielle Standardlösung für Go anerkannt. Es gibt einige andere Treiber, aber die kommen separat.

Intern haben wir keine Entwicklung für diese Treiber. Die Frage ist, ob wir eine separate Person einstellen können, nicht speziell für diesen Treiber, sondern für die Entwicklung aller Community-Treiber, oder ob wir jemanden von außen finden können.

Das externe Wörterbuch wird nach einem Neustart mit aktivierter lazy_load-Einstellung nicht geladen. Was kann man tun?

Wir haben die lazy_load-Einstellung aktiviert, und nach dem Neustart des Servers wird das Wörterbuch nicht automatisch geladen. Es wird nur geladen, wenn ein Benutzer auf dieses Wörterbuch zugreift. Und beim ersten Zugriff gibt es einen Fehler. Kann man mit ClickHouse Wörterbücher automatisch laden, oder müssen wir immer selbst deren Bereitschaft überwachen, damit die Benutzer keine Fehler erhalten?

Es könnte sein, dass wir eine alte Version von ClickHouse haben, daher wurde das Wörterbuch nicht automatisch geladen. Ist das möglich?

Zunächst können Wörterbücher mit Hilfe des Befehls system reload dictionarieserzwingend geladen werden. Zweitens, bezüglich des Fehlers — wenn das Wörterbuch bereits geladen ist, funktionieren die Abfragen mit den Daten, die geladen wurden. Wenn das Wörterbuch noch nicht geladen war, wird es genau während der Abfrage geladen.

Für schwere Wörterbücher ist das nicht sehr praktisch. Zum Beispiel, wenn man eine Million Zeilen aus MySQL ziehen muss. Einige machen einen einfachen Select, aber dieser Select wird auf genau diese Million Zeilen warten. Hier gibt es zwei Lösungen. Erste — lazy_load deaktivieren. Zweite — wenn der Server hochfährt, bevor wir ihn belasten, machen wir system reload dictionary oder führen einfach die Abfrage aus, die das Wörterbuch verwendet. Dann wird das Wörterbuch geladen. Man muss selbst die Verfügbarkeit der Wörterbücher mit aktivierter lazy_load-Einstellung überwachen, da ClickHouse diese nicht automatisch einbindet.

Auf die letzte Frage ist die Antwort — entweder ist die Version alt, oder man muss debuggen.

Wie geht man damit um, dass system reload dictionaries keinen der vielen Wörterbücher lädt, wenn eines von ihnen aufgrund eines Fehlers ausfällt?

Es gibt noch eine Frage zu system reload dictionaries. Wir haben zwei Wörterbücher — eines wird nicht geladen, das andere wird geladen. In diesem Fall lädt system reload dictionaries kein Wörterbuch, und man muss spezifisch eines nach seinem Namen mit system reload dictionary anladen. Hat das auch mit der Version von ClickHouse zu tun?

Ich möchte Ihnen eine gute Nachricht überbringen. Dieses Verhalten hat sich geändert. Das bedeutet, wenn Sie ClickHouse aktualisieren, wird es sich auch ändern. Wenn Ihnen das aktuelle Verhalten nicht gefällt, system reload dictionaries, aktualisieren Sie und hoffen wir, dass es sich zum Besseren ändern wird.

Gibt es eine Möglichkeit, die Anmeldeinformationen in der ClickHouse-Konfiguration zu konfigurieren, ohne sie bei Fehlern anzuzeigen?

Die nächste Frage betrifft Fehler, die mit dem Wörterbuch verbunden sind, nämlich die Verbindungsdetails. Wir haben die Verbindungsdetails in der ClickHouse-Konfiguration für das Wörterbuch festgelegt, und im Fehlerfall erhalten wir diese Details und das Passwort als Antwort.

Wir haben diesen Fehler behoben, indem wir die Details in die ODBC-Treiberkonfiguration ausgelagert haben. Gibt es einen Weg, die Details in der ClickHouse-Konfiguration zu konfigurieren, ohne diese Details bei Fehlern offenzulegen?

Hier ist die echte Lösung — diese Anmeldedaten in der odbc.ini anzugeben, und in ClickHouse nur den ODBC-Datenquellennamen anzugeben. Für andere Datenquellen wird dies nicht möglich sein — weder für das Wörterbuch mit MySQL noch für andere sollten Sie das Passwort bei einer Fehlermeldung sehen. Für ODBC werde ich ebenfalls nachsehen — falls es so etwas gibt, muss es einfach entfernt werden.

Bonus: Hintergründe für Zoom aus den Besprechungen

Durch Klicken auf das Bild öffnet sich für die hartnäckigsten Leser ein Bonushintergrund von unseren Treffen. Wir löschen das Feuer zusammen mit den Avito-Technologie-Maskottchen, beraten uns mit Kollegen aus dem Raum des Systemadministrators oder dem Old-School-Computerclub und halten Daily unter der Brücke vor der Graffiti-Wand.

ClickHouse für fortgeschrittene Benutzer in Fragen und Antworten

Quelle: habr.com

Zuverlässiges Hosting für Websites mit DDoS-Schutz kaufen, VPS VDS Server 🔥 Zuverlässiges Hosting für Websites mit DDoS-Schutz kaufen, VPS VDS Server - ProHoster