Is it safe to use MongoDB sessions with PHP-FPM (multi-threads)?

Hello,

I want to use MongoDB sessions to get a causal consistency guarantee. However I use nginx with PHP-FPM which is multi-threaded. Excluding MongoDB documentation Read Isolation, Consistency, and Recency — MongoDB Manual specifies “Applications must ensure that only one thread at a time executes these operations in a client session.”.

So I’m stuck at this level and I don’t really see how to get out of it. The only solution I see is to make PHP-FPM single thread which I obviously do not want for the advantages it provides.

Do you have any ideas ?

Thank you,

Bonjour,

Je souhaite utiliser les sessions MongoDB pour obtenir une garantie de cohérence causale.

Cependant j’utilise nginx avec PHP-FPM qui est multi-threads. Hors la documentation de MongoDB

précise “Applications must ensure that only one thread at a time executes these operations in a client session.”.

Je suis donc bloqué à ce niveau est je ne vois pas trop comment m’en sortir. La seule solution que je vois

est de rendre PHP-FPM single thread ce que je ne souhaite evidemment pas pour les avantages que cela procure.

Avez-vous des idées ?

Merci,

Bonjour Alexis,

Si je comprends bien, tu utilises PHP pour servir différents clients. Ce qu’il ne faut pas, c’est qu’un thread A utilise la session causale du thread B. Tant que le thread A utilise la session causale créée dans le thread A et ainsi de suite, c’est OK.

Par contre si tes thread sont interconnectés et partagent des ressources (ici les sessions causales), c’est là que ça commence à sentir le sapin.

Donc ─ pour moi ─ si chaque utilisateur utilise les ressources qu’il a créé au sein de son thread, tout est OK.

Cheers,
Maxime.

Je complète ma réponse sur le multi thread: Il est aussi possible d’assurer une consistence forte de la donnée sur un document à condition d’utiliser linerizable sur le read concern et majority sur le write concern au sein de différent threads.

Lire la doc ici qui clarifie tout ça:

Cheers,
Maxime.

Bonjour Maxime,

Tout d’abord un grand merci pour vos réponses. J’ai l’habitude depuis de nombreuse années d’utiliser PHP et MongoDB. En revanche je suis totalement débutant en serveur. Et j’ai donc du mal à comprendre si le système que j’ai développé respecte votre schéma ou non.

Pourriez-vous m’aider à le déterminer ? Je vous expose mon cas.

J’ai 2 serveurs VPS miroir connectés à la même base de donnée MongoDB. J’utilise un load balancer Cloudflare pour répartir la charge entre ces 2 serveurs.

Les VPS possèdent plusieurs coeurs et utilisent nginx avec PHP-FPM.

Je fabrique actuellement un agenda en ligne.
J’utilise ajax pour appeler un fichier php à intervalle régulier permettant de générer les rendez-vous récurrents de l’ensemble des utilisateurs.
Je suppose qu’il s’agit la d’une erreur car je pourrai très bien utiliser une tache cron pour gérer cette tache enfin le problème n’est pas la.

Ce programme PHP va récupérer dans la base de donnée MongoDB les rendez-vous qui vont bientôt avoir lieu (dans moins de 2 semaines) pour les créer réellement (la récurrence existe mais pas encore le rendez-vous sans cette étape).

Il me faut donc une session causale pour créer une sorte de verrou afin d’être certain qu’une autre requête ajax ne va pas créer un ou plusieurs doublons des rendez-vous.

Je ne m’y connais pas assez pour savoir si les utilisateurs vont rester sur le même thread ou non… Pourriez-vous m’éclairer la dessus ?

Merci pour votre aide précieuse.

Hello,

Je ne suis pas certain que la session causal va éviter la double insertion. Je pense qu’une autre manière de résoudre le problème serait de créer un index unique sur un champ (ou réutiliser le champ _id) et de faire en sorte que chaque meeting ait une valeur unique associée à ce champ. Ca éviterait de lever une erreur si le meeting existe déjà et de ne pas l’insérer à nouveau.
Une session causal n’est pas un verrou sur la collection, c’est très différent.

Après j’ai du mal à comprendre le fonctionnement en batch avec des requêtes ajax que tu essayes de mettre en place, mais pourquoi ne pas juste processer le fichier une seule fois et faire un insertMany pour tous les meetings qui doivent être créer ? Ca éviterait de créer des doublons aussi, non ?

Cheers,
Maxime.

PS: J’y connais rien à PHP :wink: ! Dernière ligne de code en PHP c’était en 2008/2009 je pense environ.

Bonjour Maxime,

Le problème de créer tous les rdvs avec un insertMany est que la recurrence peut-être tous les jours jusqu’à l’année 2100. Ce qui donnerai: 2100-2022=78*365=28470 soit plus de 28 000 rdvs à créer et cela pour chaque récurrence. Pareil pour un utilisateur souhaitant modifier la récurrence il faudrait alors modifier les 28 000 rdvs.

C’est pour résoudre ce problème que j’ai créé une collection “rdvs”. Quand un rdv est récurrent je stocke l’intervalle de récurrence ainsi que la date de la prochaine récurrence.

2 semaines avant la prochaine récurrence je créer le rdv via le fichier PHP appelé à intervalle régulier par mes utilisateurs.

Je ne l’ai pas encore écrit mais le script PHP fonctionnerai je pense de cette façon :

  1. Récupérer tous les rdvs dont le champ “recurrence_next” < (maintenant +2 semaines)

  2. Pour chacun de ces rdvs le dupliquer en changer la date d’arrivée (arr_time), la date de création du rdv (time), en ajoutant la référence de la recurrence (recurrence_id) et en retirant l’ensemble des autres champs “recurrence_*”.

  3. Mettre à jour le rdv initial avec la nouvelle “recurrence_next”

Cela permet en effet de créer les rdvs au fur et à mesure sans avoir à en créer et peut-être modifier 28 000. J’envois aussi des sms de confirmation de rendez-vous automatiquement et ça m’évite que mon script envois 28 000 sms lors de la création de la récurrence.

Mon problème actuel est que si le fichier PHP est exécuté entre les étapes 1 à 3 j’ai peur de me retrouver avec des rdvs doublons. L’idée de l’index unique est très bonne ! Mais je ne vois pas trop comment le mettre en place dans mon cas.

Le fichier PHP dans mon cas fonctionne un peu comme le ramasse-miettes (Garbage Collection) de PHP. Il ne vise pas spécifiquement l’utilisateur qui le déclenche (de façon transparente via ajax) mais l’ensemble des utilisateurs. De la même façon que le ramasse-miettes (Garbage Collection) de PHP qui est déclenché de façon transparente par les utilisateurs et supprime les sessions inactives de l’ensemble des utilisateurs.

Voici un exemple de rdv en BDD :
screen

J’espère avoir réussi à être plus clair,

Merci de continuer à essayé de trouver une solution à mon problème.

Alexis,