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 Herausforderungen wir dabei haben.
Auf Grundlage des Treffens haben wir einen Artikel mit Antworten von Experten auf unsere und Zuschauerfragen zu Backups, Datenresharding, externen Dictionaries, dem Golang-Treiber und der Aktualisierung von ClickHouse-Versionen zusammengestellt. Dieser kann für Entwickler nützlich sein, die bereits aktiv mit dem DBMS von Yandex arbeiten und sich für dessen gegenwärtige und zukünftige Entwicklungen interessieren. Standardmäßig stammen die Antworten von Alexey Milovidov, sofern nicht anders angegeben.
Vorsicht, unter dem Cut gibt es viel Text. Wir hoffen, dass der Inhalt mit den Fragen Ihnen hilft, sich zu orientieren.

Inhalt
Wenn Sie den Text nicht lesen möchten, können Sie sich die Aufzeichnung der Zusammenkünfte ansehen . Die Timecodes befinden sich im ersten Kommentar unter dem Video.
ClickHouse wird ständig aktualisiert, aber unsere Daten nicht. Was können wir dagegen tun?
ClickHouse wird ständig aktualisiert, aber unsere Daten, die zuletzt optimiert verarbeitet wurden, werden nicht aktualisiert und liegen in einer Sicherungskopie.
Angenommen, wir haben ein Problem und die Daten gingen verloren. Wir möchten eine Wiederherstellung durchführen und stellen fest, dass alte Partitionen, die auf den Backup-Servern gespeichert sind, stark von der aktuell verwendeten Version von ClickHouse abweichen. Was ist in einer solchen Situation zu tun, und ist das möglich?
Es ist ausgeschlossen, dass Sie Daten aus einem Backup im alten Format wiederhergestellt haben und diese in der neuen Version nicht erkannt werden. Wir gewährleisten, dass das Datenformat in ClickHouse stets abwärtskompatibel bleibt. Dies ist weitaus wichtiger, als die Abwärtskompatibilität in Bezug auf die Funktionalität, insbesondere wenn sich das Verhalten einer selten verwendeten Funktion geändert hat. Die Daten, die auf der Festplatte gespeichert sind, müssen von jeder neuen Version von ClickHouse lesbar sein. Das ist ein Grundsatz.
Was sind die besten derzeit verfügbaren Praktiken für das Backup von Daten aus ClickHouse?
Wie macht man Backups unter Berücksichtigung, dass wir die Operationen 'optimize final' haben, eine riesige Datenbank auf Terabyte und Daten, die sich zum Beispiel in den letzten drei Tagen aktualisiert haben, und danach keine weiteren Verfahren damit erfolgen?
Wir könnten eine eigene Lösung basteln und uns damit auseinandersetzen: Diese Backups so und so sammeln. Vielleicht braucht man gar nichts basteln, und das Fahrrad wurde schon längst erfunden?
Zunächst zu den besten Praktiken. Meine Kollegen empfehlen immer, in Antworten auf Fragen zu Backups auf den Dienst 'Yandex.Cloud' hinzuweisen, wo dieses Problem bereits gelöst ist. Nutzen Sie diesen Dienst, wenn Sie die Möglichkeit dazu haben.
Es gibt keine vollständige Lösung, die zu 100 Prozent in ClickHouse integriert ist. Es gibt einige Vorlagen, die verwendet werden können. Um eine komplette Lösung zu erhalten, müssen Sie entweder etwas manuell arbeiten oder Wrapper in Form von Skripten erstellen.
Ich beginne mit den einfachsten Lösungen und endete mit den komplexesten, je nach Datenvolumen und Clustergröße. Je größer der Cluster, desto komplizierter wird die Lösung.
Wenn die Tabelle nur einige Gigabyte Daten umfasst, kann das Backup folgendermaßen erfolgen:
- Speichern Sie die Tabellendefinition, also die Metadaten — show create table.
- Erstellen Sie ein Dump mit dem ClickHouse-Client — 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, wird das Backup mehr Zeit und Platz benötigen. Dies wird als logisches Backup bezeichnet und ist nicht an das Datenformat von ClickHouse gebunden. Wenn es existiert, können Sie im Extremfall das Backup nehmen und in MySQL zur Wiederherstellung laden.
Für fortgeschrittene Anwendungsfälle bietet ClickHouse die Möglichkeit, Snapshots von Partitionen im lokalen Dateisystem zu erstellen. Diese Funktion ist in Form einer Anfrage verfügbar. 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 auf diese Weise nicht möglich, einen konsistenten Snapshot des gesamten Clusters zu erstellen. Für die meisten Aufgaben ist dies jedoch nicht erforderlich, und es reicht aus, in jedem Shard die Anfrage 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 ganz einfach, ein solches Backup wiederherzustellen. Zuerst erstellen Sie die Tabellen nach den vorhandenen Tabellenbeschreibungen. Dann kopieren Sie die gespeicherten Snapshots der Partitionen in Directory-Detached für diese Tabellen und führen die Anfrage aus. attach partition. Diese Lösung eignet sich durchaus für die ernsthaftesten Datenvolumina.
Manchmal benötigt man etwas noch Besseres – insbesondere, wenn Sie Dutzende oder sogar Hunderte von Terabyte auf jedem Server und Hunderte von Servern haben. Hier gibt es eine Lösung, die ich von meinen Kollegen bei „Yandex.Metrica“ übernommen habe. Ich würde sie nicht jedem empfehlen – lesen Sie selbst und entscheiden Sie, ob sie für Sie geeignet ist oder nicht.
Zunächst müssen Sie mehrere Server mit großen Festplattenschränken erstellen. Dann setzen Sie auf diesen Servern mehrere ClickHouse-Server auf und konfigurieren sie so, dass sie wie eine weitere Replik für die gleichen Shards arbeiten. Sie sollten auf diesen Servern ein Dateisystem oder ein Tool verwenden, das es ermöglicht, Snapshots zu erstellen. Es gibt zwei Optionen. Die erste Option sind LVM-Snapshots, die zweite Option ist ZFS auf Linux.
Danach sollten Sie jeden Tag einen Snapshot erstellen, der einen gewissen Speicherplatz beanspruchen wird. Natürlich wird der Platzbedarf im Laufe der Zeit steigen, wenn sich die Daten ändern. Sie können diesen Snapshot jederzeit abrufen und die Daten wiederherstellen, das ist eine etwas ungewöhnliche Lösung. Außerdem sollten Sie diese Replikate in der Konfiguration einschränken, damit sie nicht versuchen, zu Führern zu werden.
Kann man eine kontrollierte Verzögerung von Replikaten in den Wälzen organisieren?
Planen Sie in diesem Jahr, InnoDB-Wellen in ClickHouse zu erstellen? Wird es möglich sein, eine kontrollierte Verzögerung der Replikate zu organisieren? Wir würden dies nutzen wollen, um uns vor negativen Szenarien mit Alternativen und anderen Veränderungen zu schützen.
Ist es möglich, für Alternativen irgendwelche Rollbacks durchzuführen? Zum Beispiel, in einer bestehenden Welle zu sagen, dass bis zu diesem Punkt Änderungen angewendet werden sollen, und ab diesem Punkt keine Änderungen mehr anzuwenden?
Wenn jemand in unseren Cluster eingreift und ihn beschädigt, haben wir eine bedingte Replik mit einer Stunde Verzögerung. Können wir sagen, dass wir genau diese nutzen werden, aber die Änderungen der letzten zehn Minuten nicht anwenden wollen?
Zunächst zum kontrollierten Verzögern der Replikate. Es gab eine solche Anfrage von Nutzern, und wir haben ein Issue auf GitHub erstellt mit der Bitte: „Wenn jemand das braucht, könnte er ein Like oder ein Herzchen setzen“. Niemand hat es getan, und das Issue wurde geschlossen. Dennoch ist es bereits möglich, diese Funktion zu erhalten, indem man ClickHouse konfiguriert, allerdings nur ab Version 20.3.
ClickHouse führt ständig im Hintergrund Datenmerging durch. Wenn der Merge abgeschlossen ist, wird eine bestimmte Anzahl von Datenteilen durch einen größeren Datenteil ersetzt. Zuvor existierende Datenteile bleiben jedoch für eine gewisse Zeit weiterhin auf der Festplatte.
Erstens werden sie so lange aufbewahrt, wie es SELECT-Anfragen gibt, die sie nutzen, um eine nicht blockierende Verarbeitung zu gewährleisten. SELECT-Anfragen können weiterhin problemlos auf die alten Datenteile zugreifen.
Zweitens gibt es auch eine Zeitgrenze – alte Datenteile bleiben für acht Minuten auf der Festplatte. Diese acht Minuten können angepasst und sogar auf einen ganzen Tag verlängert werden. Dies wird Speicherplatz kosten: Je nach Datenstrom könnte es passieren, dass die Daten nicht nur doppelt so groß werden, sondern bis zu fünfmal anwachsen. Im Falle eines schwerwiegenden Problems können Sie jedoch den ClickHouse-Server anhalten und alles klären.
Jetzt stellt sich die Frage, wie dies vor Alternativen schützt. Hierbei lohnt es sich, genauer hinzusehen, denn in älteren Versionen von ClickHouse arbeitete der Alter so, dass er einfach direkt die Datenteile änderte. Es gibt ein Datenteil mit bestimmten Dateien, und wir führen beispielsweise Alter Drop Column. Dann wird diese Spalte physisch aus allen Fragmenten gelöscht.
Doch seit Version 20.3 wurde der Alter-Mechanismus vollständig überarbeitet, und nun sind die Datenfragmente immer unveränderlich. Sie werden überhaupt nicht geändert – die Alter-Operationen funktionieren jetzt ähnlich wie Merges. Anstatt ein Fragment vor Ort zu ändern, erstellen wir ein neues. In dem neuen Fragment werden unveränderte Dateien Hardlinks, und wenn wir eine Spalte gelöscht haben, wird diese einfach im neuen Fragment fehlen. Das alte Fragment wird standardmäßig nach acht Minuten gelöscht, und hier können die oben genannten Einstellungen angepasst werden.
Das gilt auch für Alter-Operationen vom Typ Mutationen. Wenn Sie Alter Delete oder Alter Update, ändert es das Fragment nicht, sondern erstellt ein neues. Danach wird das alte gelöscht.
Was tun, wenn sich die Struktur der Tabelle geändert hat?
Wie stellt man ein Backup wieder her, das mit dem alten Schema erstellt wurde? Und eine zweite Frage zu dem Fall mit Snapshots und Dateisystemwerkzeugen. Ist Btrfs anstelle von ZFS auf Linux LVM hier geeignet?
Wenn Sie attach partition Wenn Sie Partitionen mit einer anderen Struktur haben, wird ClickHouse Ihnen sagen, dass das nicht möglich ist. Die Lösung ist wie folgt. Zuerst müssen Sie eine temporäre Tabelle vom Typ MergeTree mit der alten Struktur erstellen, die Daten mit attach anhängen, eine ALTER-Anfrage durchführen. Danach können Sie entweder die Daten kopieren oder verschieben und erneut attach durchführen, oder Sie nutzen eine Anfrage. alter table move partition.
Nun zur zweiten Frage: Ist es möglich, Btrfs zu verwenden? Zunächst einmal, 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 Umgang damit ab. Es handelt sich um ein ausgereiftes Dateisystem, aber es gibt dennoch einige Bedenken, wie es in der Praxis in bestimmten Szenarien funktionieren wird. Ich würde nicht empfehlen, dies zu verwenden, wenn Sie Btrfs nicht in Produktionsumgebungen haben.
Was sind derzeit die besten Praktiken für das Resharding von Daten?
Die Frage nach der Neuschärfung ist komplex und vielschichtig. Man könnte aus einer Perspektive sagen, dass ClickHouse keine integrierte Möglichkeit zur Neuschärfung bietet. Aber ich befürchte, dass diese Antwort niemanden zufriedenstellen wird. Daher könnte man auch aus einer anderen Perspektive argumentieren, dass ClickHouse viele Möglichkeiten zur Neuschärfung von Daten bietet.
Wenn der Speicherplatz im Cluster zur Neige geht oder die Last nicht bewältigt werden kann, fügen Sie neue Server hinzu. Diese Server sind jedoch standardmäßig leer, es befinden sich keine Daten darauf, und es gibt keine Last. Sie müssen die Daten umlegen, um eine gleichmäßige Verteilung über den neu vergrößerten Cluster zu erreichen.
Der erste Weg, dies zu tun, besteht darin, Teile der Partitionen mit einer Abfrage 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 kopieren Sie den dritten Monat auf einen weiteren neuen Server. So machen Sie weiter, bis es mehr oder weniger gleichmäßig verteilt ist.
Der Transfer kann nur für solche Partitionen durchgeführt werden, die beim Schreiben nicht verändert werden. Bei neuen Partitionen muss das Schreiben deaktiviert werden, da deren Transfer nicht atomar ist. Andernfalls erhalten Sie Duplikate oder Datenverluste. Dennoch ist diese Methode praktisch und funktioniert recht 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 der Sharding-Strategie abhängt. Es kommt darauf an, ob Sie diese Sharding-Strategie verwendet haben und welcher Sharding-Schlüssel vertreten war. In Ihrem Beispiel besteht der Sharding-Schlüssel für den Fall mit Metriken aus dem Hash des Pfades. Wenn Sie einen Select-Befehl in der verteilten Tabelle ausführen, wird dieser direkt an alle Shards des Clusters gesendet und holt dort die Daten ab.
Das bedeutet, dass es für Sie im Grunde keine Rolle spielt, welche Daten auf welchem Shard gelandet sind. Das Wichtigste ist, dass die Daten entlang eines Pfades auf demselben Shard erscheinen, und welcher das genau ist, ist nicht entscheidend. In diesem Fall eignet sich der Transfer fertiger Partitionen hervorragend, da Sie bei SELECT-Anfragen sowohl vor als auch nach dem Re-Sharding keine besonderen Unterschiede in der Struktur haben – Sie erhalten vollständige Daten.
Es gibt jedoch auch komplexere Fälle. Wenn Sie in der Logik der Anwendung auf ein spezielles Sharding-Schema setzen, wo dieser Kunde auf einem bestimmten Shard angesiedelt ist, können Anfragen direkt dorthin und nicht an die verteilte Tabelle gesendet werden. Oder Sie verwenden eine relativ neue Version von ClickHouse und haben die Einstellung optimize skip unused shards. In diesem Fall wird während einer SELECT-Anfrage der Ausdruck im WHERE-Abschnitt analysiert und es wird ermittelt, auf welche Shards gemäß dem Sharding-Schema zugegriffen werden muss. Dies funktioniert unter der Voraussetzung, dass die Daten genau nach diesem Sharding-Schema verteilt sind. Wenn Sie sie manuell umgelegt haben, kann die Übereinstimmung abweichen.
Das ist also die erste Methode. Ich warte auf Ihre Rückmeldung, 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 besonders gut, wenn es darum geht, die Last, einschließlich beim Lesen, 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. Ich möchte jedoch, dass der gesamte Cluster belastet wird, denn andernfalls wird eine Zeit lang die gesamte Last beim Lesen von zwei Shards bearbeitet.
Alexej Milowidow: Die Antwort hier ist seltsam – ja, es ist schlecht, könnte aber funktionieren. Ich erkläre, wie genau. Man sollte sich das Lastszenario ansehen, das für Ihre Daten gilt. Wenn es sich um Überwachungsdaten handelt, kann man fast sicher sagen, dass der überwiegende Teil der Anfragen nach aktuellen Daten verlangt.
Sie haben neue Server bereitgestellt, alte Partitionen verschoben und auch die Art und Weise geändert, wie frische Daten aufgezeichnet werden. Diese neuen Daten werden über den gesamten Cluster verteilt. So werden bereits nach fünf Minuten die Anfragen der letzten fünf Minuten gleichmäßig auf den Cluster verteilt, nach einem Tag werden die Anfragen für die letzten 24 Stunden gleichmäßig den Cluster belasten. Die Anfragen für den vorherigen Monat werden leider nur auf einen Teil der Server im Cluster verteilt.
Oft werden Sie jedoch keine Anfragen speziell für Februar 2019 haben. Wahrscheinlicher ist es, dass, wenn Anfragen für das Jahr 2019 kommen, diese für das gesamte Jahr sind — über einen größeren Zeitraum, nicht für einen kleinen Bereich. Solche Anfragen können ebenfalls gleichmäßig den Cluster belasten. Insgesamt ist Ihr Hinweis jedoch vollkommen richtig, dass es sich um eine ad-hoc-Lösung handelt, die die Daten nicht vollständig gleichmäßig verteilt.
Ich habe noch einige Punkte zur Beantwortung der Frage. Einer davon betrifft, wie man die Sharding-Schemata von Anfang an so gestaltet, dass das Resharding weniger schmerzhaft ist. Das ist nicht immer möglich.
Zum Beispiel verfügen Sie über Monitoring-Daten. Diese Daten wachsen aus drei Gründen. Erstens: die Ansammlung historischer Daten. Zweitens: das Wachstum des Traffics. Und drittens: die Zunahme der Dinge, die überwacht werden müssen. Es entstehen neue Mikrodienste und Metriken, die gespeichert werden müssen.
Es ist möglich, dass das größte Wachstum tatsächlich mit dem dritten Grund zusammenhängt – der erhöhten Nutzung von Monitoring. In diesem Fall sollten Sie die Art der Belastung ansehen, wobei die Hauptanfragen für select entscheidend sind. Diese Anfragen beziehen sich wahrscheinlich auf eine Teilmenge der Metriken.
Zum Beispiel die CPU-Nutzung auf bestimmten Servern durch einen Dienst. Es gibt eine Teilmenge von Schlüsseln, anhand derer Sie diese Daten abrufen. Die Anfrage nach diesen Daten ist wahrscheinlich relativ einfach und wird in Millisekunden ausgeführt. Sie wird für Monitoring-Dienste und Dashboards genutzt. Ich hoffe, ich habe das richtig verstanden.
Wladimir Kolobajew: Wir beziehen uns sehr oft auf historische Daten, da wir in Echtzeit die aktuelle Situation mit der historischen vergleichen. Deshalb ist es wichtig für uns, schnellen Zugang zu großen Datenmengen zu haben, und ClickHouse erfüllt diese Anforderungen hervorragend.
Sie haben absolut recht, die meisten Leseanfragen treten bei uns am letzten Tag auf, wie bei jedem Überwachungssystem. Dennoch gibt es auch eine erhebliche Last auf den historischen Daten. Diese stammt hauptsächlich von unserem Alarmsystem, das alle dreißig Sekunden zu ClickHouse geht und sagt: "Gib mir die Daten der letzten sechs Wochen. Und jetzt erstelle einen gleitenden Durchschnitt und lass uns den aktuellen Wert mit dem historischen vergleichen."
Ich möchte erwähnen, dass wir für derartige sehr frische Anfragen eine kleine Tabelle haben, in der wir nur Daten von zwei Tagen speichern, und die Hauptanfragen gehen dorthin. Große historische Anfragen senden wir nur an die große shardierte Tabelle.
Alexej Milowidow: Leider ist dies für Ihr Szenario nicht gut anwendbar, aber ich werde Ihnen eine Beschreibung von zwei schlechten und komplexen Sharding-Schemata geben, die nicht verwendet werden sollten, aber in dem Service meiner Freunde genutzt werden.
Es gibt einen Hauptcluster mit Ereignissen von 'Yandex.Metrica'. Die Ereignisse sind Seitenaufrufe, Klicks und Übergänge. Die meisten Anfragen betreffen eine bestimmte Website. Sie öffnen den Dienst 'Yandex.Metrica', haben eine Website – avito.ru, gehen zum Bericht und es wird eine Anfrage für Ihre Website gestellt.
Aber es gibt auch andere Anfragen – analytische und globale, die von internen Analysten gestellt werden. Ich möchte anmerken, dass interne Analysten nur Anfragen für 'Yandex'-Dienste stellen. Dennoch machen auch die 'Yandex'-Dienste einen erheblichen Teil aller Daten aus. Dies sind Anfragen nicht für spezifische Zähler, sondern für breitere Filterungen.
Wie organisiert man die Daten so, dass sowohl bei einem einzelnen Zähler alles effizient funktioniert als auch globale Anfragen? Die Herausforderung besteht darin, dass die Anzahl der Anfragen in ClickHouse für den Cluster „Metrics“ mehrere Tausend pro Sekunde beträgt. Bei komplexen Anfragen kann ein einzelner ClickHouse-Server diese Last nicht bewältigen.
Die Clustergröße liegt bei über sechshundert Servern. Wenn man einfach eine verteilte Tabelle über dieses Cluster legt und dort mehrere Tausend Anfragen sendet, wird es noch problematischer, als sie an einen einzelnen Server zu senden. Andererseits fällt die Variante weg, bei der 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 Webseiten, und die Anfrage für eine bestimmte Webseite geht an einen Shard. Nun könnte der Cluster problemlos zehntausend Anfragen pro Sekunde bearbeiten, aber auf einem bestimmten Shard könnte eine Anfrage viel zu langsam sein. In diesem Fall würde die Kapazität nicht mehr skalierbar sein. Besonders wenn es sich um die Webseite avito.ru handelt. Ich verrate kein Geheimnis, wenn ich sage, dass Avito eine der meistbesuchten Seiten im russischen Internet ist. Es wäre Wahnsinn, sie auf einem einzelnen Shard zu verarbeiten.
Daher ist das Shardierungs-Schema etwas ausgeklügelter. Der gesamte Cluster ist in eine bestimmte Anzahl von Clustern unterteilt, die wir als Schichten bezeichnen. Innerhalb jedes Clusters gibt es von einem Dutzend bis hin zu mehreren Dutzend Shards. Insgesamt gibt es neununddreißig solcher Cluster.
Wie skalieren wir das alles? Die Anzahl der Cluster bleibt gleich – wie vor einigen Jahren bei neununddreißig, so ist es auch geblieben. Innerhalb jedes Clusters erhöhen wir allmählich die Anzahl der Shards, je mehr Daten wir sammeln. Das Sharding-Schema sieht vor, dass die Aufteilung auf diese Cluster nach Websites erfolgt. Um zu verstehen, welche Website sich auf welchem Cluster befindet, verwenden wir eine separate Metadatenbank in MySQL. Eine Website gehört zu einem Cluster. Innerhalb dieses Clusters erfolgt das Sharding anhand der Besucher-IDs.
Bei der Speicherung teilen wir diese nach dem Rest der Division der Besucher-ID auf. Fügen wir einen neuen Shard hinzu, ändert sich das Sharding-Schema: Wir setzen die Aufteilung fort, jedoch mit dem Rest der Division durch eine andere Zahl. Das bedeutet, dass ein Besucher tatsächlich auf mehreren Servern verteilt ist, und darauf kann man sich nicht verlassen. Dies wurde ausschließlich eingeführt, um die Daten besser zu komprimieren. Bei Anfragen gehen wir in die verteilte Tabelle, die auf das Cluster zugreift und Dutzende von Servern anfragt. So funktioniert dieses seltsame Schema.
Meine Erzählung wäre unvollständig, wenn ich nicht erwähnen würde, dass wir uns von diesem Schema verabschiedet haben. In dem 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 die Schwelle gewählt wurde, aber am Ende ergibt es sich so, dass große Websites auf einen Cluster mit 120 Shards, jeweils mit drei Replikaten, geschrieben werden – also insgesamt 360 Server. Das Sharding-Schema ist so aufgebaut, dass jede Anfrage sofort an alle Shards gesendet wird. Wenn Sie jetzt in 'Yandex.Metrica' eine beliebige Berichtseite für avito.ru öffnen, wird die Anfrage an 120 Server gesendet. Große Websites sind im russischen Internet selten. Die Anfragen liegen also nicht bei tausend pro Sekunde, sondern sogar unter hundert. Das wird problemlos von der verteilten Tabelle verarbeitet, die von jedem der 120 Server bearbeitet wird.
Der zweite Cluster ist für kleine Websites. Hier erfolgt das Sharding nach der Website-ID, und jede Anfrage wird genau an einen Shard gesendet.
ClickHouse bietet das Tool clickhouse-copier. Können Sie darüber erzählen?
Ich sage gleich, dass diese Lösung etwas umständlicher und weniger leistungsstark ist. Der Vorteil liegt darin, dass sie die Daten vollständig gemäß dem von Ihnen angegebenen Schema verteilt. Der Nachteil des Tools ist jedoch, dass es kein Re-Sharding durchführt. Es kopiert die Daten von einem Cluster-Schema in ein anderes.
Das bedeutet, dass Sie für den Betrieb zwei Cluster benötigen. Diese können auf denselben Servern liegen, aber die Daten werden nicht inkrementell verschoben, sondern kopiert.
Zum Beispiel, wenn es vier Server gab, sind es nun acht. Sie erstellen auf allen Servern eine neue verteilte Tabelle, neue lokale Tabellen und starten den clickhouse-copier, wobei Sie das Arbeitschema angeben, welches er lesen soll, das neue Sharding-Schema annehmen soll und die Daten dorthin verschieben soll. Sie benötigen auf den alten Servern anderthalb Mal mehr Platz als jetzt, da die alten Daten dort verbleiben müssen, und zusätzlich wird eine Hälfte von diesen alten Daten dorthin kommen. Wenn Sie im Voraus darüber nachgedacht haben, dass die Daten reshardo werden müssen und Platz vorhanden ist, dann ist diese Methode sinnvoll.
Wie funktioniert clickhouse-copier intern? Es zerlegt die gesamte Arbeit in eine Reihe von Aufgaben zur Verarbeitung einer Partition einer Tabelle auf einem Shard. All diese Aufgaben können parallel ausgeführt werden, und clickhouse-copier kann auf verschiedenen Maschinen in mehreren Instanzen gestartet werden. Was es jedoch für eine Partition tut, ist nichts anderes als ein Insert Select. Die Daten werden gelesen, dekomprimiert, neu verteilt, dann wieder komprimiert, irgendwo gespeichert und umsortiert. Das ist eine anspruchsvollere Lösung.
Sie hatten ein Pilotprojekt namens Resharding. Was ist daraus geworden?
Bereits 2017 hatten Sie ein Pilotprojekt, das als Resharding bezeichnet wurde. Es gibt sogar eine Option in ClickHouse. Soweit ich weiß, hat es sich nicht durchgesetzt. Können Sie erzählen, warum das so war? Es scheint doch sehr relevant zu sein.
Das Hauptproblem ist, dass bei Bedarf eine sehr komplexe Synchronisation erforderlich ist, um die Daten vor Ort atomar umzuschreiben. Als wir untersuchten, wie diese Synchronisation funktioniert, wurde klar, dass es fundamentale Probleme gibt. Und diese fundamentalen Probleme sind nicht nur theoretisch, sondern zeigen sich sofort in der Praxis durch das sehr einfache zu erklärende Phänomen — nichts funktioniert.
Kann man alle Datenanteile vor der Verschiebung 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 zu einer Einheit zusammenzuführen?
Die Antwort auf die Frage, ob man die Teile automatisch zu einem Ganzen vor deren Verschiebung zusammenfügen kann — lautet nein. Ich denke, das ist nicht notwendig. Es ist nicht erforderlich, alle Teile zu einem zu verbinden, man kann einfach darauf vertrauen, dass sie automatisch auf die langsamen Festplatten verschoben werden.
Wir haben zwei Kriterien für den Transfer. Das erste ist der Füllstand. Wenn auf dem aktuellen Speicherplatz weniger als ein gewisser Prozentsatz frei ist, wählen wir ein Stück aus und übertragen es auf einen langsameren Speicher. Genauer gesagt, nicht einen langsameren, sondern den nächsten — je nach Ihrer Konfiguration.
Das zweite Kriterium ist die Größe. Es befasst sich mit der Übertragung großer Datenmengen. Sie können die Schwelle für den freien Speicherplatz auf der schnellen Festplatte anpassen, und die Daten werden automatisch übertragen.
Wie migriert man auf neue Versionen von ClickHouse, wenn man die Kompatibilität nicht im Voraus prüfen kann?
Dieses Thema wird regelmäßig diskutiert unter Berücksichtigung verschiedener Versionen. Wie sicher ist es beispielsweise, von Version 19.11 auf 19.16 und von 19.16 auf 20.3 zu aktualisieren? Wie können Sie am besten auf neue Versionen umsteigen, ohne die Möglichkeit zu haben, die Kompatibilität im Vorfeld in einer Sandbox zu überprüfen?
Hier sind einige „Goldene“ Regeln. Erstens — . Es ist umfangreich, aber es gibt spezifische Punkte zu nicht rückwärtskompatiblen Änderungen. Sie sollten diese Punkte nicht als roten Alarm betrachten. In der Regel handelt es sich um kleinere Inkompatibilitäten, die mit bestimmten Randfunktionen verbunden sind, die Sie wahrscheinlich nicht verwenden.
Zweiter Punkt – wenn es keine Möglichkeit gibt, die Kompatibilität in einer Testumgebung zu prüfen und Sie sofort im Produktionsumfeld aktualisieren möchten, lautet die Empfehlung: Lassen Sie es lieber sein. Erstellen Sie zunächst eine Testumgebung und überprüfen Sie die Änderungen. Falls keine Testumgebung vorhanden ist, handelt es sich wahrscheinlich um ein kleines Unternehmen, sodass Sie einen Teil der Daten auf Ihren Laptop kopieren und dort testen können, ob alles korrekt funktioniert. Sie können sogar mehrere Instanzen lokal auf Ihrem Rechner aufsetzen. Alternativ können Sie eine neue Version in der Nähe bereitstellen und einige Daten dorthin übertragen – also eine improvisierte Testumgebung einrichten.
Eine weitere Regel lautet: Aktualisieren Sie nicht in der Woche nach dem Release einer neuen Version, um Bugs im Produktionsumfeld zu identifizieren und die nachfolgenden schnellen Fixes zu berücksichtigen. Lassen Sie uns die Versionsnummerierung von ClickHouse genauer betrachten, um Verwirrung zu vermeiden.
Es gibt die Version 20.3.4. Die 20 steht für das Jahr der Veröffentlichung – 2020. Hinter den Kulissen hat das keine große Bedeutung, weshalb wir darauf nicht weiter eingehen. Weiter geht’s mit 20.3. Die zweite Ziffer – in diesem Fall 3 – erhöhen wir jedes Mal, wenn wir ein Release mit neuen Funktionalitäten herausbringen. Möchten wir ClickHouse um eine bestimmte Funktion erweitern, müssen wir diese Zahl anpassen. Das bedeutet, dass in Version 20.4 ClickHouse noch besser funktionieren wird. Die dritte Ziffer – 20.3.4. Hier steht die 4 für die Anzahl der Patch-Releases, in denen wir keine neuen Funktionen hinzugefügt haben, sondern Fehler behoben haben. Und die 4 bedeutet, dass wir dies vier Mal gemacht haben.
Man sollte nicht denken, dass dies etwas Schreckliches ist. Gewöhnlich kann der Nutzer die neueste Version installieren, und sie funktioniert ein Jahr lang problemlos im Hinblick auf die Uptime. Aber stellen Sie sich vor, dass bei einer Funktion zur Verarbeitung von Bitmaps, die von unseren chinesischen Kollegen hinzugefügt wurde, der Server abstürzt, wenn falsche Argumente übergeben werden. Wir sind verpflichtet, das zu beheben. Wir werden eine neue Patch-Version herausbringen, und ClickHouse wird stabiler.
Wenn Sie ClickHouse in der Produktion einsetzen und eine neue Version wie 20.4.1 mit zusätzlichen Funktionen erscheint, sollten Sie nicht sofort am ersten Tag in die Produktion wechseln. Warum ist sie überhaupt wichtig? Wenn Sie ClickHouse noch nicht verwenden, können Sie es installieren, und wahrscheinlich wird alles gut laufen. Aber wenn ClickHouse bereits stabil läuft, sollten Sie auf Patches und Updates achten — wir korrigieren Probleme.
Kirill Shvakov: Ich möchte noch etwas über Testumgebungen ergänzen. Viele haben große Angst vor Testumgebungen und glauben fälschlicherweise, dass, wenn Sie einen sehr großen ClickHouse-Cluster haben, die Testumgebung ebenso groß oder mindestens zehn Mal kleiner sein sollte. Das ist überhaupt nicht der Fall.
Ich kann aus eigener Erfahrung sprechen. Ich habe ein Projekt, in dem ClickHouse eingesetzt wird. Unsere Testumgebung dafür ist eine kleine virtuelle Maschine bei Hetzner für zwanzig Euro, auf der alles vollständig bereitgestellt ist. Um dies zu realisieren, haben wir eine vollständige Automatisierung mit Ansible, weshalb es im Grunde keinen Unterschied macht, ob wir auf physische Server oder einfach in virtuellen Maschinen bereitstellen.
Was kann man tun? Es wäre hilfreich, in der ClickHouse-Dokumentation ein Beispiel zu zeigen, wie man einen kleinen Cluster selbst bereitstellt – sei es in Docker oder LXC. Möglicherweise könnte man ein Ansible-Playbook erstellen, da die Deployments bei verschiedenen Nutzern unterschiedlich sind. Das würde vieles einfacher machen. Wenn man in fünf Minuten einen Cluster aufsetzen kann, ist es viel einfacher, etwas zu verstehen. So ist es viel angenehmer, denn in eine Produktionsversion einzuführen, die man nicht getestet hat – das führt in die Irre. 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 aus der Reihe der Probleme großer Unternehmen hinzufügen. Wir haben einen vollwertigen Abnahme-Cluster für ClickHouse, der in Bezug auf Datenmodelle und Konfigurationen eine exakte Kopie der Produktionsumgebung ist. Dieser Cluster ist in ziemlich bescheidenen Containern mit minimalen Ressourcen bereitgestellt. Wir schreiben einen Teil der Produktionsdaten dort hinein, da wir die Möglichkeit haben, den Datenstrom in Kafka zu replizieren. Alles ist synchronisiert und skaliert – sowohl in Bezug auf die Kapazitäten als auch auf den Durchsatz und sollte theoretisch unter gleichen Bedingungen in Bezug auf die Metriken wie die Produktion funktionieren. Alles potenziell Explosive wird zuerst in dieses Umfeld geleitet und reift dort einige Tage, bis es bereit ist. Natürlich ist diese Lösung teuer, komplex und mit nicht unerheblichen Wartungskosten verbunden.
Alexej Milowidow: Ich möchte Ihnen vorstellen, was die Testumgebung unserer Freunde von „Yandex.Metrica“ beinhaltet. Ein Cluster hatte über 600 Server, ein anderer 360, und es gibt noch einen dritten sowie mehrere weitere Cluster. Die Testumgebung für einen davon besteht einfach aus zwei Shards, wobei jeder zwei Replikate enthält. Warum zwei Shards? Damit es nicht nur einen gibt. Und auch, damit Replikate vorhanden sind. Es ist einfach eine Mindestanzahl, die man sich leisten kann.
Diese Testumgebung ermöglicht es, die Funktionsfähigkeit der Anfragen zu überprüfen und sicherzustellen, dass nichts Schwerwiegendes kaputt ist. Oft treten jedoch Probleme ganz anderer Art auf, wenn alles funktioniert, aber es einige kleine Änderungen in der Last gibt.
Ich gebe ein Beispiel. Wir haben beschlossen, eine neue Version von ClickHouse zu installieren. Diese wurde in der Testumgebung bereitgestellt, automatisierte Tests in Yandex.Metrica wurden durchgeführt, die die Daten der alten Version mit denen der neuen vergleichen, und den gesamten Prozess durchlaufen. Und natürlich waren die Tests in unserem CI erfolgreich. Andernfalls hätten wir diese Version nicht einmal angeboten.
Alles bestens. Wir beginnen mit dem Rollout in die Produktion. Ich erhalte eine Nachricht, dass die Last auf den Grafiken mehrere Male gestiegen ist. Wir setzen die Version zurück. Ich schaue auf das Diagramm und sehe: Die Last ist während des Rollouts tatsächlich gestiegen und fiel wieder, als wir es zurückgesetzt haben. Danach haben wir die Version wieder zurückgesetzt, und die Last stieg genauso an und fiel genauso zurück. Die Schlussfolgerung ist also, dass die Last aufgrund des Rollouts gestiegen ist, nichts Überraschendes.
Es war schwierig, die Kollegen zu überzeugen, die neue Version doch zu installieren. Ich sagte: „Alles gut, rollt es aus. Drückt die Daumen, es wird funktionieren. Zurzeit ist die Last auf den Grafiken gestiegen, aber es ist alles in Ordnung. Haltet durch.“ Insgesamt haben wir das so gemacht, und schließlich wurde die Version in die Produktion gebracht. Aber bei fast jedem Rollout treten ähnliche Probleme auf.
Der Kill-Query sollte Anfragen beenden, tut dies aber nicht. Warum?
Ein Analyst hat sich bei mir gemeldet und eine Anfrage gestellt, die meinen ClickHouse-Cluster zum Stillstand gebracht hat. Entweder eine bestimmte Node oder der gesamte Cluster, je nachdem, in welche Replik oder Partition die Anfrage gelangt ist. Ich sehe, dass alle CPU-Ressourcen auf diesem Server überlastet sind, alles ist rot. Dennoch antwortet ClickHouse weiter auf die Anfragen. Ich schreibe: „Zeige mir bitte die Process-Liste, welche Anfrage dieses Chaos verursacht hat.“
Ich finde diese Anfrage und schreibe ihm einen Kill-Befehl. Doch ich sehe, dass nichts passiert. Mein Server ist überlastet, ClickHouse gibt mir weiterhin Befehle aus und zeigt, dass der Server lebt, und alles ist in Ordnung. Aber ich habe eine Degeneration bei allen Benutzeranfragen, in ClickHouse beginnt die Leistung ebenfalls zu sinken, und mein Kill-Befehl funktioniert nicht. Warum? Ich dachte, der Kill-Befehl sollte die Anfragen stoppen, aber das passiert nicht.
Jetzt kommt eine etwas seltsame Antwort. Das Problem ist, dass der Kill-Befehl die Anfragen nicht stoppt.
Die Kill-Abfrage setzt ein kleines Flag mit dem Namen „Ich möchte, dass diese Anfrage beendet wird“. Bei der Verarbeitung jedes Datenblocks prüft die Anfrage dieses Flag. Ist es gesetzt, stoppt die Anfrage die Verarbeitung. Es ist also niemand da, der die Anfrage beendet; sie muss selbst alles überprüfen und anhalten. Das sollte in allen Fällen funktionieren, in denen die Anfrage sich im Zustand der Verarbeitung von Datenblöcken befindet. Sie bearbeitet den nächsten Datenblock, prüft das Flag und hält an.
Das funktioniert nicht, wenn die Anfrage bei einer bestimmten Operation blockiert ist. Allerdings ist es wahrscheinlich, dass dies nicht Ihr Fall ist, denn laut Ihren Angaben verbraucht sie eine Menge Serverressourcen. Möglicherweise funktioniert es nicht bei externen Sortierungen und in einigen anderen Details. Aber insgesamt sollte das nicht der Fall sein, das ist ein Bug. Und das Einzige, was ich empfehlen kann, ist, ClickHouse zu aktualisieren.
Wie berechnet man die Antwortzeit bei einer Leseanfrage?
Es gibt eine Tabelle, in der Aggregationen nach Item gespeichert sind – verschiedene Zähler. Die Anzahl der Zeilen beträgt etwa hundert Millionen. Kann man mit einer vorhersehbaren Antwortzeit rechnen, wenn man 1K RPS für 1K Items einspeist?
Im Kontext geht es wahrscheinlich um Leseanfragen, denn beim Schreiben gibt es keine Probleme – egal ob tausend, hunderttausend oder manchmal sogar mehrere Millionen Zeilen können eingefügt werden.
Leseanfragen können sehr unterschiedlich sein. In einem select 1 kann ClickHouse etwa zehntausende Anfragen pro Sekunde verarbeiten, sodass selbst Anfragen anhand eines einzelnen Schlüssels bereits gewisse Ressourcen benötigen. Solche punktuellen Anfragen sind komplizierter als in einigen Key-Value-Datenbanken, da für jedes Lesen ein Datenblock anhand des Index gelesen werden muss. Der Index adressiert nicht jeden einzelnen Eintrag, sondern jeden Bereich. Das bedeutet, dass der gesamte Bereich gelesen werden muss – standardmäßig 8192 Zeilen. Zudem muss der komprimierte Datenblock von 64 kB auf 1 MB entpackt werden. In der Regel benötigen solche punktuellen Anfragen mehrere Millisekunden. Aber das ist die einfachste Variante.
Lassen Sie uns eine einfache Arithmetik ausprobieren. Wenn man mehrere Millisekunden mit tausend multipliziert, erhält man mehrere Sekunden. Es mag scheinen, dass man nicht tausend Anfragen pro Sekunde verarbeiten kann, aber tatsächlich ist es möglich, da wir mehrere CPU-Kerne haben. Daher kann ClickHouse in der Regel 1000 RPS verarbeiten, allerdings nur bei kurzen, punktuellen Anfragen.
Sollte es erforderlich sein, einen ClickHouse-Cluster hinsichtlich der Anzahl einfach gestalteter Anfragen zu skalieren, empfehle ich die einfachste Lösung – die Anzahl der Replikate zu erhöhen und die Anfragen an eine zufällige Replik zu senden. Wenn eine Replik bei Ihnen fünfhundert Anfragen pro Sekunde verarbeiten kann, was durchaus realistisch ist, dann können drei Replikate anderthalbtausend Anfragen bewältigen.
Gelegentlich kann man ClickHouse auch so konfigurieren, dass es das maximale Volumen an punktuellen Lesevorgängen verarbeiten kann. Was benötigt man dafür? Zuerst muss die Granularität des Indexes verringert werden. Dabei sollte man sie jedoch nicht auf eins reduzieren, sondern so, dass die Anzahl der Einträge im Index mehrere Millionen oder Dutzend Millionen pro Server beträgt. Wenn die Tabelle hundert Millionen Zeilen hat, könnte man eine Granularität von 64 festlegen.
Die Größe des komprimierten Blocks kann verringert werden. Dafür gibt es Einstellungen. minimale Größe des komprimierten Blocks, maximale Größe des komprimierten Blocks. Diese können verringert und die Daten umgeschichtet werden, sodass punktuelle Abfragen schneller sind. Dennoch ist ClickHouse keine Key-Value-Datenbank. Eine große Anzahl kleiner Abfragen ist ein Antipattern bei der Lastverteilung.
Kirill Shvakov: Ein Hinweis für den Fall, dass dort herkömmliche Zähler verwendet werden. Es ist eine relativ gängige Situation, wenn ClickHouse einen bestimmten Zähler speichert. Ich habe einen Benutzer, der aus einem bestimmten Land kommt, und ein drittes Feld, in dem etwas inkrementell erhöht werden muss. Sie nehmen MySQL, erstellen einen einzigartigen Schlüssel – in MySQL ist er ein doppelter Schlüssel, in PostgreSQL ein Konflikt – und addieren ihn mit einem Plus. Das wird viel besser funktionieren.
Wenn Sie nur wenige Daten haben, gibt es keinen besonderen Sinn darin, ClickHouse zu verwenden. Es gibt herkömmliche Datenbanken, die damit gut zurechtkommen.
Was kann man in ClickHouse optimieren, damit mehr Daten im Cache sind?
Stellen wir uns eine Situation vor – die Server haben 256 GB RAM, im täglichen Betrieb benötigt ClickHouse etwa 60-80 GB, in der Spitze bis zu 130. Was kann aktiviert und optimiert werden, damit mehr Daten im Cache sind und somit weniger Zugriffe auf die Festplatte erfolgen?
In der Regel bewältigt der Page-Cache des Betriebssystems diese Aufgabe gut. Wenn Sie einfach nur die Top-Performance überprüfen, sehen Sie dort den Status "cached" oder "free" – auch dort steht, wie viel gespeichert ist. Es ist zu erkennen, dass der gesamte verfügbare Speicher für den Cache genutzt wird. Bei der Lektüre werden diese Daten nicht von der Festplatte, sondern aus dem Arbeitsspeicher gelesen. Ich kann sagen, dass der Cache effizient genutzt wird, da komprimierte Daten zwischengespeichert werden.
Wenn Sie jedoch einige einfache Abfragen noch weiter beschleunigen möchten, gibt es die Möglichkeit, innerhalb von ClickHouse einen Cache für die unkomprimierten Daten zu aktivieren. Dies wird genannt uncompressed cache. Im Konfigurationsdatei config.xml stellen Sie die Größe des uncompressed cache auf den gewünschten Wert ein – ich empfehle, nicht mehr als die Hälfte des verfügbaren Arbeitsspeichers zu verwenden, da der Rest für den Page-Cache benötigt wird.
Darüber hinaus gibt es zwei Abfrageebenen-Einstellungen. Die erste Einstellung ist use uncompressed cache — ermöglicht deren Nutzung. Es wird empfohlen, sie für alle Anfragen zu aktivieren, außer für umfangreiche, die alle Daten auslesen und diesen Cache leeren könnten. Die zweite Einstellung bezieht sich auf die maximale Anzahl an Zeilen, die für die Cache-Nutzung genutzt werden können. Sie begrenzt automatisch große Anfragen, sodass sie den Cache umgehen.
Wie kann man die storage_configuration für den Betriebsspeicher optimieren?
In der neuen Dokumentation von ClickHouse habe ich einen Abschnitt gefunden, der sich . Im Beschreibung gibt es ein Beispiel mit schnellen SSDs.
Es ist interessant, wie man dasselbe mit volatiler Hauptspeicher konfigurieren kann. Und noch eine Frage: Wie funktioniert der SELECT-Befehl mit dieser Datenorganisation? Liest er das gesamte Set oder nur das, was auf der Festplatte liegt, und werden diese Daten im Speicher komprimiert? Und wie funktioniert der Pre-Where-Abschnitt in dieser Datenorganisation?
Diese Einstellung hat Einfluss auf die Speicherung von Datenblöcken, und ihr Format ändert sich nicht.
Lassen Sie uns das genauer betrachten.
Es ist möglich, die Datenspeicherung im Arbeitsspeicher einzurichten. Alles, was für die Festplatte konfiguriert wird, ist ihr Pfad. Sie erstellen einen tmpfs-Bereich, der an einem bestimmten Pfad im Dateisystem eingehängt ist. Diesen Pfad geben Sie als Speicherort für die heißesten Daten an, die hier eintreffen und gespeichert werden. Es läuft alles gut.
Ich empfehle jedoch, dies aufgrund der geringen Zuverlässigkeit zu vermeiden, obwohl es möglich ist, falls Sie mindestens drei Kopien in verschiedenen Rechenzentren haben. Im Notfall können die Daten wiederhergestellt werden. Stellen Sie sich vor, der Server wird plötzlich ausgeschaltet und wieder eingeschaltet. Der Bereich wird erneut eingehängt, aber dort ist es leer. Der ClickHouse-Server sieht beim Start, dass diese Daten fehlen, obwohl sie laut den Metadaten von ZooKeeper vorhanden sein sollten. Er überprüft, auf welchen Replikaten sie vorhanden sind, fordert sie an und lädt sie herunter. Auf diese Weise werden die Daten wiederhergestellt.
In diesem Zusammenhang unterscheidet sich die Speicherung von Daten im Arbeitsspeicher prinzipiell nicht von der Speicherung auf der Festplatte, da die Daten beim Schreiben auf die Festplatte ebenfalls zunächst im Page-Cache landen und physisch verzögert aufgezeichnet werden. Dies hängt von der Art der Einbindung des Dateisystems ab. Aber zur Vorsicht sei gesagt, dass ClickHouse bei Inserts kein fsync durchführt.
Dabei werden die Daten im Arbeitsspeicher im genau gleichen Format gespeichert wie auf der Festplatte. Die Select-Abfrage wählt in ähnlicher Weise die Teile aus, die gelesen werden müssen, wählt die notwendigen Datenbereiche in Segmenten aus und liest sie. Das Prewhere funktioniert dabei absolut identisch, unabhängig davon, ob die Daten im Arbeitsspeicher oder auf der Festplatte waren.
Bis zu wie vielen einzigartigen Werten ist Low Cardinality effektiv?
Low Cardinality ist clever aufgebaut. Es erstellt Datenwörterbücher, aber diese sind lokal. Erstens hat jeder Teil seine eigenen Wörterbücher, und zweitens können sie sogar innerhalb eines Teils unterschiedlich für jeden Bereich sein. Wenn die Anzahl der einzigartigen Werte eine Schwelle erreicht – meines Wissens nach eine Million – wird das Wörterbuch einfach abgelegt und ein neues erstellt.
Generell gilt: Für jeden lokalen Bereich — sagen wir, für jeden Tag — sind bis zu einer Million einzigartiger Werte mit Low Cardinality effektiv. Danach gibt es lediglich einen Fallback, bei dem verschiedene Wörterbücher anstelle von nur einem verwendet werden. Dies funktioniert ähnlich wie eine gewöhnliche Spalte vom Typ string, möglicherweise etwas weniger effizient, jedoch wird es zu keinerlei erheblichen Leistungseinbußen kommen.
Was sind die besten Praktiken für die Volltextsuche in einer Tabelle mit fünf Milliarden Zeilen?
Es gibt verschiedene Antwortmöglichkeiten. Die erste wäre zu sagen, dass ClickHouse kein System für die Volltextsuche ist. Dafür gibt es spezielle Systeme wie zum Beispiel, und . Dennoch treffe ich zunehmend auf Menschen, die berichten, dass sie von Elasticsearch zu ClickHouse wechseln.
Wie kommt es dazu? Sie erklären es damit, dass Elasticsearch bei bestimmten Datenmengen nicht mehr mit der Last zurechtkommt, besonders wenn es um das Erstellen von Indizes geht. Die Indizes werden zu sperrig, und wenn man die Daten einfach nach ClickHouse verschiebt, resultiert dies in einer deutlich effizienteren Speicherung. Dabei waren die Suchanfragen oft nicht darauf ausgelegt, in den gesamten Datenmengen eine bestimmte Phrase unter Berücksichtigung der Morphologie zu finden, sondern etwas ganz anderes. Zum Beispiel, die Logs der letzten Stunden nach einer bestimmten Byte-Unterfolge zu durchsuchen.
In diesem Fall erstellen Sie in ClickHouse einen Index, dessen erstes Feld das Datum mit der Uhrzeit ist. Und die größte Datenbeschneidung erfolgt genau anhand des Datumsbereichs. Innerhalb des gewählten Datumsbereichs kann man in der Regel eine Volltextsuche sogar mit einer Brute-Force-Methode mithilfe von like durchführen. 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 ein Full-Scan wie ein vollständiger Scan. Und ein vollständiger Scan kann nicht nur CPU-intensiv, sondern auch plattenspeicherintensiv sein. Wenn Sie plötzlich ein Terabyte Daten pro Tag haben und nach einem bestimmten Wort suchen, müssen Sie ein Terabyte scannen. Und dieses befindet sich wahrscheinlich auf herkömmlichen Festplatten, die dann so stark ausgelastet sind, dass Sie nicht mehr per SSH auf diesen Server zugreifen können.
In diesem Fall möchte ich Ihnen einen weiteren kleinen Trick anbieten. Es handelt sich um einen experimentellen Ansatz – er könnte funktionieren oder auch nicht. In ClickHouse gibt es Volltextindizes in Form von trigrammatischen Bloom-Filtern. Unsere Kollegen bei Arenadata haben diese Indizes bereits ausprobiert, und oft funktionieren sie genau wie beabsichtigt.
Um sie richtig zu nutzen, sollte man gut verstehen, wie sie genau funktionieren: was ein trigrammatischer Bloom-Filter ist und wie man seine Größe wählt. Ich kann sagen, dass sie bei Abfragen nach seltenen Phrasen oder Substrings, die in den Daten selten vorkommen, hilfreich sind. In diesem Fall werden Sub-Bereiche basierend auf den Indizes ausgewählt, und es werden weniger Daten gelesen.
Kürzlich wurden in ClickHouse weitere fortschrittliche Funktionen für die Volltextsuche eingeführt. Dazu gehört unter anderem die gleichzeitige Suche nach mehreren Substrings in einem Durchgang, einschließlich Optionen 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 für Sie am effektivsten passende Methode aus.
Außerdem gibt es jetzt die Möglichkeit, mehrere reguläre Ausdrücke in einem Durchgang zu durchsuchen. Sie müssen nicht mehr X like ein Substring oder X like ein anderes Substring eingeben. Schreiben Sie einfach alles auf einmal, und es wird so effizient wie möglich ausgeführt.
Drittens ist jetzt eine ungefähre Suche nach Regex und ungefähren Substrings möglich. Wenn jemand ein Wort mit einem Tippfehler eingegeben hat, wird es nach der maximalen Übereinstimmung gesucht.
Wie organisiert man den Zugriff auf ClickHouse für eine große Anzahl von Benutzern am besten?
Erklären Sie, wie der Zugang für eine große Anzahl von Nutzern und Analysten am besten organisiert werden kann. Wie kann eine Warteschlange gebildet, die Anfragen priorisiert und die maximalen gleichzeitigen Anfragen gesteuert werden, und welche Tools sollten dabei verwendet werden?
Wenn der Cluster groß genug ist, kann es sinnvoll sein, zwei zusätzliche Server einzurichten, die als Zugangspunkt für Analysten dienen. Das bedeutet, dass Analysten keinen direkten Zugriff auf die spezifischen Shards des Clusters erhalten, sondern dass einfach zwei leere Server ohne Daten erstellt werden, auf denen die Zugriffsrechte eingerichtet werden. Die Benutzereinstellungen werden dabei für die verteilten Anfragen an die entfernten Server übertragen. Das heißt, alles wird auf diesen beiden Servern konfiguriert, und die Einstellungen wirken sich auf den gesamten Cluster aus.
Grundsätzlich sind diese Server datalos, aber der Arbeitsspeicher ist für die Ausführung von Anfragen sehr wichtig. 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 Grenzen verbunden sind. Wenn ich jetzt als Analyst auf den Cluster »Yandex.Metrika« zugreife und eine Anfrage stelle, select count from hits, erhalte ich sofort eine Ausnahme, dass ich die Anfrage nicht ausführen kann. Die maximale Anzahl der Zeilen, die ich scannen darf, liegt bei einhundert Milliarden, während insgesamt fünfzig Billionen in einer Tabelle im Cluster vorhanden sind. Das ist die erste Einschränkung.
Angenommen, ich hebe die Begrenzung der Zeilenanzahl auf und führe die Abfrage erneut aus. Dann sehe ich folgende Ausnahme - die Einstellung ist aktiviert. Index nach Datum erzwingen. Ich kann die Abfrage nicht ausführen, wenn ich keinen Datumsbereich angegeben habe. Man sollte nicht erwarten, dass Analysten ihn manuell eingeben. Ein typischer Fall ist, dass ein Datumsbereich geschrieben wurde, bei dem das Ereignisdatum zwischen einer Woche liegt. Und dann wurde einfach die Klammer falsch gesetzt, sodass es anstelle von und ein oder gab — oder URL entspricht. Wenn keine Einschränkungen vorliegen, wird es die URL-Spalte scannen und einfach eine Menge Ressourcen verschwenden.
Darüber hinaus gibt es in ClickHouse zwei Prioritätseinstellungen. Leider sind sie sehr primitiv. Eine davon heißt einfach Priorität. Wenn die Priorität ≠ 0 ist und Abfragen mit einer bestimmten Priorität ausgeführt werden, aber gleichzeitig eine Abfrage mit einer Priorität ausgeführt wird, die kleiner ist – was bedeutet, dass es eine höhere Priorität gibt – dann wird die Abfrage mit dem höheren Prioritätswert, der eine niedrigere Priorität bedeutet, einfach pausiert und funktioniert während dieser Zeit überhaupt nicht.
Dies ist eine sehr grobe Einstellung und eignet sich nicht für Szenarien mit konstanten Lasten auf dem Cluster. Aber wenn Sie kurze, wichtige Anfragen haben und der Cluster hauptsächlich inaktiv ist, könnte diese Einstellung geeignet sein.
Die nächste Prioritätseinstellung heißt OS-Thread-Priorität. Sie legt einfach für alle Ausführungs-Threads der Anfragen einen nice-Wert für den Linux-Scheduler fest. Die Funktionalität ist eher begrenzt, aber sie funktioniert. Wenn der nice-Wert auf das niedrigste gesetzt wird, bedeutet das den höchsten Prioritätswert, und Anfragen mit hoher Priorität können auf -19 gesetzt werden, sodass die CPU niedrigpriorisierte Anfragen etwa viermal weniger verarbeitet als hochpriorisierte.
Außerdem muss die maximale Ausführungszeit für Anfragen eingestellt werden – sagen wir, fünf Minuten. Die Mindestgeschwindigkeit für die Anfrageverarbeitung ist entscheidend. Diese Einstellung gibt es schon lange und sie ist notwendig, um sicherzustellen, dass ClickHouse nicht nur behauptet, dass es nicht stockt, sondern dass dies auch tatsächlich durchgesetzt wird.
Stellen Sie sich vor, Sie konfigurieren: Wenn ein Anfrage weniger als eine Million Zeilen pro Sekunde verarbeitet, sollte das nicht sein. Das schadet unserem guten Ruf und unserer hervorragenden Datenbank. Lassen Sie uns das einfach unterbinden. Es gibt eigentlich zwei Einstellungen. Eine nennt sich min execution speed — in Zeilen pro Sekunde, und die andere heißt timeout before checking min execution speed — standardmäßig fünfzehn Sekunden. Das heißt, fünfzehn Sekunden sind in Ordnung, und wenn es danach weiterhin langsam ist, wird einfach eine Ausnahme geworfen — die Anfrage wird abgebrochen.
Außerdem müssen die Quoten angepasst werden. In ClickHouse gibt es eine eingebaute Möglichkeit zur Quotierung, die den Ressourcenverbrauch zählt. Leider bezieht sich das nicht auf physische Ressourcen wie CPU oder Festplatten, sondern auf logische Ressourcen — die Anzahl der verarbeiteten Anfragen, Zeilen und gelesenen Bytes. Man kann zum Beispiel eine Höchstgrenze von einhundert Anfragen in fünf Minuten und tausend Anfragen pro Stunde festlegen.
Warum ist das wichtig? Weil ein Teil der Analyseanfragen manuell über den ClickHouse-Client ausgeführt wird. Das wird gut funktionieren. Aber wenn in Ihrem Unternehmen erfahrene Analysten sind, schreiben sie ein Skript, und im Skript könnte ein Fehler sein. Dieser Fehler könnte zur Folge haben, dass die Anfrage in einer Endlosschleife ausgeführt wird. Dagegen müssen Sie sich absichern.
Kann man die Ergebnisse einer Anfrage an zehn Clients weitergeben?
Wir haben einige Nutzer, die gerne gleichzeitig mit sehr großen Anfragen kommen. Die Anfrage ist groß und wird im Prinzip schnell ausgeführt, aber aufgrund der hohen Anzahl der gleichzeitigen Anfragen wird es sehr schmerzhaft. Kann man dieselbe Anfrage, die zehn Mal hintereinander eingetroffen ist, einmal ausführen und das Ergebnis an zehn Kunden weitergeben?
Das Problem ist, dass wir keine Ergebnisse aus dem Cache oder den Zwischendaten haben. Es gibt einen Page-Cache des Betriebssystems, der es ermöglicht, Daten nicht erneut von der Festplatte zu lesen, aber leider müssen die Daten dennoch entpackt, deserialisiert und erneut verarbeitet werden.
Wir möchten dies irgendwie vermeiden, sei es durch das Zwischenspeichern von Daten oder durch das Anordnen ähnlicher Anfragen in einer Warteschlange mit einem Ergebnis-Caching. Momentan haben wir einen Pull-Request in der Entwicklung, der das Caching von Anfragen hinzufügt, jedoch nur für Unterabfragen in den Abschnitten 'in' und 'join' — das bedeutet, dass die Lösung noch nicht vollständig ist.
Dennoch haben wir auch mit dieser Situation zu kämpfen. Ein typisches Beispiel sind Anfragen mit Seitenzahlen. Es gibt einen Bericht, der mehrere Seiten hat, und es wird eine Anfrage mit limit 10 ausgeführt. Dann das Gleiche, aber limit 10,10. Dann folgt die nächste Seite. Die Frage ist, warum wir das jedes Mal neu berechnen? Momentan gibt es dafür keine Lösung, und wir können dem nicht entkommen.
Es gibt eine alternative Lösung, die als Sidecar neben ClickHouse eingesetzt wird — .
Kirill Shvakov: In ClickHouse Proxy gibt es einen integrierten Ratenbegrenzer und einen eingebauten Ergebniscache. Dort sind viele Einstellungen vorgenommen worden, da eine ähnliche Aufgabe gelöst wurde. Proxy ermöglicht es, Anfragen zu begrenzen, indem sie in eine Warteschlange eingereiht werden, und es kann eingestellt werden, wie lange die Anfrage-Caches gültig sind. Wenn die Anfragen tatsächlich identisch waren, wird Proxy sie viele Male zurückgeben, aber nur einmal in ClickHouse nachschlagen.
Auch in Nginx gibt es Caching in der kostenlosen Version, und das funktioniert ebenfalls. Nginx hat sogar Konfigurationen, die festlegen, dass, wenn Anfragen gleichzeitig eingehen, andere Anfragen verzögert werden, bis eine bearbeitet ist. Doch in ClickHouse Proxy ist die Konfiguration erheblich besser umgesetzt. Sie wurde speziell für ClickHouse und diese Anfragen entwickelt, wodurch sie besser geeignet ist. Außerdem ist die Installation unkompliziert.
Wie geht man mit asynchronen Operationen und materialisierten Sichten um?
Ein Problem besteht darin, dass Operationen mit dem Replacing-Engine asynchron sind – zunächst werden Daten geschrieben, gefolgt von deren Verdichtung. Wenn sich unter der Tabelle eine materialisierte Sicht mit bestimmten Aggregaten befindet, werden Duplikate in diese geschrieben. Und wenn es keine komplexe Logik gibt, werden die Daten dupliziert. Was kann man dagegen tun?
Eine offensichtliche Lösung wäre, einen Trigger für eine bestimmte Klasse von Materialized Views während der asynchronen Verdichtungsoperation zu implementieren. Gibt es irgendwelche 'Silbergeschosse', Pläne zur Implementierung solcher Funktionen?
Es ist wichtig, sich mit der Funktionsweise der Deduplication auseinanderzusetzen. Das, was ich jetzt erzähle, gehört zwar nicht zur Fragestellung, aber es lohnt sich, dies in Betracht zu ziehen.
Beim Einfügen in eine replizierte Tabelle erfolgt eine vollständige Duplikatsbereinigung der eingefügten Blöcke. Wenn Sie denselben Block, der die gleiche Anzahl an Zeilen in derselben Reihenfolge enthält, erneut einfügen, werden die Daten dedupliziert. Sie erhalten ein „Ok“ als Antwort auf das Insert, aber tatsächlich wird nur ein Datenblock geschrieben, und dieser wird nicht erneut dupliziert.
Dies ist wichtig für die Klarheit. Wenn Sie während des Einfügens ein „Ok“ erhalten, bedeutet das, dass Ihre Daten eingefügt wurden. Wenn Sie einen Fehler von ClickHouse erhalten haben, wurden sie nicht eingefügt, und Sie müssen das Einfügen wiederholen. Wenn während des Einfügens die Verbindung unterbrochen wird, wissen Sie jedoch nicht, ob die Daten eingefügt wurden oder nicht. Die einzige Möglichkeit ist, das Einfügen erneut durchzuführen. Wenn die Daten tatsächlich eingefügt wurden und Sie sie erneut einfügen, erfolgt eine Blockdeduplizierung. Diese ist notwendig, um Duplikate zu vermeiden.
Und es ist auch wichtig, wie es für materialisierte Ansichten funktioniert. Wenn die Daten bei der Einspeisung in die Haupttabelle dedupliziert wurden, werden sie auch nicht in die materialisierte Ansicht übernommen.
Zu Ihrem Anliegen: Ihre Situation ist etwas komplexer, da Sie Duplikate einzelner Zeilen erfassen. Das bedeutet, dass nicht die gesamte Gruppe dupliziert wird, sondern spezifische Zeilen, und diese verdichten sich im Hintergrund. Tatsächlich werden die Daten in der Haupttabelle komprimiert, während die nicht komprimierten Daten in die materialisierte Sicht übernommen werden, und bei Merges wird nichts mit den materialisierten Sichten geschehen. Denn eine materialisierte Sicht funktioniert als Trigger für Insert. Bei anderen Operationen passiert nichts Weiteres mit ihr.
Leider kann ich Ihnen hier nicht weiterhelfen. Es bleibt nur, eine spezifische Lösung für diesen Fall zu finden. Zum Beispiel, ob es auch in einer materialisierten Sicht möglich ist, ein Replacing durchzuführen, und möglicherweise würde das Verfahren zur Deduplication ebenfalls funktionieren. Aber leider funktioniert das nicht immer. Wenn es aggregierend ist, wird es nicht klappen.
Kirill Shvakov: Auch bei uns war das irgendwann eine Herausforderung mit den Anzeigen. Es gab das Problem, dass es Werbeeinblendungen gibt und einige Daten, die wir in Echtzeit anzeigen können – das sind einfach die Impressionen. Diese werden selten dupliziert, aber wenn dies geschieht, fassen wir sie später zusammen. Es gibt jedoch Daten, die man nicht duplizieren kann – Klicks und die gesamte dazugehörige Geschichte. Aber auch diese wollten wir so schnell wie möglich anzeigen.
Wie wurden die materialisierten Ansichten erstellt? Es gibt Ansichten, in die direkt geschrieben wird – die Daten werden in Rohdaten erfasst und in die Views geschrieben. Zu einem bestimmten Zeitpunkt sind die Daten nicht ganz korrekt, sie werden dupliziert und so weiter. Und es gibt einen zweiten Teil der Tabelle, der absolut gleich aussieht wie die materialisierten Ansichten, das heißt, strukturell sind sie identisch. Von Zeit zu Zeit berechnen wir die Daten neu, zählen die Daten ohne Duplikate und schreiben sie in die entsprechenden Tabellen.
Wir haben über die API gearbeitet – manuelle Arbeiten im ClickHouse funktionieren nicht. Die API prüft, wann ich das Datum der letzten Hinzufügung in die Tabelle habe, in der garantiert bereits die richtigen Daten berechnet sind, und sie stellt Anfragen an eine Tabelle sowie an eine andere Tabelle. Aus einer Tabelle wählt sie bis zu einem bestimmten Zeitpunkt und aus der anderen holt sie das, was noch nicht berechnet wurde. Und das funktioniert, aber nicht mit den Mitteln eines einzelnen ClickHouse.
Wenn Sie eine API haben – für Analysten, für Benutzer – dann ist das grundsätzlich eine Option. Sie zählen immer nach, sie rechnen immer um. Das kann einmal täglich oder zu einer anderen Zeit geschehen. Sie wählen selbst den Zeitraum, der für Sie irrelevant und nicht kritisch ist.
ClickHouse hat viele Protokolle. Wie kann ich alles sehen, was im Moment mit dem Server passiert?
ClickHouse verfügt über eine sehr große Anzahl verschiedener Protokolle, und diese Anzahl wächst. In neuen Versionen sind einige davon sogar standardmäßig aktiviert, in älteren Versionen müssen sie bei der Aktualisierung aktiviert werden. Nichtsdestotrotz werden es immer mehr. Ich möchte letztendlich sehen, was gerade mit meinem Server passiert, möglicherweise auf einem zusammenfassenden Dashboard.
Haben Sie oder einer Ihrer Freunde im Team ClickHouse, die ein bestimmtes Funktionalität von fertigen Dashboards unterstützen, die diese Protokolle in Form eines bereits fertiggestellten Produkts darstellen? Letztendlich ist es großartig, die Protokolle in ClickHouse zu betrachten. Aber es wäre noch spannender, wenn das bereits in Form eines Dashboards vorbereitet wäre. Das würde mich wirklich begeistern.
Es gibt Dashboards, allerdings sind sie nicht standardisiert. In unserem Unternehmen nutzen etwa 60 Teams ClickHouse, und das Seltsame ist, dass viele von ihnen Dashboards haben, die sie selbst erstellt haben, und diese unterscheiden sich etwas. Einige Teams verwenden eine interne Installation von „Yandex.Cloud“. Dort gibt es einige fertige Berichte, aber nicht alle erforderlichen. Andere haben ihre eigenen.
Meine Kollegen aus dem ‚Metrik‘-Team haben ihr eigenes Dashboard in Grafana, und ich habe meines auf ihrem Cluster. Ich schaue mir dort Dinge wie Cache Hits für den Caching-Algorithmus an. Und es wird sogar noch komplizierter, da wir unterschiedliche Werkzeuge verwenden. Mein Dashboard habe ich mit einem sehr alten Tool erstellt, das Graphite-web heißt. Das ist absolut nicht schön. Und bis heute benutze ich es, obwohl Grafana wahrscheinlich praktischer und schöner gewesen wäre.
Die Grundlage der Dashboards ist gleich. Es handelt sich um systemrelevante Metriken für den Cluster: CPU, RAM, Festplatte, Netzwerk. Weitere Metriken umfassen die Anzahl gleichzeitiger Anfragen, die Anzahl gleichzeitiger Merges, die Anfragen pro Sekunde, die maximale Anzahl an Datenpartitionen für MergeTree-Tabellen, den Replikations-Soll, die Größe der Replikationswarteschlange, die Anzahl der pro Sekunde eingefügten Zeilen sowie die Anzahl der pro Sekunde eingefügten Blöcke. Dies sind alles Informationen, die nicht aus Logs, sondern aus Metriken stammen.
Wladimir Kolobajew: Alexey, ich möchte das ein wenig anpassen. Es gibt Grafana. Grafana hat eine Datenquelle, die ClickHouse ist. Das heißt, ich kann aus Grafana direkt Anfragen an ClickHouse senden. In ClickHouse gibt es eine Logtabelle, die für alle gleich ist. Ich möchte in Grafana auf diese Logtabelle zugreifen und die Anfragen sehen, die mein Server durchführt. Es wäre großartig, ein solches Dashboard zu haben.
Ich habe es selbst zusammengebastelt. Aber ich frage mich, wenn alles standardisiert ist und Grafana von allen verwendet wird, warum gibt es dann in 'Yandex' kein offizielles Dashboard?
Kirill Shvakov: Tatsächlich wird die Datenquelle, die mit ClickHouse verbunden ist, momentan von Altinity unterstützt. Ich möchte nur eine Richtung angeben, in die man weiter suchen und Fragen stellen kann. Man kann sie fragen, denn "Yandex" ist schließlich diejenige, die ClickHouse entwickelt und nicht die Geschichte darum herum. Altinity ist das Unternehmen, das ClickHouse zurzeit aktiv vorantreibt. Sie werden es nicht aufgeben, sondern weiterhin unterstützen. Um ein Dashboard auf der Grafana-Website hochzuladen, muss man sich einfach nur registrieren und es hochladen – dabei gibt es keine besonderen Probleme.
Alexej Milowidow: Im letzten Jahr wurden viele neue Funktionen zur Profilierung von Anfragen in ClickHouse hinzugefügt. Es gibt Metriken für jede Anfrage zur Ressourcennutzung. Ganz neu ist ein noch detaillierterer Profiler für Anfragen, der zeigt, wo eine Anfrage jede Millisekunde verbringt. Aber um diese Funktion nutzen zu können, muss ich den Konsolen-Client öffnen und die Anfrage eingeben, die ich ständig vergesse. Ich habe sie irgendwo gespeichert und vergesse immer wieder, wo genau.
Ich hätte gern ein Tool, das einfach aufzeigt – hier sind Ihre komplexen Abfragen, gruppiert nach Abfragekategorien. Ich klicke auf eine und bekomme die Information, dass diese besonders ressourcenintensiv ist. Ein solches Werkzeug gibt es momentan nicht. Es ist tatsächlich etwas merkwürdig, dass ich, wenn mich Leute fragen: "Gibt es fertige Dashboards für Grafana?", antworte: "Besuchen Sie die Grafana-Website, im Community-Bereich gibt es 'Dashboards', dort finden Sie eines von Dima oder eines von Kostya. Was das genau ist, weiß ich nicht, ich habe es selbst nicht genutzt."
Wie kann ich auf die Merges einwirken, damit der Server nicht in OOM abstürzt?
Ich habe eine Tabelle, die nur eine Partition hat, und zwar ReplacingMergeTree. Ich schreibe seit vier Jahren Daten hinein. Ich musste einen Alter durchführen und einige Daten löschen.
Ich habe das gemacht, und während der Verarbeitung dieser Anfrage wurde der gesamte Speicher auf allen Servern im Cluster verbraucht, wodurch alle Server des Clusters in OOM gingen. Danach starteten sie gemeinsam neu, fingen an, den Merge derselben Operation, dieses Datenblocks, durchzuführen, und stürzten erneut in OOM ab. Dann starteten sie wieder und fielen erneut aus. Dieses Szenario wiederholte sich ständig.
Es stellte sich heraus, dass dies tatsächlich ein Fehler war, den die Jungs behoben haben. Das ist großartig, vielen Dank. Aber der Nachgeschmack bleibt. Und jetzt, wenn ich darüber nachdenke, dass ich einen Merge in der Tabelle durchführen muss, frage ich mich – warum kann ich nicht irgendwie Einfluss auf diese Merges nehmen? Zum Beispiel, sie bezüglich der benötigten RAM-Menge oder grundsätzlich in der Anzahl, die spezifisch diese Tabelle verarbeitet, zu begrenzen.
Ich habe eine Tabelle namens „Metrix“, bitte bearbeite sie für mich in zwei Streams. Es ist nicht nötig, zehn oder fünf Merges parallel zu erzeugen, mache es in zwei. Ich denke, dass ich mit zwei genug Speicher habe, während es möglicherweise nicht für die Verarbeitung von zehn ausreicht. Warum bleibt die Angst? Weil die Tabelle wächst, und irgendwann werde ich in die Situation kommen, dass dies nicht mehr wegen eines Fehlers, sondern weil die Daten in so großer Menge geändert werden, dass ich einfach nicht genug RAM auf dem Server habe. Und dann wird der Server beim Merge aufgrund von OOM ausfallen. Während ich die Mutation zurücknehmen kann, die Merges jedoch nicht.
Wissen Sie, bei Merges wird der Server nicht in OOM (Out of Memory) fallen, da beim Mergen nur ein kleinerer Bereich an Daten im Arbeitsspeicher verwendet wird. Daher wird alles gut sein, unabhängig von der Datenmenge.
Wladimir Kolobajew: Das ist gut. Hier ist der Punkt, dass, nachdem ich den Bug-Fix gemacht habe, ich mir die neue Version heruntergeladen habe. In einer anderen, kleineren Tabelle mit vielen Partitionen habe ich eine ähnliche Operation durchgeführt. Während des Mergers wurden etwa 100 GB RAM auf dem Server verbraucht. Ich hatte 150 GB belegt, 100 GB wurden verbraucht, und es blieb ein Fenster von 50 GB übrig, deshalb bin ich nicht in OOM gefallen.
Was schützt mich derzeit davor, in OOM zu fallen, wenn er tatsächlich 100 GB Arbeitsspeicher benötigt? Wie sollte ich in einer Situation verfahren, in der der Arbeitsspeicher bei den Merges plötzlich aufgebraucht ist?
Alexej Milowidow: Es gibt ein Problem, dass der Speicherverbrauch bei Merges nicht begrenzt ist. Ein weiteres Problem besteht darin, dass, wenn ein Merge festgelegt wurde, er ausgeführt werden muss, da er im Replikationsprotokoll vermerkt ist. Das Replikationsprotokoll enthält die Schritte, die erforderlich sind, um eine Kopie in einen konsistenten Zustand zu versetzen. Wenn keine manuellen Eingriffe durchgeführt werden, um das Replikationsprotokoll zurückzusetzen, muss der Merge in jedem Fall durchgeführt werden.
Natürlich wäre es sinnvoll, eine Beschränkung des Arbeitsspeichers zu haben, die ‚für alle Fälle‘ speziell vor OOM schützt. Das würde zwar nicht helfen, den Merge abzuschließen – er würde wieder gestartet, einen bestimmten Punkt erreichen, eine Ausnahme werfen und dann erneut beginnen – aus diesem Vorgehen ergibt sich nichts Positives. Aber grundsätzlich wäre die Einführung dieser Begrenzung nützlich.
Wie wird die Entwicklung des Golang-Treibers für ClickHouse aussehen?
Der Golang-Treiber, den Kirill Shvakov geschrieben hat, wird offiziell von dem ClickHouse-Team unterstützt. , ist er jetzt groß und echt.
Eine kleine Anmerkung. Es gibt ein großartiges und beliebtes Speichersystem für unendliche Ordnung – Vertica. Auch sie haben einen offiziellen Python-Treiber, der von den Entwicklern von Vertica unterstützt wird. Es kam jedoch schon mehrmals vor, dass die Versionen des Speichersystems und des Treibers erheblich auseinanderdrifteten, sodass der Treiber irgendwann nicht mehr funktionierte. Ein weiterer Punkt ist, dass die Unterstützung dieses offiziellen Treibers, so scheint es, über das System "Nippel" läuft – du schreibst ihnen ein Issue, und es bleibt ewig hängen.
Ich habe zwei Fragen. Der Golang-Treiber von Kirill ist mittlerweile die nahezu standardmäßige Methode, um aus Golang mit ClickHouse zu kommunizieren. Es könnte sein, dass jemand immer noch über die HTTP-Schnittstelle kommuniziert, weil ihm das so besser gefällt. Wie wird die Entwicklung dieses Treibers ablaufen? Wird sie sich mit den möglichen Breaking Changes im Speicher selbst synchronisieren? Und wie erfolgt die Bearbeitung von Issues?
Kirill Shvakov: Erstens – wie alles bürokratisch geregelt ist. Dieser Punkt wurde nicht besprochen, daher kann ich dazu nichts sagen.
Um auf die Frage zu dem Issue zu antworten, ist eine kurze Geschichte zum Treiber nötig. Ich habe in einem Unternehmen gearbeitet, in dem es viele Daten gab. Es handelte sich um ein Werbesystem mit einer riesigen Menge an Ereignissen, die irgendwo gespeichert werden mussten. Irgendwann tauchte ClickHouse auf. Wir haben die Daten dorthin übertragen, und anfangs lief alles gut, bis ClickHouse irgendwann abstürzte. Zu diesem Zeitpunkt waren wir der Meinung, dass wir es nicht mehr benötigten.
Ein Jahr später kehrten wir zur Idee zurück, ClickHouse zu nutzen, und wir mussten einen Weg finden, Daten dorthin zu schreiben. Die Rahmenbedingungen waren klar – die Hardware war sehr schwach und die Ressourcen waren begrenzt. Aber so haben wir immer gearbeitet, also haben wir uns den nativen Protokollansatz angesehen.
Da wir mit Go arbeiteten, war klar, dass wir einen Treiber in Go benötigten. Ich habe fast Vollzeit daran gearbeitet – das war mein Arbeitsauftrag. Bis zu einem bestimmten Punkt haben wir ihn weiterentwickelt, und grundsätzlich ging niemand davon aus, dass jemand außer uns ihn nutzen würde. Dann kam CloudFlare mit genau demselben Problem, und eine Zeit lang haben wir sehr reibungslos mit ihnen zusammengearbeitet, weil sie die gleichen Herausforderungen hatten. Wir haben sowohl in ClickHouse selbst als auch im Treiber daran gearbeitet.
I eventually stopped working on it because my involvement with ClickHouse and its operation changed a bit. Therefore, issues remain open. Occasionally, people commit to the repository when they need something themselves. Then I look at the pull requests and sometimes even make some adjustments myself, but that happens rarely.
I want to return to the driver. A few years ago, when all of this started, ClickHouse was different and had other capabilities. Now, there's a clearer idea of how to redo the driver to make it better. If this happens, version 2 will definitely be incompatible due to accumulated workarounds.
I don't know how to organize this. I don't have much time myself. If some people will work on improving the driver, I can help them and explain what to do. However, the active participation of 'Yandex' in the project development has not been discussed so far.
Alexej Milowidow: Tatsächlich gibt es derzeit keine Bürokratie bezüglich dieser Treiber. Das Einzige ist, dass sie in eine offizielle Organisation ausgegliedert sind, das heißt, dieser Treiber ist als offizielle Standardlösung für Go anerkannt. Es gibt einige andere Treiber, aber die werden separat behandelt.
Wir haben intern keine Entwicklung für diese Treiber. Die Frage ist, ob wir eine separate Person anstellen können, die nicht speziell für diesen Treiber zuständig ist, sondern für die Entwicklung aller Community-Treiber, oder ob wir jemanden extern finden können.
Der externe Wörterbuchdienst wird nach einem Neustart mit aktivierter lazy_load-Einstellung nicht gestartet. Was sollen wir 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, nachdem ein Benutzer darauf zugreift. Und beim ersten Zugriff wird ein Fehler ausgegeben. Gibt es eine Möglichkeit, die Wörterbücher automatisch mit ClickHouse zu laden, oder müssen wir immer selbst deren Verfügbarkeit überwachen, damit die Benutzer keine Fehler erhalten?
Vielleicht haben wir eine alte Version von ClickHouse, weshalb das Wörterbuch nicht automatisch geladen wurde. Kann das sein?
Erstens können Wörterbücher mit Hilfe einer Anweisung zwangsweise geladen werden. System Wörterbücher neu laden. Zweitens, zur Fehlerbehebung – wenn das Wörterbuch bereits geladen ist, arbeiten die Anfragen mit den Daten, die geladen wurden. Wenn das Wörterbuch noch nicht geladen wurde, wird es während der Anfrage geladen.
Für schwere Wörterbücher ist das nicht sehr praktisch. Zum Beispiel muss man eine Million Zeilen aus MySQL abrufen. Jemand führt einen einfachen Select aus, aber dieser Select wartet auf die Millionen Zeilen. Es gibt hier zwei Lösungen. Erstens – schalten Sie lazy_load aus. Zweitens – wenn der Server hochgefahren wird, bevor er belastet wird, sollte man System Wörterbuch neu laden oder einfach eine Anfrage ausführen, 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 sie nicht automatisch lädt.
Auf die letzte Frage lautet die Antwort – entweder ist die Version alt oder es muss debuggt werden.
Wie geht man damit um, dass das system reload dictionaries keinen der vielen Wörterbücher lädt, wenn auch nur eines davon mit einem Fehler ausfällt?
Gibt es noch eine Frage zum Systemreload von Wörterbüchern? Wir haben zwei Wörterbücher - eines lädt nicht, das andere lädt. In diesem Fall lädt der Systemreload der Wörterbücher keines der Wörterbücher, und wir müssen das spezifische Wörterbuch manuell nach dem Namen mit "system reload dictionary" nachladen. Hängt das auch mit der Version von ClickHouse zusammen?
Ich möchte Sie erfreuen. Dieses Verhalten hat sich geändert. Wenn Sie ClickHouse aktualisieren, wird es sich ebenfalls ändern. Wenn Sie mit dem aktuellen Verhalten unzufrieden sind, System Wörterbücher neu laden, aktualisieren Sie, und wir hoffen, dass es sich in die richtige Richtung verändert.
Gibt es eine Möglichkeit, die Anmeldeinformationen in der ClickHouse-Konfiguration zu konfigurieren, ohne sie bei Fehlern offenzulegen?
Die nächste Frage betrifft die Fehler, die mit dem Wörterbuch zusammenhängen, insbesondere die Zugangsdaten. Wir haben die Zugangsdaten in der ClickHouse-Konfiguration für das Wörterbuch festgelegt, und bei einem Fehler erhalten wir diese Zugangsdaten und das Passwort als Antwort.
Wir haben diesen Fehler behoben, indem wir die Zugangsdaten in die ODBC-Treiberkonfiguration ausgegliedert haben. Gibt es eine Möglichkeit, die Zugangsdaten in der ClickHouse-Konfiguration zu setzen, ohne diese bei Fehlern preiszugeben?
Die Lösung ist einfach: Diese Anmeldedaten in der odbc.ini angeben und im ClickHouse nur den ODBC-Datenquellennamen eingeben. Für andere Quellen wird dies nicht der Fall sein – weder für das MySQL-Dictionary noch für andere sollten Sie ein Passwort in der Fehlermeldung sehen. Ich werde auch nachsehen, ob es das für ODBC gibt – falls ja, sollte das einfach entfernt werden.
Bonus: Hintergründe für Zoom-Meetings von den Zusammenkünften
Ein Klick auf das Bild öffnet für die hartnäckigsten Leser Bonushintergründe von unseren Treffen. Löschen Sie das Feuer zusammen mit den Avito-Technologie-Maskottchen, besprechen Sie sich mit Kolleginnen und Kollegen aus dem Büro des Systemadministrators oder einem Old-School-Computerclub und führen Sie ein Daily-Meeting unter der Brücke vor einer Graffiti-Wand durch.
Quelle: habr.com
