Passer de Redshift à ClickHouse



Pendant longtemps, iFunny a utilisé Redshift comme base de données pour les événements qui se produisent dans les services backend et les applications mobiles. Il a été choisi parce qu'au moment de la mise en œuvre, il n'y avait, dans l'ensemble, aucune alternative comparable en termes de coût et de commodité.

Cependant, tout a changé après la sortie publique de ClickHouse. Nous l'avons étudié pendant longtemps, comparé le coût, estimé l'architecture approximative, et enfin, cet été, nous avons décidé de voir à quel point il nous était utile. Dans cet article, vous découvrirez le problème que Redshift nous a aidé à résoudre et comment nous avons déplacé cette solution vers ClickHouse.

Le problème


iFunny avait besoin d'un service similaire à Yandex.Metrica, mais exclusivement pour la consommation domestique. Je vais vous expliquer pourquoi.

Les clients externes écrivent des événements. Il peut s'agir d'applications mobiles, de sites Web ou de services backend internes. Il est très difficile pour ces clients d'expliquer que le service d'accueil événementiel est actuellement indisponible, «essayez de l'envoyer en 15 minutes ou en une heure». Il y a beaucoup de clients, ils veulent envoyer des événements tout le temps et ne peuvent pas attendre du tout.

Contrairement à eux, il existe des services internes et des utilisateurs assez tolérants à cet égard: ils peuvent fonctionner correctement même avec un service d'analyse inaccessible. Et la plupart des métriques du produit et les résultats des tests A / B sont généralement judicieux à regarder une seule fois par jour, voire moins souvent. Par conséquent, les exigences de lecture sont assez faibles. En cas d'accident ou de mise à jour, nous pouvons nous permettre d'être inaccessibles ou incohérents en lecture pendant plusieurs heures voire plusieurs jours (dans un cas particulièrement négligé).

Si nous parlons de chiffres, nous devons prendre environ cinq milliards d'événements (300 Go de données compressées) par jour, tout en stockant les données pendant trois mois sous une forme «à chaud», accessible pour les requêtes SQL et dans une «froide» pendant deux ans ou plus, mais pour qu'en quelques jours nous puissions les transformer en "chaud".

Fondamentalement, les données sont une collection d'événements classés par heure. Il existe environ trois cents types d'événements, chacun ayant son propre ensemble de propriétés. Il existe encore des données provenant de sources tierces qui doivent être synchronisées avec la base de données analytiques: par exemple, une collection d'installations d'applications à partir de MongoDB ou un service AppsFlyer externe.

Il s'avère que pour la base de données, nous avons besoin d'environ 40 To de disque et pour le stockage «froid» - environ 250 To de plus.

Redshift Solution




Il existe donc des clients mobiles et des services backend à partir desquels vous devez recevoir des événements. Le service HTTP accepte les données, effectue la validation minimale, collecte les événements sur le disque local dans des fichiers regroupés par minute, les comprime immédiatement et les envoie au compartiment S3. La disponibilité de ce service dépend de la disponibilité des serveurs avec l'application et AWS S3. Les applications ne stockent pas l'état, elles sont donc facilement équilibrées, mises à l'échelle et échangées. S3 est un service de stockage de fichiers relativement simple avec une bonne réputation et une bonne disponibilité, vous pouvez donc vous y fier.

Ensuite, vous devez en quelque sorte livrer les données à Redshift. Tout est assez simple ici: Redshift a un importateur S3 intégré, qui est la méthode recommandée pour charger les données. Par conséquent, une fois toutes les 10 minutes, un script démarre qui se connecte à Redshift et lui demande de télécharger les données en utilisant le préfixe s3://events-bucket/main/year=2018/month=10/day=14/10_3*

Afin de surveiller l'état de la tâche de téléchargement, nous utilisons Apache Airflow : il vous permet de répéter l'opération en cas d'erreurs et d'avoir un historique d'exécution clair, ce qui est important pour un grand nombre de ces tâches. Et en cas de problème, vous pouvez répéter le téléchargement pendant quelques intervalles de temps ou télécharger les données «froides» de S3 il y a un an.

Dans le même Airflow, de la même manière, selon le planning, les scripts fonctionnent qui se connectent à la base de données et effectuent des téléchargements périodiques à partir de référentiels externes, ou construisent des agrégations d'événements sous la forme INSERT INTO ... SELECT ...

Redshift a de faibles garanties de disponibilité. Une fois par semaine, jusqu'à une demi-heure (la fenêtre de temps est spécifiée dans les paramètres), AWS peut arrêter la mise à jour du cluster ou tout autre travail planifié. En cas de panne sur un nœud, le cluster devient également indisponible jusqu'à la restauration de l'hôte. Cela prend généralement environ 15 minutes et se produit environ une fois tous les six mois. Dans le système actuel, ce n'est pas un problème, il a été initialement conçu pour que la base soit périodiquement indisponible.

Sous Redshift, 4 instances ds2.8xlarge ont été utilisées (36 CPU, 16 TB HDD), ce qui nous donne au total 64 TB d'espace disque.

Le dernier point est la sauvegarde. La planification de la sauvegarde peut être spécifiée dans les paramètres du cluster et elle fonctionne correctement.

ClickHouse Transition Motivation


Bien sûr, s'il n'y avait pas de problèmes, personne n'aurait pensé à migrer vers ClickHouse. Mais ils l'étaient.

Si vous regardez le schéma de stockage ClickHouse avec le moteur MergeTree et Redshift, vous pouvez voir que leur idéologie est très similaire. Les deux bases de données sont en colonnes, fonctionnent correctement avec un grand nombre de colonnes et compressent très bien les données sur le disque (et dans Redshift, vous pouvez configurer les types de compression pour chaque colonne individuelle). Même les données sont stockées de la même manière: elles sont triées par clé primaire, ce qui vous permet de lire uniquement des blocs spécifiques et de ne pas conserver des index séparés en mémoire, ce qui est important lorsque vous travaillez avec de grandes quantités de données.

La différence essentielle, comme toujours, réside dans les détails.

Table journalière


Le tri des données sur le disque et leur suppression dans Redshift se produisent lorsque vous effectuez:
 VACUUM <tablename> 
Dans ce cas, le processus de vide fonctionne avec toutes les données de ce tableau. Si vous stockez des données pour les trois mois dans une table, ce processus prend un temps indécent et vous devez l'exécuter au moins quotidiennement, car les anciennes données sont supprimées et de nouvelles sont ajoutées. J'ai dû créer des tableaux séparés pour chaque jour et les combiner via la vue, et ce n'est pas seulement la difficulté de faire pivoter et de prendre en charge cette vue, mais aussi de ralentir les requêtes. Sur demande, à en juger par expliquer, toutes les tables ont été scannées. Et bien que la numérisation d'une table prenne moins d'une seconde, avec une quantité de 90 pièces, il s'avère que toute requête prend au moins une minute. Ce n'est pas très pratique.

Doublons


Le problème suivant est les doublons. D'une manière ou d'une autre, lors de la transmission de données sur un réseau, il existe deux options: soit perdre des données, soit recevoir des doublons. Nous ne pouvions pas perdre de messages, par conséquent, nous nous sommes simplement réconciliés avec le fait qu'un petit pourcentage des événements seraient dupliqués. Vous pouvez supprimer des doublons par jour en créant une nouvelle table, en y insérant des données de l'ancienne, où en utilisant la fonction de fenêtre vous avez supprimé des lignes avec un ID en double, en supprimant l'ancienne table et en renommant la nouvelle. Puisqu'il y avait une vue au-dessus des tables quotidiennes, il fallait ne pas l'oublier et la supprimer pour le moment de renommer les tables. Dans ce cas, il était également nécessaire de surveiller les verrous, sinon, dans le cas d'une requête qui bloquait la vue ou l'une des tables, ce processus pouvait être traîné longtemps.

Surveillance et maintenance


Pas une seule requête dans Redshift ne prend moins de quelques secondes. Même si vous voulez simplement ajouter un utilisateur ou voir une liste des demandes actives, vous devrez attendre quelques dizaines de secondes. Bien sûr, vous pouvez tolérer, et pour cette classe de bases de données, cela est acceptable, mais en fin de compte, cela se traduit par un tas de temps perdu.

Coût


Selon nos calculs, le déploiement de ClickHouse sur des instances AWS avec exactement les mêmes ressources est exactement la moitié du prix. Bien sûr, il devrait en être ainsi, car en utilisant Redshift, vous obtenez une base de données prête à l'emploi à laquelle vous pouvez vous connecter avec n'importe quel client PostgreSQL juste après avoir cliqué sur quelques boutons dans la console AWS, et AWS fera le reste pour vous. Mais ça vaut le coup? Nous avons déjà l'infrastructure, nous semblons être en mesure de faire des sauvegardes, la surveillance et la configuration, et nous le faisons pour un tas de services internes. Pourquoi ne pas vous attaquer au support ClickHouse?

Processus de transition


Tout d'abord, nous avons créé une petite installation ClickHouse à partir d'une seule machine, où nous avons commencé à télécharger périodiquement, à l'aide des outils intégrés, des données à partir de S3. Ainsi, nous avons pu tester nos hypothèses sur la vitesse et les capacités de ClickHouse.

Après quelques semaines de tests sur une petite copie des données, il est devenu clair que pour remplacer Redshift par Clickhouse, plusieurs problèmes devaient être résolus:

  • sur quels types d'instances et de disques déployer;
  • utiliser la réplication?
  • comment installer, configurer et exécuter;
  • comment faire le suivi;
  • quel genre de régime sera;
  • comment fournir des données à partir de S3;
  • Comment réécrire toutes les requêtes de SQL standard à non standard?

Types d'instances et de disques . En ce qui concerne le nombre de processeurs, disque et mémoire, ils ont décidé de s'appuyer sur l'installation actuelle de Redshift. Il y avait plusieurs options, y compris les instances i3 avec des disques NVMe locaux, mais nous avons décidé de nous arrêter à r5.4xlarge et le stockage sous la forme de 8T ST1 EBS pour chaque instance. Selon les estimations, cela aurait dû donner des performances comparables à Redshift pour la moitié du coût. Dans le même temps, en raison de l'utilisation de disques EBS, nous obtenons des sauvegardes et une restauration simples via des instantanés de disques, presque comme dans Redshift.

Réplication . Comme nous sommes partis de ce qui est déjà dans Redshift, nous avons décidé de ne pas utiliser de réplication. De plus, cela ne nous oblige pas à étudier immédiatement ZooKeeper, qui n'est pas encore dans l'infrastructure, mais c'est formidable qu'il soit désormais possible de faire de la réplication à la demande.

L'installation C'est la partie la plus simple. Un rôle suffisamment petit pour Ansible, qui installera des packages RPM prêts à l'emploi et effectuera la même configuration sur chaque hôte.

Suivi Pour surveiller tous les services, Prometheus est utilisé avec Telegraf et Grafana.Par conséquent, ils ont simplement placé des agents Telegraf sur des hôtes avec ClickHouse, collecté un tableau de bord à Grafana, qui montrait la charge actuelle du serveur par processeur, mémoire et disques. Grâce au plugin pour Grafana, nous avons apporté à ce tableau de bord les demandes actives actuelles pour le cluster, le statut des importations depuis S3 et d'autres choses utiles. Il s'est avéré encore meilleur et plus informatif (et nettement plus rapide) que le tableau de bord qui a donné la console AWS.

Schéma . L'une de nos principales erreurs dans Redshift a été de ne mettre que les principaux champs d'événement dans des colonnes distinctes et d'ajouter les champs qui sont rarement utilisés pour ajouter
dans une grande propriété de colonne. D'une part, cela nous a donné la flexibilité de changer les champs aux étapes initiales, quand nous ne savions pas exactement quels événements nous allions collecter, avec quelles propriétés, de plus, ils changeaient 5 fois par jour. Et d'autre part, les demandes pour une grande colonne de propriétés ont pris de plus en plus de temps. Dans ClickHouse, nous avons décidé de faire la bonne chose tout de suite, nous avons donc collecté toutes les colonnes possibles et entré le type optimal pour elles. Le résultat est un tableau avec environ deux cents colonnes.

La tâche suivante consistait à choisir le bon moteur de stockage et de partitionnement.
Ils n'ont plus pensé au partitionnement, mais ont fait de même que dans Redshift - une partition pour chaque jour, mais maintenant toutes les partitions sont une table, qui
accélère considérablement les demandes et simplifie la maintenance. Le moteur de stockage a été pris par ReplacingMergeTree, car il vous permet de supprimer les doublons d'une partition particulière, simplement en faisant OPTIMIZE ... FINAL . De plus, le schéma de partitionnement quotidien permet, en cas d'erreurs ou d'accidents, de ne travailler qu'avec des données pendant une journée, pas un mois, ce qui est beaucoup plus rapide.

Livraison des données de s3 à ClickHouse . Ce fut l'un des processus les plus longs. Cela n'a tout simplement pas fonctionné en effectuant le chargement par les outils ClickHouse intégrés, car les données sur S3 sont en JSON, chaque champ doit être extrait dans son propre jsonpath, comme nous l'avons fait dans Redshift, et parfois nous devons également utiliser la transformation: par exemple, l'UUID d'un message provenant d'un enregistrement standard sous la forme DD96C92F-3F4D-44C6-BCD3-E25EB26389E9 convertir en octets et mettre en type FixedString (16).

Je voulais avoir un service spécial similaire à ce que nous avions dans Redshift en tant que commande COPY . Ils n'ont rien trouvé de prêt, j'ai donc dû le faire. Vous pouvez écrire un article séparé sur son fonctionnement, mais en bref, il s'agit d'un service HTTP déployé sur chaque hôte avec ClickHouse. Vous pouvez vous référer à l'un d'eux. Les paramètres de demande spécifient le préfixe S3 à partir duquel les fichiers sont extraits, la liste jsonpath pour la conversion de JSON en un ensemble de colonnes, ainsi qu'un ensemble de conversions pour chaque colonne. Le serveur auquel la demande est arrivée commence à analyser les fichiers sur S3 et à distribuer le travail d'analyse aux autres hôtes. Dans le même temps, il est important pour nous que les lignes qui n'ont pas pu être importées, ainsi que l'erreur, soient ajoutées à une table ClickHouse distincte. Cela aide beaucoup à enquêter sur les problèmes et les bogues dans le service de réception d'événements et les clients qui génèrent ces événements. Avec le placement de l'importateur directement sur les hôtes de la base de données, nous avons utilisé ces ressources qui, en règle générale, sont inactives, car les demandes complexes ne tournent pas 24 heures sur 24. Bien sûr, s'il y a plus de demandes, vous pouvez toujours prendre le service de l'importateur sur des hôtes séparés.

Il n'y a pas eu de gros problèmes avec l'importation de données à partir de sources externes. Dans ces scripts qui l'étaient, ils ont juste changé la destination de Redshift à ClickHouse.

Il y avait une option pour connecter MongoDB sous la forme d'un dictionnaire et ne pas faire de copies quotidiennes. Malheureusement, cela ne convenait pas, car le dictionnaire doit être placé en mémoire, et la taille de la plupart des collections dans MongoDB ne le permet pas. Mais les dictionnaires nous ont également été utiles: leur utilisation est très pratique pour connecter les bases de données GeoIP de MaxMind et les utiliser dans les requêtes. Pour cela, nous utilisons les fichiers de mise en page ip_trie et CSV fournis par le service. Par exemple, la configuration du dictionnaire geoip_asn_blocks_ipv4 ressemble à ceci:

 <dictionaries> <dictionary> <name>geoip_asn_blocks_ipv4</name> <source> <file> <path>GeoLite2-ASN-Blocks-IPv4.csv</path> <format>CSVWithNames</format> </file> <\/source> <lifetime>300</lifetime> <layout> <ip_trie /> </layout> <structure> <key> <attribute> <name>prefix</name> <type>String</type> </attribute> </key> <attribute> <name>autonomous_system_number</name> <type>UInt32</type> <null_value>0</null_value> </attribute> <attribute> <name>autonomous_system_organization</name> <type>String</type> <null_value>?</null_value> </attribute> </structure> </dictionary> </dictionaries> 

Il suffit de mettre cette configuration dans /etc/clickhouse-server/geoip_asn_blocks_ipv4_dictionary.xml , après quoi vous pouvez faire des requêtes dans le dictionnaire pour obtenir le nom du fournisseur par adresse IP:

 SELECT dictGetString('geoip_asn_blocks_ipv4', 'autonomous_system_organization', tuple(IPv4StringToNum('192.168.1.1'))); 

Modifier le schéma de données . Comme mentionné ci-dessus, nous avons décidé de ne pas encore utiliser la réplication, car nous pouvons maintenant nous permettre de devenir inaccessibles en cas d'accident ou de travail planifié, et une copie des données est déjà sur s3 et nous pouvons la transférer vers ClickHouse dans un délai raisonnable. S'il n'y a pas de réplication, ils n'ont pas développé ZooKeeper et l'absence de ZooKeeper conduit également à l'impossibilité d'utiliser l'expression ON CLUSTER dans les requêtes DDL. Ce problème a été résolu par un petit script python qui se connecte à chaque hôte ClickHouse (il n'y en a que huit jusqu'à présent) et exécute la requête SQL spécifiée.

Prise en charge SQL incomplète dans ClickHouse . Le processus de transfert des requêtes de la syntaxe Redshift vers la syntaxe ClickHouse s'est déroulé parallèlement au développement de l'importateur et a été principalement traité par une équipe d'analystes. Curieusement, mais le problème n'était même pas dans le JOIN, mais dans les fonctions de la fenêtre. Pour comprendre comment cela peut être fait via des tableaux et des fonctions lambda, cela a pris plusieurs jours. Il est bon que ce problème soit souvent traité dans les rapports sur ClickHouse, dont il existe un grand nombre, par exemple events.yandex.ru/lib/talks/5420 . À ce stade, les données étaient déjà écrites à la fois à deux endroits: à la fois dans Redshift et dans le nouveau ClickHouse, donc lorsque nous avons transféré les demandes, nous avons comparé les résultats. La comparaison de la vitesse a été problématique, car nous avons supprimé une grande colonne de propriétés, et la plupart des requêtes ont commencé à fonctionner uniquement avec les colonnes nécessaires, ce qui, bien sûr, a considérablement augmenté, mais les requêtes auxquelles la colonne des propriétés n'a pas participé, ont fonctionné de la même manière, ou un peu plus vite.

En conséquence, nous avons obtenu le schéma suivant:



Résultats


En fin de compte, nous avons obtenu les avantages suivants:

  • Une table au lieu de 90
  • Les demandes de service sont exécutées en millisecondes
  • Le coût a diminué de moitié
  • Suppression facile des événements en double

Il existe également des inconvénients pour lesquels nous sommes prêts:

  • En cas d'accident, vous devrez réparer vous-même le cluster
  • Les modifications de schéma doivent maintenant être effectuées sur chaque hôte séparément
  • La mise à jour vers de nouvelles versions devra se faire vous-même

Nous ne pouvons pas comparer la vitesse des demandes de front, car le schéma de données a considérablement changé. De nombreuses requêtes sont devenues plus rapides, simplement parce qu'elles lisent moins de données sur le disque. Dans le bon sens, un tel changement a dû être effectué dans Redshift, mais il a été décidé de le combiner avec la migration vers ClickHouse.

La migration et la préparation ont duré environ trois mois. Elle a marché du début juillet à la fin septembre et a exigé la participation de deux personnes. Le 27 septembre, nous avons désactivé Redshift et depuis lors, nous ne travaillons que sur ClickHouse. Il s'avère, déjà un peu plus de deux mois. Le terme est court, mais n'a jusqu'à présent jamais rencontré de perte de données ou de bogue critique, à cause duquel l'ensemble du cluster se lèverait. Nous attendons les mises à jour des nouvelles versions!

Source: https://habr.com/ru/post/fr433346/


All Articles