Actuellement, les E/S de disque distantes et le CPU peuvent être ordonnancés selon la méthode décrite. Pour des limites de mémoire flexibles, voir surallocation de mémoire
Configuration du disque
storage_configuration du serveur :
Pour activer la planification des E/S pour un disque spécifique, vous devez spécifier read_resource et/ou write_resource dans la configuration de stockage. Cela indique à ClickHouse quelle ressource utiliser pour chaque requête de lecture et d’écriture sur le disque concerné. Les ressources de lecture et d’écriture peuvent faire référence au même nom de ressource, ce qui est utile pour les SSD locaux ou les HDD. Plusieurs disques différents peuvent également faire référence à la même ressource, ce qui est utile pour les disques distants si vous souhaitez permettre une répartition équitable de la bande passante réseau entre, par exemple, les workloads “production” et “development”.
Exemple :
Marquage des charges de travail
workload pour distinguer différentes charges de travail. Si workload n’est pas défini, la valeur “default” est utilisée. Notez que vous pouvez également spécifier une autre valeur à l’aide de profils de paramètres. Des contraintes sur les paramètres peuvent être utilisées pour rendre workload constant si vous souhaitez que toutes les requêtes d’un utilisateur soient marquées avec une valeur fixe du paramètre workload.
Il est possible d’attribuer un paramètre workload aux activités en arrière-plan. Les merges et les mutations utilisent respectivement les paramètres serveur merge_workload et mutation_workload. Ces valeurs peuvent également être redéfinies pour des tables spécifiques à l’aide des paramètres MergeTree merge_workload et mutation_workload
Prenons l’exemple d’un système avec deux charges de travail différentes : “production” et “développement”.
Hiérarchie d’ordonnancement des ressources
inflight_limit(constraint) - bloque si le nombre de requêtes concurrentes en vol dépassemax_requests, ou si leur coût total dépassemax_cost; doit avoir un seul enfant.bandwidth_limit(constraint) - bloque si la bande passante actuelle dépassemax_speed(0 signifie illimité) ou si le burst dépassemax_burst(par défaut, égal àmax_speed) ; doit avoir un seul enfant.fair(policy) - sélectionne la prochaine requête à traiter dans l’un de ses nœuds enfants selon l’équité max-min ; les nœuds enfants peuvent spécifierweight(la valeur par défaut est 1).priority(policy) - sélectionne la prochaine requête à traiter dans l’un de ses nœuds enfants selon des priorités statiques (une valeur plus faible signifie une priorité plus élevée) ; les nœuds enfants peuvent spécifierpriority(la valeur par défaut est 0).fifo(queue) - feuille de la hiérarchie capable de stocker les requêtes qui dépassent la capacité de la ressource.
inflight_limit. Notez qu’un nombre trop faible de max_requests ou une valeur trop faible de max_cost peut entraîner une utilisation incomplète de la ressource, tandis que des valeurs trop élevées peuvent entraîner des files d’attente vides dans le scheduler, ce qui fera que les policies seront ignorées (manque d’équité ou priorités ignorées) dans le sous-arbre. En revanche, si vous voulez protéger les ressources contre une utilisation excessive, vous devez utiliser bandwidth_limit. Il applique une limitation lorsque la quantité de ressources consommée en duration secondes dépasse max_burst + max_speed * duration octets. Deux nœuds bandwidth_limit sur la même ressource peuvent être utilisés pour limiter la bande passante de crête sur de courts intervalles et la bande passante moyenne sur des intervalles plus longs.
L’exemple suivant montre comment définir les hiérarchies d’ordonnancement des IO illustrées dans l’image :
Classificateurs de workloads
workload spécifié par une requête et les files d’attente terminales à utiliser pour certaines ressources. Pour le moment, la classification des workloads reste simple : seule une correspondance statique est disponible.
Exemple :
Hiérarchie des charges de travail
CREATE RESOURCE partagent la même structure hiérarchique, mais peuvent différer sur certains points. Chaque charge de travail créée avec CREATE WORKLOAD comporte quelques nœuds d’ordonnancement créés automatiquement pour chaque ressource. Une charge de travail enfant peut être créée au sein d’une autre charge de travail parente. Voici un exemple qui définit exactement la même hiérarchie que la configuration XML ci-dessus :
SETTINGS workload = 'name'.
Pour personnaliser un workload, les paramètres suivants peuvent être utilisés :
priority- les workloads frères sont servis selon des valeurs de priorité statiques (une valeur plus faible signifie une priorité plus élevée).weight- les workloads frères ayant la même priorité statique se partagent les ressources en fonction de leurs poids.max_io_requests- la limite du nombre de requêtes d’E/S concurrentes dans ce workload.max_bytes_inflight- la limite du nombre total d’octets en cours de traitement pour les requêtes concurrentes dans ce workload.max_bytes_per_second- la limite du débit en octets en lecture ou en écriture de ce workload.max_burst_bytes- le nombre maximal d’octets pouvant être traités par le workload sans être bridé (pour chaque ressource indépendamment).max_concurrent_threads- la limite du nombre de threads pour les requêtes dans ce workload.max_concurrent_threads_ratio_to_cores- identique àmax_concurrent_threads, mais normalisé par rapport au nombre de cœurs CPU disponibles.max_cpus- la limite du nombre de cœurs CPU pour servir les requêtes dans ce workload.max_cpu_share- identique àmax_cpus, mais normalisé par rapport au nombre de cœurs CPU disponibles.max_burst_cpu_seconds- le nombre maximal de secondes CPU pouvant être consommées par le workload sans être bridé en raison demax_cpus.
max_bytes_per_second = 10485760 aura une limite de bande passante de 10 MB/s pour chaque ressource de lecture et d’écriture, indépendamment. Si une limite commune pour la lecture et l’écriture est requise, envisagez d’utiliser la même ressource pour l’accès READ et WRITE.
Il n’existe aucun moyen de spécifier des hiérarchies de workloads différentes pour différentes ressources. Mais il existe un moyen de spécifier une valeur de workload setting différente pour une ressource spécifique :
CREATE OR REPLACE WORKLOAD.
Les paramètres du workload sont convertis en un ensemble approprié de nœuds d’ordonnancement. Pour plus de détails sur les mécanismes sous-jacents, consultez la description des types et options des nœuds d’ordonnancement.
Ordonnancement du CPU
- Master thread — le premier thread qui commence à travailler sur une requête ou une activité en arrière-plan comme une merge ou une mutation.
- Worker thread — les threads supplémentaires que le master peut créer pour travailler sur des tâches gourmandes en CPU.
max_threads sont utilisées. Les requêtes entrantes doivent alors se bloquer et attendre qu’un slot CPU se libère pour que leur master thread puisse commencer l’exécution. Pour éviter cela, la configuration suivante peut être utilisée :
cpu_slot_preemption. S’il est activé, chaque thread renouvelle périodiquement son slot CPU (selon le paramètre serveur cpu_slot_quantum_ns). Un tel renouvellement peut bloquer l’exécution si le CPU est surchargé. Lorsque l’exécution reste bloquée pendant une durée prolongée (voir le paramètre serveur cpu_slot_preemption_timeout_ms), la requête réduit alors sa capacité, et le nombre de threads exécutés en parallèle diminue dynamiquement. Notez que l’équité du temps CPU est garantie entre les charges de travail, mais qu’entre les requêtes d’une même charge de travail, elle peut ne pas être respectée dans certains cas limites.
La déclaration d’une ressource CPU désactive l’effet des paramètres
concurrent_threads_soft_limit_num et concurrent_threads_soft_limit_ratio_to_cores. À la place, le workload setting max_concurrent_threads est utilisé pour limiter le nombre de CPU alloués à une charge de travail spécifique. Pour retrouver le comportement précédent, créez uniquement la ressource WORKER THREAD, définissez max_concurrent_threads pour la charge de travail all sur la même valeur que concurrent_threads_soft_limit_num, puis utilisez le paramètre de requête workload = "all". Cette configuration correspond au paramètre concurrent_threads_scheduler défini sur la valeur “fair_round_robin”.Threads vs. CPU
- Limite du nombre de threads :
max_concurrent_threadsetmax_concurrent_threads_ratio_to_cores - Bridage du CPU :
max_cpus,max_cpu_shareetmax_burst_cpu_seconds
max_threads. La seconde bride la consommation de CPU de la charge de travail à l’aide de l’algorithme du seau à jetons. Elle n’affecte pas directement le nombre de threads, mais bride la consommation totale de CPU de tous les threads de la charge de travail.
Le bridage par seau à jetons avec max_cpus et max_burst_cpu_seconds signifie ce qui suit. Sur tout intervalle de delta secondes, la consommation totale de CPU de toutes les queries de la charge de travail ne doit pas dépasser max_cpus * delta + max_burst_cpu_seconds secondes CPU. Cela limite la consommation moyenne à max_cpus sur le long terme, mais cette limite peut être dépassée à court terme. Par exemple, avec max_burst_cpu_seconds = 60 et max_cpus=0.001, il est possible d’exécuter soit 1 thread pendant 60 secondes, soit 2 threads pendant 30 secondes, soit 60 threads pendant 1 seconde sans bridage. La valeur par défaut de max_burst_cpu_seconds est de 1 seconde. Des valeurs plus faibles peuvent entraîner une sous-utilisation des cœurs autorisés par max_cpus en présence de nombreux threads concurrents.
Lorsqu’il détient un slot CPU, un thread peut se trouver dans l’un de ces trois états principaux :
- Running: consomme effectivement des ressources CPU. Le temps passé dans cet état est pris en compte par le bridage du CPU.
- Ready: attend qu’un CPU devienne disponible. N’est pas pris en compte par le bridage du CPU.
- Blocked: effectue des opérations d’IO ou d’autres appels système bloquants (par exemple, en attente d’un mutex). N’est pas pris en compte par le bridage du CPU.
max_cpu_share, d’une limite de 70 % des ressources CPU totales. Quant à l’ingestion, si elle conserve une garantie d’au moins 0.8 * 0.25 = 20 %, elle n’a pas de limite supérieure.
Si vous souhaitez maximiser l’utilisation du CPU sur votre serveur ClickHouse, évitez d’utiliser
max_cpus et max_cpu_share pour le workload racine all. Définissez plutôt une valeur plus élevée pour max_concurrent_threads. Par exemple, sur un système avec 8 CPU, définissez max_concurrent_threads = 16. Cela permet à 8 threads d’exécuter des tâches CPU pendant que 8 autres threads peuvent gérer des opérations d’E/S. Des threads supplémentaires créeront une pression sur le CPU, ce qui garantit l’application des règles d’ordonnancement. À l’inverse, définir max_cpus = 8 ne créera jamais de pression sur le CPU, car le serveur ne peut pas dépasser les 8 CPU disponibles.Ordonnancement des slots de requête
max_concurrent_queries limite le nombre de requêtes concurrentes pouvant s’exécuter simultanément pour un workload donné. Il s’agit de l’équivalent du paramètre de requête max_concurrent_queries_for_all_users et du paramètre du serveur max_concurrent_queries. Les requêtes async insert et certaines requêtes spécifiques, comme KILL, ne sont pas comptabilisées dans cette limite.
Les paramètres de workload max_queries_per_second et max_burst_queries limitent le nombre de requêtes pour le workload à l’aide d’un mécanisme de limitation de débit de type token bucket. Cela garantit que, sur tout intervalle de temps T, pas plus de max_queries_per_second * T + max_burst_queries nouvelles requêtes ne commenceront à s’exécuter.
Le paramètre de workload max_waiting_queries limite le nombre de requêtes en attente pour le workload. Lorsque la limite est atteinte, le serveur renvoie une erreur SERVER_OVERLOADED.
Les requêtes bloquées attendront indéfiniment et n’apparaîtront pas dans
SHOW PROCESSLIST tant que toutes les contraintes ne seront pas satisfaites.Stockage des workloads et des ressources
CREATE WORKLOAD et CREATE RESOURCE, sont stockées de manière persistante soit sur le disque dans workload_path, soit dans ZooKeeper dans workload_zookeeper_path. Le stockage dans ZooKeeper est recommandé pour garantir la cohérence entre les nœuds. Sinon, la clause ON CLUSTER peut être utilisée avec le stockage sur disque.
Charges de travail et ressources définies par configuration
Format de la configuration
CREATE WORKLOAD et CREATE RESOURCE. Toutes les requêtes doivent être valides.
Recommandations d’utilisation
- Définir le workload racine et les ressources d’E/S réseau dans la configuration afin de fixer les limites de l’infrastructure
- Définir
throw_on_unknown_workloadpour faire respecter ces limites - Créer un
CREATE WORKLOAD default IN allpour appliquer automatiquement les limites à toutes les requêtes (puisque la valeur par défaut du paramètre de requêteworkloadest ‘default’) - Autoriser les utilisateurs à créer des workloads supplémentaires dans la hiérarchie configurée
Accès strict aux ressources
throw_on_unknown_workload. S’il est défini sur true, chaque requête doit utiliser un paramètre de requête workload valide, faute de quoi l’exception RESOURCE_ACCESS_DENIED est levée. S’il est défini sur false, une telle requête n’utilise pas l’ordonnanceur de ressources, c’est-à-dire qu’elle bénéficie d’un accès illimité à n’importe quelle RESOURCE. Le paramètre de requête ‘use_concurrency_control = 0’ permet à une requête de contourner l’ordonnanceur CPU et d’obtenir un accès illimité au CPU. Pour imposer l’ordonnancement CPU, créez une contrainte de paramètre afin que ‘use_concurrency_control’ reste une valeur constante en lecture seule.
Ne définissez pas
throw_on_unknown_workload sur true tant que CREATE WORKLOAD default n’a pas été exécuté. Cela peut entraîner des problèmes au démarrage du serveur si une requête sans paramètre workload explicite est exécutée pendant le démarrage.Voir aussi
- system.scheduler
- system.workloads
- system.resources
- merge_workload paramètre de MergeTree
- merge_workload paramètre global du serveur
- mutation_workload paramètre de MergeTree
- mutation_workload paramètre global du serveur
- workload_path paramètre global du serveur
- workload_zookeeper_path paramètre global du serveur
- cpu_slot_preemption paramètre global du serveur
- cpu_slot_quantum_ns paramètre global du serveur
- cpu_slot_preemption_timeout_ms paramètre global du serveur