Remplacement d'une fil d'attente [PERL] - Perl - Programmation
Marsh Posté le 26-06-2008 à 09:57:21
Le plus simple est d'avoir un programme qui écoute et alimente un cache en permanence, et qui ne fait que ça.
Un second programme lit le cache et traite les informations autant qu'il peut.
Le but est de ne pas avoir de perte d'information lorsque le flux d'information est plus important que la capacité de traitement.
Marsh Posté le 27-06-2008 à 14:27:35
Quelles sont tes marges de manoeuvre ? parce que "application" reste vague, si c'est une appli commeciale où tu ne peux rien changer, ca va être compliqué
Si tu peux t'amuser à tout remplacer, là les pistes s'élargissent.
Tu pourrais être exemple avoir plusieurs démons qui tournent sur plusieurs ports pour le traitement d'infos et un chef d'orchestre qui attribue les messages sur chacun des démons, ou alors un démon qui écoute les messages, bufferise et envoie à l'"application-dont-on-a-aucune-infos" les messages de manière modéré
Marsh Posté le 30-06-2008 à 09:19:38
Citation : Le plus simple est d'avoir un programme qui écoute et alimente un cache en permanence, et qui ne fait que ça. |
Comment alimenter le cache?
Grossièrement, ça revient à couper le programme actuel en 2 donc, un qui écoute et un qui traite. En quoi, ça va améliorer les perfs?
Citation : Quelles sont tes marges de manoeuvre ? parce que "application" reste vague, si c'est une appli commeciale où tu ne peux rien changer, ca va être compliqué |
Ce n'est pas une appli commerciale, c'est une appli interne. De plus, j'ai une "plate-forme" de test, donc il y a moyen de changer complètement le système tant que le travail effectué reste le même (en mieux lol)...
Citation : Tu pourrais être exemple avoir plusieurs démons qui tournent sur plusieurs ports pour le traitement d'infos et un chef d'orchestre qui attribue les messages sur chacun des démons |
Ca diminuerait la perte au niveau des IO ça nan? ça me paraît être une bonne piste. Seulement c'est compliqué de répartir l'envoi sur différents ports alors qu'aujourd'hui tous les envois ne se font que sur un port en UDP...
Citation : ou alors un démon qui écoute les messages, bufferise et envoie à l'"application-dont-on-a-aucune-infos" les messages de manière modéré |
La est tout le pb. Comment envoyer de manière modérée? Car il y a au moins 1000 messages (surement beaucoup +) par minutes à traiter, donc un moment le buffer ne va pas aimer...
Marsh Posté le 30-06-2008 à 10:06:03
johnkro a écrit : |
Plutôt que d'augmenter les performances, cela permettra de ne pas les diminuer en cas de pic de charge.
La première partie continue d'écouter pendant que la seconde est occupée à traiter, ce qui permet de ne pas perdre de données sur le flux à cause d'une indisponibilité du programme due au traitement. Tout ce que cela fait, c'est que le cache grossit le temps que les données en attente soient traitées.
Marsh Posté le 30-06-2008 à 10:39:27
Elmoricq a écrit : Plutôt que d'augmenter les performances, cela permettra de ne pas les diminuer en cas de pic de charge. |
Ok ok ça a l'air pas mal du tout.
Je me pose une question, c'est comment alimenté le cache? C'est par exemple un programme qui écoute et écrit dans un tableau. Puis l'autre programme qui lit ce tableau et fait le traitement? ou écrire dans un fichier? dans une BDD ce serait trop lent?
En tout cas, je te remercie beaucoup de tes réponses !!!
Marsh Posté le 30-06-2008 à 10:49:02
Ça dépend des moyens mis à disposition et de la façon dont travaille ton programme habituellement. Spool de fichiers dans un répertoire (pas un unique fichier, sinon gérer le vidage du cache c'est la misère), base de données, mémoire partagée, fais ton choix.
Je préfère travailler avec une BDD personnellement, et en second choix un répertoire de fichiers. L'avantage de ces deux moyens c'est que le cache est permanent tant qu'il n'y a pas eu traitement, ce qui permet une reprise en cas de problème, alors qu'en mémoire partagée, si l'écouteur tombe, tu perds le cache.
Marsh Posté le 30-06-2008 à 14:46:11
Elmoricq a écrit : Ça dépend des moyens mis à disposition et de la façon dont travaille ton programme habituellement. Spool de fichiers dans un répertoire (pas un unique fichier, sinon gérer le vidage du cache c'est la misère), base de données, mémoire partagée, fais ton choix. |
C'est vrai que le fait que le cache reste permanent est un gros avantage, je vais donc opter pour la solution BDD ou répertoire de fichiers, comme tu me le conseilles.
Au niveau de la solution de la BDD, ça ne va pas être long le fait de copier d'un côté grâce à " l'écouteur ", et de lire depuis l'autre programme dans la BDD??? c'est gèrable d'effectuer ces 2 opérations pour 1000-2000 entrées et lecture par seconde?
Sinon c'est vrai qu'avec un ID, incrémenté de 1 à chaque fois d'un côté et de l'autre, ça peut aller vite...
Pour les fichiers, il faut par exemple créer un fichier par minute, et sauter de l'un à l'autre en copie d'un côté et en écriture de l'autre, c'est ça?
Si tu as une bonne doc, des conseils ou autres pour l'une ou l'autre de ces solutions (principalement la solution de la BDD apparemment), je suis preneur
Merci !
Marsh Posté le 30-06-2008 à 14:51:11
1000~2000 entrées/seconde ?
Sacré débit en effet. Je n'ai jamais bossé avec un débit pareil, donc je ne suis pas sûr d'être de bon conseil sur les performances.
Marsh Posté le 30-06-2008 à 14:57:56
Elmoricq a écrit : 1000~2000 entrées/seconde ? |
Si ce n'est pas plus...
Merci quand même de toutes ces précieuses informations!
Si quelqu'un avait une idée sur cette question, je suis très preneur... Je vais lancer quelques tests pour voir si cette solution est envisageable.
Marsh Posté le 30-06-2008 à 15:14:55
Les données pour chaque entrée sont de quelle taille environ?
A+,
Marsh Posté le 30-06-2008 à 15:24:35
gilou a écrit : Les données pour chaque entrée sont de quelle taille environ? |
Ce qu'il faudrait insérer en BDD (pour le traitement par le second démons), c'est de la forme :
host datas (ex: ma_machine 1 1214831700 |SAR|kbswpcad|0) donc tt petit
Marsh Posté le 30-06-2008 à 16:06:36
Donc en gros, il faut que tu traites 64x2000 octets par seconde, soit du 128 ko/s. Je voulais avoir une idée de la capacité de traitement necessaire.
A+,
Marsh Posté le 30-06-2008 à 16:44:56
gilou a écrit : Donc en gros, il faut que tu traites 64x2000 octets par seconde, soit du 128 ko/s. Je voulais avoir une idée de la capacité de traitement necessaire. |
Ouais dans ces eux-là.
Mais l'avis que je souhaitais avoir c'était au niveau des I/O de la BDD, ça peut être envisageable d'écrire à ce débit et de l'autre côté lire et supprimer au fur et à mesure???
Marsh Posté le 30-06-2008 à 16:50:51
Le souci avec la BDD ce n'est pas le débit lui-même (c'est rien du tout 128ko/s), mais le nombre de requêtes par secondes, c'est là qu'est l'inconnue pour moi, je ne sais pas du tout ce que ça peut accepter à ce niveau-là.
Quoi qu'en bulk copy ça doit être très très largement jouable.
J'imagine qu'un minimum de documentation pourra te renseigner là-dessus, je pense que c'est une information facile à trouver.
Marsh Posté le 30-06-2008 à 17:06:31
Elmoricq a écrit : Le souci avec la BDD ce n'est pas le débit lui-même (c'est rien du tout 128ko/s), mais le nombre de requêtes par secondes, c'est là qu'est l'inconnue pour moi, je ne sais pas du tout ce que ça peut accepter à ce niveau-là. |
Qu'est-ce le bulk copy?
Les premiers résultats m'ont l'air bon. Pour l'instant avec 500 I/O, il n'y a aucun soucil, donc c'est encourageant !
Je vais pousser le débit quand j'aurai un protoype de l'appli, pour voir aussi le comportement et tt et tt...
Merci beaucoup de cette précieuse aide !
Marsh Posté le 30-06-2008 à 17:30:25
johnkro a écrit :
|
Je raisonnais en C avec l'API de la BDD que j'utilise, en fait. En PERL si tu utilises DBI (ou autre module qui utilise un driver constructeur) tu n'as pas à t'en soucier, normalement le driver de ta base est optimisé pour passer en bulk tout seul si besoin (bulk copy = copie brute, non loguée, très rapide, non-dénué de risque mais nickel pour ce genre d'opération).
Marsh Posté le 30-06-2008 à 17:53:56
Elmoricq a écrit : |
Ah d'accord. J'utilise DBI en effet.
J'ai poussé un peu les tests et c'est plutot très bon !
Au niveau des insertions par " l'écouteur ", puis de la lecture et suppression par l'appli ( mais sans traitements par cette dernière) :
- à 8000 trames/minute, il n'y a aucun retard (même avec un traitement light), donc ça devrait être amplement suffisant, je vérifierai ça avec des tests plus approfondis et plus poussés !
- a 16000 trames/minute ça écrivait qd même plus vite que ça ne lisait lol ...
Marsh Posté le 30-06-2008 à 18:00:15
johnkro a écrit : - a 16000 trames/minute ça écrivait qd même plus vite que ça ne lisait lol ... |
Objectif atteint donc, on dirait.
Ton écouteur peut gérer tranquillement la charge pendant que la seconde partie du programme peut être en retard sans que ce soit génant.
Marsh Posté le 30-06-2008 à 18:18:04
Elmoricq a écrit : |
Ouais, mais qu'aurais-je fait sans ton aide? lol
Now j'ai plus qu'à fignoler les 2 codes et passer tt ça en qualif...
Une dernière fois pour aujourd'hui merci, et à bientôt pour de nouvelles aventures lol
Marsh Posté le 30-06-2008 à 22:01:47
Pour en revenir aux files d'attente multiple, cela peut être intéressant si tu as un goulot d'étranglement.
Tu peux avoir un monstre de calcul au niveau machine, si tu as 1 seule file d'attente tu as un goulot d'étranglement potentiel. Il est dans ce cas là préférable d'avoir plusieurs process qui lisent et/ou écrivent si la machine est capable de le supporter : autant balancer la sauce sur plusieurs coeurs du processeur plutôt que sur un seul. En ce qui concerne les I/O, généralement les bases de données modernes sont largement optimisées pour faire ce genre de choses avec tout un système de cache et de reprise en cas de crash. Plus encore si tu as une vraie BDD et un DBA sous la main, il peut te tuner ça au petits oignons en fonction du hardware (CPU, RAM, RAID utilisé pour les disques, etc.)
Personnellement je me serais passé de BDD en faisant un process qui lit les messages UDP et qui les redirige vers un des n-process parallèles tournant chacun sur des ports différents. Non pas que je déteste les BDD, au contraire je bosse tous les jours avec Oracle
L'intérêt réside surtout dans le fait qu'on utilise pas de BDD, ce qui enlève toutes les tâches d'administration (purge, défragmentation, sauvegarde, etc.). Bah ouais, la rotation des fichiers de logs, le maintien en bonne santé d'une base, la sauvegarde en cas de crash... c'est du boulot en plus si tu veux une appli qui tient plusieurs années
J'aurais plutôt fait un "chef d'orchestre" qui renvoie les requêtes sur un intervalle de ports avec un processus d'écoute fils derrière chaque port. Pas la peine de modéliser une file d'attente avec une loi de Poisson ou autre joyeuseté statistique, un simple "random" ou une séquence sur l'intervalle de ports suffit.
Par exemple : processus "chef d'orchestre sur le port 4000" et 3 processus fils (fais un nombre de process fils paramétrable ) à partir des ports 4010.
A chaque requête sur le port 4000, ton process chef d'orchestre renvoie la requête sur le port 4010, puis 4011, puis 4012, puis 4010, et ainsi de suite. Tu parallélises le traitement et tout se joue entre le(s) CPU(s), la RAM et la pile IP de l'OS. En plus tu vires une couche supplémentaire pour le cache qui t'ajouteras forcément du boulot de maintenance (admin BDD ou purge de fichiers).
Un exemple tout bête : même si tu n'as qu'une pauvre table que tu alimentes et purge au fil de l'eau, il faudra bien un jour reconstruire l'index qui s'est déséquilibré à force de INSERT et de DELETE parce que t'as mis une clé primaire.
Un autre truc con qui m'est arrivé un jour sur une appli de tracabilité, le process censé purger les données volatiles est parti en cacahuète et ne faisait plus les DELETE correctement... Ca a foutu un bordel monstre et j'ai dû faire opération chirurgie sur la base pour purger sans faire d'arrêt de service, et avec une marge de manoeuvre faible (plus de place disque, tablespaces remplis, petits rollback segments, etc.)
Mais bon je mégare alors que tu as déjà une solution qui tient la route
Marsh Posté le 30-06-2008 à 22:53:33
Pas conne ta solution, et très facile à implémenter aussi.
Pour ma part je bosse dans une structure où les BDDs sont inévitables, administrées, et où une petite table supplémentaire ne se chiffre même pas en centimes, du coup c'est un peu la solution de facilité pour moi, et ça enlève tous les défauts que tu mentionnes (ou plutôt, pour être exact, ils sont masqués par une architecture déjà en place).
Marsh Posté le 01-07-2008 à 00:36:30
J'ai retrouvé un vieux rapport sur un démon TCP fait en Perl qui se contentait d'attribuer un numéro de file d'attente aux clients. Les tests de montée en charges atteignent 10.000 requêtes en 20 sec, mais la courbe est exponentielle et montre une saturation : je n'ai plus "que" 25.000 requêtes pour 60 sec.
Si mes souvenirs sont bon, à l'époque j'étais en Perl 5.005 sous Solaris 8, avec un bi-CPU sparc et 1Go de RAM. Mais à mon avis la vitesse de traitement des requêtes doit essentiellement dépendre de l'OS, et de la couche réseau (hardware+drivers).
C'est sûr qu'une carte rézal achetée à Carrefour installé avec un driver Microsoft sous Windows 2000 (winsocks.dll mal foutu) est bien moins performant qu'un hardware Sun + Solaris 8 qui prenait déjà en charge IPv6 + drivers ethernet du constructeur
Marsh Posté le 01-07-2008 à 11:51:02
Merci de cette longue explication, ça m'aide énormément.
Ce que je vais faire, c'est développer les 2 solutions, les tester et voir laquelle des 2 est viable... Si les 2 fonctionnent, je garderai la meilleur ou celle qui me plait le + lol
Avec la BDD, j'arrive a environ 10.000 req/min, donc si ton chiffre de 25.000 req/min est le bon, je pense que cette solution pourrait bien être celle que je retiendrai.
Comme dirait l'autre : "y'a plu qu'à !"
Marsh Posté le 26-06-2008 à 08:56:10
Bonjour tout le monde,
je suis à la recherche d'idées concernant le traitement d'un flux important de données. En fait, je dois améliorer une application qui traite des informations grâce à une queue IPC. L'application écoute continuellement sur un port en UDP, et elle traite toutes les informations qu'elle reçoit sur ce port. Seulement il y a saturation par moment. Je dois donc trouver un nouveau système pour faire ce traitement, mais je n'ai pas trop d'idées.
Si vous aviez des pistes de recherches...
Merci beaucoup