Base de données KDB+ : de la finance à la Formule 1

KDB+, produit d'entreprise KX est une base de données en colonnes extrêmement rapide et largement connue dans les cercles étroits, conçue pour stocker des séries chronologiques et des calculs analytiques basés sur celles-ci. Au départ, il était (et est) très populaire dans le secteur financier - toutes les 10 plus grandes banques d'investissement et de nombreux fonds spéculatifs, bourses et autres organisations bien connus l'utilisent. Récemment, KX a décidé d'élargir sa clientèle et propose désormais des solutions dans d'autres domaines où il existe une grande quantité de données, organisées dans le temps ou non - télécommunications, bioinformatique, fabrication, etc. Ils sont également devenus partenaires de l'équipe Aston Martin Red Bull Racing en Formule 1, où ils aident à collecter et à traiter les données des capteurs des voitures et à analyser les tests en soufflerie. Dans cet article, je souhaite vous expliquer quelles fonctionnalités de KDB+ le rendent ultra-performant, pourquoi les entreprises sont prêtes à y consacrer beaucoup d'argent et, enfin, pourquoi ce n'est pas vraiment une base de données.
 
Base de données KDB+ : de la finance à la Formule 1
 
Dans cet article, je vais essayer de vous expliquer en général ce qu'est KDB+, quelles sont ses capacités et ses limites, et quels sont ses avantages pour les entreprises qui souhaitent traiter de grandes quantités de données. Je n'entrerai pas dans les détails de l'implémentation de KDB+ ni dans les détails de son langage de programmation Q. Ces deux sujets sont très vastes et méritent des articles séparés. De nombreuses informations sur ces sujets peuvent être trouvées sur code.kx.com, y compris un livre sur Q - Q For Mortals (voir lien ci-dessous).

Quelques termes

  • Base de données en mémoire. Une base de données qui stocke les données dans la RAM pour un accès plus rapide. Les avantages d'une telle base de données sont clairs, mais les inconvénients sont la possibilité de perte de données et la nécessité de disposer de beaucoup de mémoire sur le serveur.
  • Base de données en colonnes. Une base de données dans laquelle les données sont stockées colonne par colonne plutôt que enregistrement par enregistrement. Le principal avantage d'une telle base de données est que les données d'une colonne sont stockées ensemble sur le disque et en mémoire, ce qui en accélère considérablement l'accès. Il n'est pas nécessaire de charger des colonnes qui ne sont pas utilisées dans la requête. Le principal inconvénient est qu’il est difficile de modifier et de supprimer des enregistrements.
  • Des séries chronologiques. Données avec une colonne de date ou d'heure. En règle générale, l'ordre temporel est important pour ces données, afin que vous puissiez facilement déterminer quel enregistrement précède ou suit l'enregistrement actuel, ou appliquer des fonctions dont les résultats dépendent de l'ordre des enregistrements. Les bases de données classiques sont construites sur un principe complètement différent : représenter une collection d'enregistrements comme un ensemble, où l'ordre des enregistrements n'est, en principe, pas défini.
  • Vecteur. Dans le contexte de KDB+, il s'agit d'une liste d'éléments du même type atomique, par exemple des nombres. En d’autres termes, un ensemble d’éléments. Les tableaux, contrairement aux listes, peuvent être stockés de manière compacte et traités à l'aide d'instructions de processeur vectoriel.

 

Les informations historiques

KX a été fondée en 1993 par Arthur Whitney, qui travaillait auparavant chez Morgan Stanley Bank sur le langage A+, le successeur de l'APL - un langage très original et autrefois populaire dans le monde financier. Bien entendu, dans KX, Arthur a continué dans le même esprit et a créé le langage vectoriel-fonctionnel K, guidé par les idées du minimalisme radical. Les programmes K ressemblent à un fouillis de signes de ponctuation et de caractères spéciaux, la signification des signes et des fonctions dépend du contexte, et chaque opération a bien plus de sens que dans les langages de programmation conventionnels. De ce fait, un programme K prend peu de place (quelques lignes peuvent remplacer des pages de texte dans un langage verbeux comme Java) et constitue une implémentation ultra-concentrée de l'algorithme.
 
Une fonction en K qui implémente l'essentiel du générateur d'analyseurs LL1 selon une grammaire donnée :

1. pp:{q:{(x;p3(),y)};r:$[-11=@x;$x;11=@x;q[`N;$*x];10=abs@@x;q[`N;x]  
2.   ($)~*x;(`P;p3 x 1);(1=#x)&11=@*x;pp[{(1#x;$[2=#x;;,:]1_x)}@*x]  
3.      (?)~*x;(`Q;pp[x 1]);(*)~*x;(`M;pp[x 1]);(+)~*x;(`MP;pp[x 1]);(!)~*x;(`Y;p3 x 1)  
4.      (2=#x)&(@x 1)in 100 101 107 7 -7h;($[(@x 1)in 100 101 107h;`Ff;`Fi];p3 x 1;pp[*x])  
5.      (|)~*x;`S,(pp'1_x);2=#x;`C,{@[@[x;-1+#x;{x,")"}];0;"(",]}({$[".s.C"~4#x;6_-2_x;x]}'pp'x);'`pp];  
6.   $[@r;r;($[1<#r;".s.";""],$*r),$[1<#r;"[",(";"/:1_r),"]";""]]}  

 Arthur a incarné cette philosophie d'efficacité extrême avec un minimum de mouvements corporels dans KDB+, apparu en 2003 (je pense qu'on sait désormais d'où vient la lettre K dans le nom) et n'est plus qu'un interprète de la quatrième version du K. langage. Une version plus conviviale a été ajoutée à K K appelée Q. Q. a également ajouté la prise en charge d'un dialecte spécifique de SQL - QSQL, et l'interpréteur - prise en charge des tables en tant que type de données système, des outils pour travailler avec des tables en mémoire et sur disque, etc.
 
Ainsi, du point de vue de l'utilisateur, KDB+ est simplement un interpréteur de langage Q prenant en charge les tables et les expressions de style LINQ de type SQL à partir de C#. C’est la différence la plus importante entre KDB+ et les autres bases de données et son principal avantage concurrentiel, souvent négligé. Il ne s'agit pas d'une base de données + langage auxiliaire désactivé, mais d'un langage de programmation puissant à part entière + prise en charge intégrée des fonctions de base de données. Cette distinction jouera un rôle déterminant pour lister tous les bénéfices de KDB+. Par exemple…
 

Taille

Selon les normes modernes, KDB+ est tout simplement de taille microscopique. Il s'agit littéralement d'un fichier exécutable de moins d'un mégaoctet et d'un petit fichier texte contenant certaines fonctions système. En réalité, moins d'un mégaoctet, et pour ce programme, les entreprises paient des dizaines de milliers de dollars par an pour un processeur sur le serveur.

  • Cette taille permet à KDB+ de fonctionner parfaitement sur n'importe quel matériel - d'un micro-ordinateur Pi aux serveurs dotés de téraoctets de mémoire. Cela n'affecte en rien la fonctionnalité ; de plus, Q démarre instantanément, ce qui permet de l'utiliser, entre autres, comme langage de script.
  • A cette taille, l'interpréteur Q s'intègre entièrement dans le cache du processeur, ce qui accélère l'exécution du programme.
  • Avec cette taille de fichier exécutable, le processus Q occupe un espace mémoire négligeable ; vous pouvez en exécuter des centaines. De plus, si nécessaire, Q peut fonctionner avec des dizaines ou des centaines de gigaoctets de mémoire au sein d'un seul processus.

Universalisme

Q est idéal pour un large éventail d’applications. Process Q peut agir comme une base de données historique et fournir un accès rapide à des téraoctets d'informations. Par exemple, nous disposons de dizaines de bases de données historiques, dans certaines desquelles une journée de données non compressées occupe plus de 100 gigaoctets. Cependant, sous des restrictions raisonnables, une requête vers la base de données sera complétée en dizaines, voire centaines de millisecondes. En général, nous avons un délai d'attente universel pour les demandes des utilisateurs - 30 secondes - et cela fonctionne très rarement.
 
Q pourrait tout aussi bien être une base de données en mémoire. Les nouvelles données sont ajoutées aux tables en mémoire si rapidement que les demandes des utilisateurs constituent le facteur limitant. Les données des tables sont stockées dans des colonnes, ce qui signifie que toute opération sur une colonne utilisera le cache du processeur à pleine capacité. En plus de cela, KX a essayé de mettre en œuvre toutes les opérations de base telles que l'arithmétique via les instructions vectorielles du processeur, en maximisant leur vitesse. Q peut également effectuer des tâches qui ne sont pas typiques des bases de données - par exemple, traiter des données en streaming et calculer en « temps réel » (avec un délai de plusieurs dizaines de millisecondes à plusieurs secondes selon la tâche) diverses fonctions d'agrégation d'instruments financiers pour différents temps intervalles ou construire un modèle de l'influence des transactions parfaites sur le marché et effectuer son profilage presque immédiatement après son achèvement. Dans de telles tâches, le plus souvent le principal délai n'est pas Q, mais la nécessité de synchroniser les données provenant de différentes sources. La vitesse élevée est obtenue grâce au fait que les données et les fonctions qui les traitent sont dans un seul processus, et le traitement est réduit à l'exécution de plusieurs expressions et jointures QSQL, qui ne sont pas interprétées, mais sont exécutées par du code binaire.
 
Enfin, vous pouvez écrire n'importe quel processus de service dans Q. Par exemple, les processus Gateway qui distribuent automatiquement les demandes des utilisateurs aux bases de données et aux serveurs nécessaires. Le programmeur a toute liberté pour implémenter n'importe quel algorithme d'équilibrage, de priorisation, de tolérance aux pannes, de droits d'accès, de quotas et essentiellement tout ce qu'il désire. Le principal problème ici est que vous devrez mettre en œuvre tout cela vous-même.
 
À titre d'exemple, je vais énumérer les types de processus dont nous disposons. Tous sont activement utilisés et fonctionnent ensemble, combinant des dizaines de bases de données différentes en une seule, traitant des données provenant de plusieurs sources et servant des centaines d'utilisateurs et d'applications.

  • Connecteurs (feedhandler) vers les sources de données. Ces processus utilisent généralement des bibliothèques externes chargées dans Q. L'interface C de Q est extrêmement simple et vous permet de créer facilement des fonctions proxy pour n'importe quelle bibliothèque C/C++. Q est suffisamment rapide pour gérer, par exemple, le traitement simultané d'un flot de messages FIX provenant de toutes les bourses européennes.
  • Distributeurs de données (tickerplant), qui servent de lien intermédiaire entre les connecteurs et les consommateurs. Dans le même temps, ils écrivent les données entrantes dans un journal binaire spécial, offrant ainsi aux consommateurs une protection contre les pertes ou les redémarrages de connexion.
  • Base de données en mémoire (rdb). Ces bases de données offrent l'accès le plus rapide possible aux données brutes et fraîches en les stockant en mémoire. En règle générale, ils accumulent les données dans des tableaux pendant la journée et les réinitialisent la nuit.
  • Base de données persistante (pdb). Ces bases de données garantissent que les données d'aujourd'hui sont stockées dans une base de données historique. En règle générale, contrairement à rdb, ils ne stockent pas les données en mémoire, mais utilisent un cache spécial sur le disque pendant la journée et copient les données à minuit dans la base de données historique.
  • Bases de données historiques (hdb). Ces bases de données donnent accès aux données des jours, mois et années précédents. Leur taille (en jours) n'est limitée que par la taille des disques durs. Les données peuvent être localisées n'importe où, notamment sur différents disques pour en accélérer l'accès. Il est possible de compresser les données à l'aide de plusieurs algorithmes parmi lesquels choisir. La structure de la base de données est bien documentée et simple, les données sont stockées colonne par colonne dans des fichiers réguliers, afin de pouvoir être traitées, y compris au moyen du système d'exploitation.
  • Bases de données avec des informations agrégées. Ils stockent diverses agrégations, généralement avec, regroupées par nom d'instrument et intervalle de temps. Les bases de données en mémoire mettent à jour leur état à chaque message entrant, et les bases de données historiques stockent des données précalculées pour accélérer l'accès aux données historiques.
  • Enfin, le processus de passerellemaintenance des applications et des utilisateurs. Q vous permet de mettre en œuvre un traitement complètement asynchrone des messages entrants, en les répartissant sur des bases de données, en vérifiant les droits d'accès, etc. Notez que les messages ne sont pas limités et ne sont le plus souvent pas des expressions SQL, comme c'est le cas dans d'autres bases de données. Le plus souvent, l'expression SQL est cachée dans une fonction spéciale et est construite en fonction des paramètres demandés par l'utilisateur - le temps est converti, filtré, les données sont normalisées (par exemple, le cours de l'action est égalisé si des dividendes ont été payés), etc.

Architecture typique pour un type de données :

Base de données KDB+ : de la finance à la Formule 1

vitesse

Bien que Q soit un langage interprété, c'est aussi un langage vectoriel. Cela signifie que de nombreuses fonctions intégrées, en particulier arithmétiques, acceptent des arguments de n'importe quelle forme - nombres, vecteurs, matrices, listes - et que le programmeur est censé implémenter le programme sous forme d'opérations sur les tableaux. Dans un tel langage, si l'on ajoute deux vecteurs d'un million d'éléments, peu importe que le langage soit interprété ; l'addition sera effectuée par une fonction binaire super-optimisée. Étant donné que la part du lion du temps dans les programmes Q est consacrée aux opérations avec des tables qui utilisent ces fonctions vectorielles de base, le résultat est une vitesse de fonctionnement très décente, nous permettant de traiter une énorme quantité de données même en un seul processus. Ceci est similaire aux bibliothèques mathématiques de Python - bien que Python lui-même soit un langage très lent, il possède de nombreuses excellentes bibliothèques comme numpy qui vous permettent de traiter des données numériques à la vitesse d'un langage compilé (d'ailleurs, numpy est idéologiquement proche de Q ).
 
De plus, KX a adopté une approche très prudente dans la conception des tables et l'optimisation de leur utilisation. Premièrement, plusieurs types d'index sont pris en charge, qui sont pris en charge par des fonctions intégrées et peuvent être appliqués non seulement aux colonnes de table, mais également à n'importe quel vecteur - regroupement, tri, attribut d'unicité et regroupement spécial pour les bases de données historiques. L'index est appliqué simplement et est automatiquement ajusté lors de l'ajout d'éléments à la colonne/vecteur. Les index peuvent également être appliqués avec succès aux colonnes de tables en mémoire et sur disque. Lors de l'exécution d'une requête QSQL, les index sont utilisés automatiquement si possible. Deuxièmement, le travail avec les données historiques s'effectue via le mécanisme d'affichage des fichiers du système d'exploitation (carte mémoire). Les grandes tables ne sont jamais chargées en mémoire ; au lieu de cela, les colonnes nécessaires sont mappées directement en mémoire et seule la partie d'entre elles qui est réellement chargée (les index aident également ici) qui est nécessaire. Cela ne fait aucune différence pour le programmeur que les données soient en mémoire ou non ; le mécanisme permettant de travailler avec mmap est complètement caché dans les profondeurs de Q.
 
KDB+ n'est pas une base de données relationnelle ; les tables peuvent contenir des données arbitraires, tandis que l'ordre des lignes dans la table ne change pas lorsque de nouveaux éléments sont ajoutés et peut et doit être utilisé lors de l'écriture de requêtes. Cette fonctionnalité est nécessaire de toute urgence pour travailler avec des séries temporelles (données d'échanges, télémétrie, journaux d'événements), car si les données sont triées par heure, l'utilisateur n'a pas besoin d'utiliser d'astuces SQL pour trouver la première ou la dernière ligne ou N lignes du tableau, déterminez quelle ligne suit la Nième ligne, etc. Les jointures de tables sont encore plus simplifiées : par exemple, trouver le dernier cours de 16000 500 transactions VOD.L (Vodafone) dans un tableau de XNUMX millions d'éléments prend environ une seconde sur le disque et des dizaines de millisecondes en mémoire.
 
Un exemple de jointure temporelle - la table de cotation est mappée en mémoire, il n'est donc pas nécessaire de spécifier VOD.L dans lequel, l'index sur la colonne sym et le fait que les données sont triées par heure sont implicitement utilisés. Presque toutes les jointures dans Q sont des fonctions régulières qui ne font pas partie d'une expression de sélection :

1. aj[`sym`time;select from trade where date=2019.03.26, sym=`VOD.L;select from quote where date=2019.03.26]  

Enfin, il convient de noter que les ingénieurs de KX, à commencer par Arthur Whitney lui-même, sont véritablement obsédés par l'efficacité et mettent tout en œuvre pour tirer le meilleur parti des fonctionnalités standard du Q et optimiser les modèles d'utilisation les plus courants.
 

Total

KDB+ est populaire parmi les entreprises principalement en raison de sa polyvalence exceptionnelle : il sert aussi bien de base de données en mémoire, de base de données pour stocker des téraoctets de données historiques et de plate-forme d'analyse de données. Du fait que le traitement des données s'effectue directement dans la base de données, une vitesse de travail élevée et des économies de ressources sont obtenues. Un langage de programmation à part entière intégré aux fonctions de base de données vous permet de mettre en œuvre l'ensemble des processus nécessaires sur une seule plate-forme - de la réception des données au traitement des demandes des utilisateurs.
 

Pour plus d'informations,

Limites

Un inconvénient majeur de KDB+/Q est le seuil d’entrée élevé. Le langage a une syntaxe étrange, certaines fonctions sont fortement surchargées (value, par exemple, a environ 11 cas d'utilisation). Plus important encore, cela nécessite une approche radicalement différente de l’écriture des programmes. Dans un langage vectoriel, vous devez toujours penser en termes de transformations de tableaux, implémenter toutes les boucles à travers plusieurs variantes des fonctions map/reduce (appelées adverbes en Q) et ne jamais essayer d'économiser de l'argent en remplaçant les opérations vectorielles par des opérations atomiques. Par exemple, pour trouver l'index de la Nième occurrence d'un élément dans un tableau, vous devez écrire :

1. (where element=vector)[N]  

bien que cela semble terriblement inefficace par rapport aux standards C/Java (= crée un vecteur booléen, où renvoie les vrais index des éléments qu'il contient). Mais cette notation rend le sens de l'expression plus clair et vous utilisez des opérations vectorielles rapides au lieu d'opérations atomiques lentes. La différence conceptuelle entre un langage vectoriel et les autres est comparable à la différence entre les approches impératives et fonctionnelles de la programmation, et vous devez vous y préparer.
 
Certains utilisateurs sont également mécontents de QSQL. Le fait est que cela ne ressemble qu'à du vrai SQL. En réalité, il s'agit simplement d'un interpréteur d'expressions de type SQL qui ne prend pas en charge l'optimisation des requêtes. L'utilisateur doit écrire lui-même des requêtes optimales, et en Q, pour lesquelles beaucoup ne sont pas prêts. D’un autre côté, bien sûr, vous pouvez toujours écrire vous-même la requête optimale, plutôt que de vous fier à un optimiseur de boîte noire.
 
En plus, un livre sur Q - Q For Mortals est disponible gratuitement sur site Web, de nombreux autres matériaux utiles y sont également collectés.
 
Un autre gros inconvénient est le coût de la licence. Cela représente des dizaines de milliers de dollars par an et par processeur. Seules les grandes entreprises peuvent se permettre de telles dépenses. Récemment, KX a assoupli sa politique de licence et offre la possibilité de payer uniquement pour la durée d'utilisation ou de louer KDB+ dans les cloud Google et Amazon. KX propose également en téléchargement version gratuite à des fins non commerciales (Version 32 bits ou 64 bits sur demande).
 

concurrents

Il existe de nombreuses bases de données spécialisées construites sur des principes similaires : en colonnes, en mémoire, axées sur de très grandes quantités de données. Le problème est qu’il s’agit de bases de données spécialisées. Un exemple frappant est Clickhouse. Cette base de données a un principe très similaire à KDB+ pour stocker des données sur disque et construire un index ; elle effectue certaines requêtes plus rapidement que KDB+, mais pas de manière significative. Mais même en tant que base de données, Clickhouse est plus spécialisée que KDB+ - analyse Web vs séries temporelles arbitraires (cette différence est très importante - à cause de cela, par exemple, dans Clickhouse, il n'est pas possible d'utiliser l'ordre des enregistrements). Mais plus important encore, Clickhouse n'a pas la polyvalence de KDB+, un langage qui permettrait de traiter les données directement dans la base de données, plutôt que de les charger d'abord dans une application distincte, de construire des expressions SQL arbitraires, d'appliquer des fonctions arbitraires dans une requête, de créer des processus. non lié à l'exécution des fonctions de la base de données historique. Il est donc difficile de comparer KDB+ avec d'autres bases de données ; elles peuvent être meilleures dans certains cas d'utilisation ou simplement meilleures lorsqu'il s'agit de tâches classiques de base de données, mais je ne connais pas d'autre outil aussi efficace et polyvalent pour traiter les données temporaires.
 

Intégration Python

Pour rendre KDB+ plus facile à utiliser pour les personnes peu familiarisées avec la technologie, KX a créé des bibliothèques pour s'intégrer étroitement à Python au sein d'un seul processus. Vous pouvez soit appeler n'importe quelle fonction Python depuis Q, soit vice versa, appeler n'importe quelle fonction Q depuis Python (en particulier, les expressions QSQL). Les bibliothèques convertissent, si nécessaire (pas toujours par souci d'efficacité), les données du format d'une langue vers le format d'une autre. En conséquence, Q et Python vivent dans une symbiose si étroite que les frontières entre eux sont floues. En conséquence, le programmeur, d'une part, a un accès complet à de nombreuses bibliothèques Python utiles, d'autre part, il reçoit une base rapide pour travailler avec le Big Data intégré à Python, ce qui est particulièrement utile pour ceux impliqués dans l'apprentissage automatique. ou du modelage.
 
Travailler avec Q en Python :

1. >>> q()  
2.q)trade:([]date:();sym:();qty:())  
3. q)  
4. >>> q.insert('trade', (date(2006,10,6), 'IBM', 200))  
5. k(',0')  
6. >>> q.insert('trade', (date(2006,10,6), 'MSFT', 100))  
7. k(',1')  

références

Le site de l'entreprise - https://kx.com/
Site Web pour les développeurs - https://code.kx.com/v2/
Livre Q pour les mortels (en anglais) - https://code.kx.com/q4m3/
Articles sur les applications KDB+/Q rédigés par des employés de kx - https://code.kx.com/v2/wp/

Source: habr.com

Ajouter un commentaire