C'est une question soudaine, mais comment gérez-vous les Jobs que vous exécutez régulièrement?
Même en 2018, lorsque le serveur sans serveur est populaire, il se peut que certaines personnes utilisent toujours l'ancien cron
.
Dans cet article, je voudrais suggérer un moyen de remplacer un serveur exécutant le traitement par lots par cron
sans temps d'arrêt. Aussi, je voudrais expliquer pourquoi c'est possible en jetant un coup d'œil au code source de cron
. (Pour des raisons de temps, nous ne gérons cronie
que sur CentOS7
.)
En fonctionnement réel, vous devez concevoir un système de gestion des tâches approprié, mais cet article présentera une méthode trouble.
TL; DR
crond
arrêtécrond
sur l'ancien serveur et démarrez crond
sur le nouveau serveur.cron
est un planificateur de travaux basé sur le temps utilisé dans les systèmes d'exploitation UNIX et convient à la planification de tâches exécutées régulièrement. Il est également utilisé pour la gestion du système et pour l'exécution de tâches de services réels.
Par exemple, si vous enregistrez un travail comme celui-ci avec crontab -e
, le lot d'agrégation sera exécuté à 0 minute toutes les heures.
0 * * * * /bin/bash -l -c '/home/vagrant/bin/execute_hourly_aggregation'
Pour plus d'informations, consultez les articles Wikipédia ci-dessous et les différents documents qui servent de références.
https://ja.wikipedia.org/wiki/Crontab
Dans cette méthode proposée, nous visons à remplacer par zéro temps d'arrêt dans un environnement où un lot est toujours exécuté, comme un lot qui prend beaucoup de temps ou un grand nombre de lots.
Cependant, sachez que la méthode proposée ne peut pas atteindre un temps d'arrêt strict sur un serveur où de nouvelles tâches sont lancées toutes les minutes.
J'expliquerai dans l'environnement suivant, qui a été mis en place dans Vagrant. La version est légèrement différente du code source à expliquer, mais il n'y a pas de changements majeurs, donc j'espère que vous comprenez le mécanisme.
[vagrant@localhost ~]$ cat /etc/redhat-release
CentOS Linux release 7.5.1804 (Core)
[vagrant@localhost ~]$ yum list installed | grep cron
Failed to set locale, defaulting to C
cronie.x86_64 1.4.11-19.el7 @anaconda
cronie-anacron.x86_64 1.4.11-19.el7 @anaconda
crontabs.noarch 1.11-6.20121102git.el7 @anaconda
Tout d'abord, préparons un nouveau serveur. En ce qui concerne la structure des fichiers, il n'y a pas de problème avec la même structure de fichiers que l'ancien serveur, mais faites-le de manière à satisfaire les deux suivants.
Par exemple, dans la série CentOS7, utilisez la commande service
pour l'arrêter.
[vagrant@localhost ~]$ sudo service crond stop
Redirecting to /bin/systemctl stop crond.service
[vagrant@localhost ~]$ service crond status
Redirecting to /bin/systemctl status crond.service
● crond.service - Command Scheduler
Loaded: loaded (/usr/lib/systemd/system/crond.service; enabled; vendor preset: enabled)
Active: inactive (dead) since Tue 2018-09-11 17:44:33 UTC; 11s ago
Process: 3406 ExecStart=/usr/sbin/crond -n $CRONDARGS (code=exited, status=0/SUCCESS)
Main PID: 3406 (code=exited, status=0/SUCCESS)
Laissez le temps aux tâches cron de s'arrêter.
L'important ici n'est pas lorsque le travail est terminé, mais lorsque le travail n'est plus expulsé.
Regardez le processus ci-dessous crond
avec ps aux f
etc. et assurez-vous que le dernier traitement par lots sur l'ancien serveur a été lancé.
root 3492 0.0 0.3 26096 1704 ? Ss 17:45 0:00 /usr/sbin/crond -n
root 3921 0.0 0.4 82144 2488 ? S 18:05 0:00 \_ /usr/sbin/CROND -n
vagrant 3924 0.0 0.3 12992 1568 ? Ss 18:05 0:00 | \_ /bin/bash -l -c echo "start at $(date)" && sleep 120 && echo "end at $(date)"
vagrant 3937 0.0 0.0 7764 352 ? S 18:05 0:00 | | \_ sleep 120
crond
sur l'ancien serveur et démarrez crond
sur le nouveau serveurEnfin, nous passerons aux travaux de remplacement.
Tout d'abord, arrêtez crond
sur l'ancien serveur et démarrez crond
sur le nouveau serveur.
À ce stade, l'ancien serveur ne lancera plus de nouvelles opérations par lots.
crond
a cessé, mais il y a encore des emplois qui crond
ont été lancés. Attendons la fin du traitement par lots. À ce moment, le travail lancé par crond
a perdu son parent principal et est maintenant suspendu sous / usr / sbin / CROND
.
root 4199 0.0 0.4 82144 2488 ? S 18:18 0:00 /usr/sbin/CROND -n
vagrant 4201 0.0 0.3 12992 1564 ? Ss 18:18 0:00 \_ /bin/bash -l -c echo "start at $(date)" && sleep 120 && echo "end at $(date)"
vagrant 4214 0.0 0.0 7764 352 ? S 18:18 0:00 | \_ sleep 120
Attendez que le dernier traitement par lots soit terminé, puis arrêtez poliment.
Pourquoi est-ce possible?
Revérifions l'état du processus à l'exécution tout en lisant le code cron
pendant un moment.
Tout d'abord, "cron" boucle le processus suivant "while" jusqu'à ce qu'il reçoive un signal de "SIGINT" ou "SIGTERM".
while (!got_sigintterm) {
int timeDiff;
enum timejump wakeupKind;
/* ... wait for the time (in minutes) to change ... */
do {
cron_sleep(timeRunning + 1, &database);
set_time(FALSE);
} while (!got_sigintterm && clockTime == timeRunning);
if (got_sigintterm)
break;
timeRunning = clockTime;
// ~Omission~
handle_signals(&database);
}
https://github.com/cronie-crond/cronie/blob/40b7164227a17058afb4f3d837ebb3263943e2e6/src/cron.c#L354-L481
En d'autres termes, vous pouvez voir que le nouveau lot s'exécute toutes les (environ) toutes les minutes de cette vérification.
Le nouveau lot est découvert par find_jobs ()
et fonctionne comme un descendant du crond
original via job_runqueue ()
, do_command ()
, child_process ()
.
root 3492 0.0 0.3 26096 1704 ? Ss 17:45 0:00 /usr/sbin/crond -n
root 3921 0.0 0.4 82144 2488 ? S 18:05 0:00 \_ /usr/sbin/CROND -n
vagrant 3924 0.0 0.3 12992 1568 ? Ss 18:05 0:00 | \_ /bin/bash -l -c echo "start at $(date)" && sleep 120 && echo "end at $(date)"
vagrant 3937 0.0 0.0 7764 352 ? S 18:05 0:00 | | \_ sleep 120
Alors que se passe-t-il si vous vous arrêtez ici avec SIGTERM
?
Jetons un coup d'œil au code de la dernière partie de nettoyage.
#if defined WITH_INOTIFY
if (inotify_enabled && (EnableClustering != 1))
set_cron_unwatched(fd);
if (fd >= 0 && close(fd) < 0)
log_it("CRON", pid, "INFO", "Inotify close failed", errno);
#endif
log_it("CRON", pid, "INFO", "Shutting down", 0);
(void) unlink(_PATH_CRON_PID);
return 0;
https://github.com/cronie-crond/cronie/blob/40b7164227a17058afb4f3d837ebb3263943e2e6/src/cron.c#L482-L495
As-tu remarqué? Au lieu d '«attendre» ou «tuer» le processus enfant ou petit-enfant, le parent est tranquillement mort, confiant à l'enfant le traitement du petit-enfant.
root 4199 0.0 0.4 82144 2488 ? S 18:18 0:00 /usr/sbin/CROND -n
vagrant 4201 0.0 0.3 12992 1564 ? Ss 18:18 0:00 \_ /bin/bash -l -c echo "start at $(date)" && sleep 120 && echo "end at $(date)"
vagrant 4214 0.0 0.0 7764 352 ? S 18:18 0:00 | \_ sleep 120
Par conséquent, les nouveaux travaux ne sont pas supprimés, tandis que les travaux déjà supprimés peuvent être terminés jusqu'à la fin. (C'est un peu douloureux)
Puisque crond
est implémenté très simplement, il est possible de le remplacer par zéro temps d'arrêt même avec une méthode brute telle que la méthode proposée. Bien sûr, en fonctionnement réel, c'est un domaine qui devrait être systématisé correctement, mais j'espère que vous serez intéressé par le «cron» familier.
Recommended Posts