H2 est une base de données à thread unique avec une bonne réputation en termes de performances. D'autres bases de données sont multithread.
Ma question est: quand une base de données multithread devient-elle plus intéressante qu'une base de données monofil? Combien d'utilisateurs? Combien de processus? Quel est le déclencheur? Quelqu'un a-t-il de l'expérience à partager?
Résumé
Voici mon avis:
Le goulot d'étranglement (ou la partie la plus lente) d'un système DB est généralement le disque. Le processeur ne pointe que pendant les opérations arithmétiques, le traitement ou toute autre tâche effectuée par le processeur. Avec une architecture appropriée, le multithreading peut aider à compenser la charge d'une requête sur le CPU au lieu de faire des lectures/écritures lentes sur disque. Il y a des cas où il est plus rapide de calculer une valeur en utilisant les cycles CPU plutôt que de créer une colonne calculée (qui a été précédemment enregistrée sur le disque) et de lire cette colonne à partir du disque.
Dans certains SGBDR, il existe une base de données temporaire (tempdb) qui est utilisée par toutes les bases de données de cette instance pour le tri, le hachage, les variables temporaires, etc. , améliorant ainsi les performances globales du serveur.
En utilisant le multithreading (parallélisme), le jeu de résultats d'une requête peut être divisé pour être traité sur les différents cœurs du serveur, plutôt que d'utiliser un seul cœur. Cette fonctionnalité n'améliore pas toujours les performances, mais il y a des cas où elle le fait, et donc la fonctionnalité est disponible.
Les threads disponibles pour la base de données sont utilisés à de nombreuses fins: lecture/écriture sur le disque, connexions utilisateur, travaux en arrière-plan, verrouillage/verrouillage, E/S réseau, etc. géré à l'aide d'attentes et de files d'attente. Si le CPU peut croquer ces threads assez rapidement, les temps d'attente seront faibles. Une base de données à plusieurs threads sera plus rapide qu'une base de données à thread unique, car dans une base de données à thread unique, il y aura la surcharge de recycler un seul thread plutôt que d'avoir d'autres bandes de roulement facilement disponibles.
L'évolutivité devient également un problème, car davantage de threads seront nécessaires pour gérer et exécuter le système de base de données mis à l'échelle.
S'il y a une chose que je peux dire à propos de MySQL, c'est qu'InnoDB, son moteur de stockage transactionnel (compatible ACID), est en effet multithread. Cependant, il est aussi multithread que VOUS LE CONFIGUREZ !!! Même dès la sortie de l'emballage, InnoDB fonctionne très bien dans un environnement à processeur unique compte tenu de ses paramètres par défaut. Pour profiter des capacités de multithreading d'InnoDB, vous devez vous rappeler d'activer de nombreuses options.
innodb_thread_concurrency définit la limite supérieure du nombre de threads simultanés qu'InnoDB peut maintenir ouverts. Le meilleur nombre de tours à définir pour cela est (2 X nombre de CPU) + nombre de disques. [~ # ~] mise à jour [~ # ~] : Comme je l'ai appris de première main lors de la conférence Percona NYC, vous devez définir cette valeur sur 0 afin d'alerter InnoDB Storage Engine pour trouver le meilleur nombre de threads pour l'environnement dans lequel il s'exécute.
innodb_concurrency_tickets définit le nombre de threads qui peuvent contourner la vérification de la concurrence en toute impunité. Une fois cette limite atteinte, la vérification de la simultanéité des threads redevient la norme.
innodb_commit_concurrency définit le nombre de transactions simultanées qui peuvent être validées. Étant donné que la valeur par défaut est 0, le fait de ne pas le définir permet à un nombre illimité de transactions d'être validées simultanément.
innodb_thread_sleep_delay définit le nombre de millisecondes pendant lequel un thread InnoDB peut être inactif avant de rentrer dans la file d'attente InnoDB. La valeur par défaut est 10000 (10 secondes).
innodb_read_io_threads et innodb_write_io_threads (les deux depuis MySQL 5.1.38) allouent le nombre spécifié de threads pour les lectures et les écritures. La valeur par défaut est 4 et la valeur maximale est 64.
innodb_replication_delay impose un délai de thread à un esclave lorsque innodb_thread_concurrency est atteint.
innodb_read_ahead_threshold permet des lectures linéaires du nombre défini d'extensions (64 pages [page = 16K]) avant de passer en lecture asynchrone.
Le temps m'échapperait si je nommais plus d'options. Vous pouvez les lire dans MySQL's Documentation .
La plupart des gens ne connaissent pas ces fonctionnalités et sont très satisfaits qu'InnoDB ne fasse que des transactions conformes à ACID. Si vous modifiez l'une de ces options, vous le faites à vos risques et périls.
J'ai joué avec des instances de pool de tampons multiples MySQL 5.5 (162 Go dans 9 instances de pools de tampons) et j'ai tenté de partitionner automatiquement les données en mémoire de cette façon. Certains experts disent que cela devrait vous donner 50% d'amélioration des performances. Ce que j'ai obtenu, c'est une tonne de verrous de threads qui a en fait fait ramper InnoDB. Je suis passé à 1 tampon (162 Go) et tout allait bien à nouveau dans le monde. Je suppose que vous avez besoin d'experts Percona à votre disposition pour régler cela. Je serai à la conférence Percona MySQL à New York demain et je poserai des questions à ce sujet si l'occasion se présente.
En conclusion, InnoDB se comporte bien maintenant dans un serveur multi CPU compte tenu de ses paramètres par défaut pour les opérations multithread. Les modifier nécessite beaucoup de soin, une grande patience, une excellente documentation et un excellent café (ou Red Bull, Jolt, etc.).
Bonjour, bonne soirée et bonne nuit !!!
MISE À JOUR 2011-05-27 20:11
Je suis revenu de Conférence Percona MySQL à New York jeudi. Quelle conférence. J'ai beaucoup appris, mais j'ai obtenu une réponse que je vais examiner concernant InnoDB. J'ai été informé par Ronald Bradford qu'en définissant innodb_thread_concurrency sur 0, InnoDB décidera du meilleur plan d'action en interne avec la simultanéité des threads. Je vais expérimenter cela plus en détail dans MySQL 5.5.
MISE À JOUR 2011-06-01 11:20
En ce qui concerne une longue requête, InnoDB est compatible ACID et fonctionne très bien en utilisant MultiVersion Concurrency Control . Les transactions doivent pouvoir transporter des niveaux d'isolement (lectures répétables par défaut) qui empêchent les autres d'accéder aux données.
Quant aux systèmes multicœurs, InnoDB a parcouru un long chemin. Dans le passé, InnoDB ne pouvait pas bien fonctionner dans un environnement multicœur. Je me souviens avoir dû exécuter plusieurs instances de mysql sur un seul serveur pour obtenir les multiples cœurs pour distribuer les multiples processus mysqld sur les CPU. Ce n'est plus nécessaire, grâce à Percona, et plus tard à MySQL (eh, Oracle, en disant que ça me fait toujours mal), car ils ont développé InnoDB en un moteur de stockage plus mature qui peut accéder aux cœurs avec simplicité sans trop de réglage. L'instance actuelle d'InnoDB peut aujourd'hui bien fonctionner sur un seul serveur principal.
Dès que vous avez plusieurs utilisateurs ou processus simultanés, ou même un seul processus avec accès à une base de données multithread, avoir une base de données qui prend en charge le threading deviendra potentiellement intéressant.
H2 est thread-safe, mais sérialise toutes les demandes à la base de données, ce qui peut devenir un problème de performances potentiel dans un scénario de forte charge. Que ce soit réellement le cas pour un projet particulier dépend de la combinaison de vos exigences de performances, du nombre de threads/utilisateurs/processus accédant à la base de données, de la fréquence des requêtes exécutées par ces threads et des performances moyennes et pires de votre requêtes.
Par exemple, si vos exigences de performances doivent avoir une réponse en une seconde, vous n'avez pas plus de 10 utilisateurs simultanés exécutant une seule requête qui prend 0,05 seconde pour s'exécuter, une base de données à thread unique vous permettrait toujours d'atteindre ces objectifs (bien que multithread donnerait probablement déjà une amélioration notable des performances). Dans le même scénario, avec une seule requête potentielle avec une performance dans le pire des cas pendant une demi-seconde, la sérialisation de l'accès à votre base de données ne vous permettra plus d'atteindre vos objectifs de performance.
Si vous utilisez actuellement H2 sur votre projet, je vous conseillerais d'exécuter un profileur sur votre base de code dans un scénario de chargement (lancez simplement un nombre x de threads frappant votre code simultanément en utilisant des cas d'utilisation typiques). Cela vous donnera des mesures réelles concernant les performances et les goulots d'étranglement dans votre base de code, au lieu de simplement théoriser. Si cela montre que vos demandes passent un grand pourcentage de leur temps à attendre d'accéder à la base de données, il est temps de passer à une base de données filetée.
D'après ce que je peux dire, "single-threaded" est un peu inapproprié pour H2. Le fait est que il sérialise toutes les transactions (c'est-à-dire les fait une à la fois).
La question cruciale de savoir si c'est "ok" ou non pour votre application n'est pas "Combien d'utilisateurs?" ou même "Combien de processus?", mais "Combien de temps vont prendre mes transactions?"
Si toutes vos transactions sont inférieures à la seconde, cela peut être correct, si certaines prennent plusieurs heures, cela peut ne pas être correct car toutes les autres transactions en attente attendront qu'elles se terminent. La décision de savoir si cela est "bien" ou non dépendra de vos propres exigences de performances - c'est-à-dire combien de temps est une attente acceptable pour mes utilisateurs atteignant la base de données avec des transactions.
--ÉDITER
Il semble que H2 ne sérialise pas vraiment les transactions - juste DML. En d'autres termes, beaucoup de courtes mises à jour au cours d'une seule transaction longue ne bloquera pas les autres mises à jour . Cependant, sauf si vous utilisez la fonction fonction MVCC expérimentale , le verrouillage de table signifie que cela a un effet similaire dans la pratique. Il y a aussi une fonction expérimentale "multi_threaded" mais elle ne peut pas être utilisée en même temps que MVCC
Citant des morceaux du site PostgreSQL ... Veuillez noter que je n'ai absolument aucune idée du bien-fondé de ces arguments - ils ne correspondaient tout simplement pas à un commentaire.
Du développeur FAQ ("Pourquoi les threads ne sont pas utilisés ..."):
Les threads ne sont actuellement pas utilisés à la place de plusieurs processus pour les backends car: (...)
- Une erreur dans un backend peut corrompre d'autres backends s'ils sont des threads dans un seul processus
- Les améliorations de la vitesse à l'aide de threads sont faibles par rapport au temps de démarrage du backend restant.
- Le partage de mappages exécutables en lecture seule et l'utilisation de shared_buffers signifie que les processus, comme les threads, sont très efficaces en mémoire
- La création et la destruction régulières des processus contribuent à protéger contre la fragmentation de la mémoire, qui peut être difficile à gérer dans les processus de longue durée
Dans la liste Todo ("Fonctionnalités dont nous ne voulons pas"):
http://wiki.postgresql.org/wiki/Todo#Features_We_Do_Not_Want
Tous les backends s'exécutant en tant que threads dans un seul processus (non souhaité)
Cela élimine la protection des processus que nous obtenons de la configuration actuelle. La création de threads est généralement la même surcharge que la création de processus sur les systèmes modernes, il semble donc imprudent d'utiliser un modèle purement threadé, et MySQL et DB2 ont démontré que les threads introduisent autant de problèmes qu'ils résolvent. (...)
Donc, encore une fois ... Je n'ai absolument aucune idée des mérites de ce qui précède. Il était simplement trop long pour tenir dans un commentaire.