PHP, MySQL, Cron Job – Méthode efficace pour maintenir datatables actuelles / live dans de grandes tables?

C'est surtout de la théorie, alors je m'excuse si ça devient verbeux.

Context

Le projet sur lequel je travaille tire des informations d'autres sites (externes, non hébergés par nous). Nous aimerions avoir des informations aussi proches que possible de la vie, afin que nos users reçoivent des informations immédiatement pertinentes. Cela signifie surveiller et mettre à jour la table en permanence.

Il est difficile de montrer mon travail précédent, mais j'ai cherché haut et bas ces dernières semaines, pour "maintenir datatables en direct dans les bases de données" et "mettre à jour instantanément la database lorsque des changements externes sont faits". Mais tout en vain. J'imagine que le problème de la tenue à jour de dossiers est courant, et je ne suis donc pas certain que des solutions approfondies semblent si rares.

Pour restr avec les lignes direcsortingces pour SO, je ne cherche pas d'opinions, mais plutôt pour les meilleures pratiques actuelles et les methods les plus couramment utilisées / acceptées, efficaces dans l'indussortinge.

Actuellement, avec un cron job , le mieux que nous pouvons faire est de lancer un process toutes les minutes.

 * * * * * cd /home/.../public_html/.../ && /usr/bin/php .../robot.php >/dev/null 2>&1 

Le fait est que nous tirons des données de plusieurs milliers d'autres sites (chaque ligne est un site), et parfois une mise à jour peut prendre quelques minutes ou plus. Appeler la fonction seulement une fois par minute n'est pas assez bon. Idéalement, nous voulons une résolution quasi instantanée .

Vérifier si une ligne doit être mise à jour est rapide. Essentiellement juste votre comparaison de hachage simple:

 if(hash(current) != hash(previous)){ ... update row ... } 

L'utilisation de process lancés exclusivement par le travail cron signifie que si une ligne finit par être mise à jour, le process est bloqué jusqu'à ce qu'il soit terminé ou jusqu'à ce que le travail cron triggers un nouveau process une minute plus tard.

Pas de bueno! Pas bien! Si, par une horrible tournure du destin, chaque ligne devait être mise à jour, cela pourrait prendre des heures (ou plus) avant que tous les loggings soient à jour. Et à ce moment-là, les lignes qui avaient déjà été passées seraient périmées.

Remarque: La database est configurée de sorte que les lignes en cours de mise à jour soient inaccessibles aux nouveaux process. La fonction parcourt essentiellement la table, trouve la prochaine ligne disponible qui n'a pas été lue / mise à jour et plonge. Une fois la mise à jour terminée, elle continue jusqu'à la prochaine ligne disponible.

Chaque process est supprimé lorsqu'il atteint la fin de la table ou lorsque toutes les lignes de la table sont marquées comme lues. À ce stade, toutes les lignes sont réinitialisées à non lues et le process recommence.

Avec la quantité de données collectées, la seule façon d'améliorer la résolution est d'avoir plusieurs process en même time.

Mais combien est trop?

Solution possible (méthode)

La meilleure méthode que j'ai trouvée jusqu'ici, pour parcourir toutes les lignes le plus rapidement possible , est la suivante:

  1. Cron Job appelle le premier process (P1)

  2. P1 survole la table jusqu'à ce qu'elle trouve une ligne non lue et nécessite une mise à jour, et plonge dans

  3. Dès que P1 entre dans la ligne, il appelle un deuxième process identique (P2) pour continuer à partir de ce point

  4. P2 survole la table jusqu'à ce qu'elle trouve une ligne non lue et nécessite une mise à jour.

  5. Dès que P2 entre dans la rangée, il appelle un troisième process identique (P3) pour continuer à partir de ce point

… etc.

Essentiellement, chaque fois qu'un process entre dans une ligne pour le mettre à jour, un nouveau process est appelé pour continuer.

MAIS … les process parents ne sont pas morts. Cela signifie que dès qu'ils ont terminé leurs mises à jour, ils recommencent à explorer la table, à la search de la prochaine ligne disponible.

ET … en plus de tout cela, un nouveau travail cron est toujours tiré chaque minute.

Cela signifie que potentiellement des milliers de process identiques pourraient fonctionner en même time. Le nombre de process ne peut pas dépasser le nombre d'loggings dans la table. Dans le pire des cas, chaque ligne est mise à jour simultanément et un ou deux travaux cron sont déclenchés avant la fin des mises à jour. Les tâches cron vont immédiatement mourir, car aucune ligne n'est disponible pour la mise à jour. Comme chaque process se termine avec ses mises à jour, il mourrait aussi immédiatement pour la même raison.

Le scénario ci-dessus est le pire des cas. Il est peu probable que plus de 5 ou 10 lignes aient besoin d'être mises à jour à chaque passage, mais théoriquement, il est possible que chaque ligne soit mise à jour simultanément.

Améliorations possibles (principalement sur les ressources, pas sur la vitesse ou la résolution)

  1. Surveillez et limitez le nombre de process en cours autorisés et tuez les nouveaux qui sont déclenchés. Mais alors cela soulève des questions comme "combien est trop?", Et "quel est le nombre minimum requirejs pour atteindre une certaine résolution?"

  2. Demandez à chaque process de marquer plusieurs lignes à la fois (5-10) et de ne pas continuer jusqu'à ce que toutes les lignes de l'set aient été traitées. Cela aurait pour effet de diminuer le nombre maximum de process simultanés d'un facteur de plusieurs lignes marquées à la fois.

Comme je l'ai dit au début, c'est sûrement un problème commun pour les architectes de bases de données. Existe-t-il une méthode meilleure / plus rapide / plus efficace que celle que j'ai définie pour le maintien des dossiers actuels?

Merci de restr avec moi!

Tout d'abord, j'ai tout lu! Je devais me tapoter à l'arrière pour ça 🙂

Ce que vous cherchez probablement, c'est une queue de travail. Une queue est essentiellement une ligne comme celle que vous findez dans un supermarché, et une travailleuse est la femme au comptoir qui reçoit l'argent et qui fait tout pour chaque client. Quand il n'y a pas de client, elle ne travaille pas, et quand c'est le cas, elle travaille.

Quand il y a beaucoup de clients dans le centre commercial, plus de travailleurs vont sur les comptoirs vides, et les gens qui achètent des produits d'épicerie se répartissent entre eux.

J'ai beaucoup écrit sur les files d'attente récemment, et celui que je recommand le plus est Beanstalk . C'est simple à utiliser, et il utilise l'API Pheanstalk si vous envisagez de créer des files d'attente et des travailleurs dans php (et de là contrôlez ce qui se passe dans votre database dans MySQL).

Un exemple de l'apparence d'un script de queue et d'un certificate de travail est le suivant (vous appendiez évidemment votre propre code pour l'adapter à vos besoins spécifiques et vous pourriez générer autant de travailleurs que vous le souhaitez. varier en fonction de la quantité de requests que vous avez dans votre queue):

Ajouter des tâches à la queue

 <?php $pheanstalk = new Pheanstalk('127.0.0.1:11300'); $pheanstalk ->useTube("my_queue") ->put("UPDATE mytable SET price = price + 4 WHERE stock = GOOG");//sql query for instance ?> 

D'après votre description, il semble que vous définissez des transactions, ce qui interdit certaines mises à jour alors que d'autres sont en cours d'implémentation. C'est en fait une bonne raison d'utiliser une queue car si un travail de queue expire , il est envoyé en haut de la file (au less dans la queue pheanstalk que je décris), ce qui signifie qu'il ne sera pas perdu d'un timeout d'attente.

Script travailleur

 <?php $pheanstalk = new Pheanstalk('127.0.0.1:11300'); if ($job = $pheanstalk ->watch('my_queue') ->ignore('default') ->reserve())//retreives the job if there is one in the queue { echo $job->getData();//instead of echoing you would //have your query execute at this point $pheanstalk->delete($job);//deletes the job from the queue } } ?> 

Vous auriez à faire quelques changements comme la design combien de travailleurs vous auriez. Vous pourriez mettre 1 travailleur dans une boucle while obtenant tous les travaux et les exécutant 1 par un, puis appeler d'autres scripts de travail pour aider dans le cas où vous voyez que vous avez exécuté 3 et plus arrivent. Il y a plusieurs façons de gérer la queue, mais c'est ce qui est souvent utilisé dans des situations comme celle que vous avez décrite.

Un autre grand avantage des files d'attente d'une bibliothèque comme recommandé comme pheanstalk est qu'il est très polyvalent. Si, à l'avenir, vous décidez que vous souhaitez organiser vos travailleurs différemment, vous pouvez le faire facilement, et de nombreuses fonctions facilitent votre travail. Aucune raison de réinventer la roue.