6
votes

Autocrampe à Redis

Je commence à utiliser Redis et je rencontre le problème suivant.

J'ai un tas d'objets, disons messages dans mon système. Chaque fois qu'un nouveau utilisateur se connecte, je passe les suivants:

  1. augmenter une variable globale, disons g_message_id et enregistrez la valeur de retour de l'augmentation (la valeur actuelle de g_message_id ).

  2. lpush le nouveau message (y compris le ID et le message actuel) dans une liste.

    D'autres clients utilisent la valeur de g_message_id pour vérifier s'il y a de nouveaux messages à obtenir.

    Problème est, un client pourrait croiss le g_message_id , mais pas le temps de lpush le message avant que un autre client essaie de le lire, en supposant qu'il y a un nouveau message.

    En d'autres termes, je cherche un moyen de faire l'équivalent d'ajouter des lignes en SQL et d'avoir un index auto-incrémenté pour travailler avec.

    notes :

    Je ne peux pas utiliser les index de la liste, car je dois souvent supprimer des parties de la liste, ce qui le rend invalide.

    Ma situation en réalité est un peu plus complexe, c'est une version plus simple.

    solution actuelle :

    La meilleure solution que j'ai proposée et ce que je prévois de faire est d'utiliser watch et transactions pour essayer d'effectuer un "autoIncrerement" moi-même.

    Mais c'est un cas d'usage aussi courant dans Redis que je suis surpris qu'il n'y ait pas de réponse existante pour cela, alors je suis inquiet Je fais quelque chose de mal.


0 commentaires

3 Réponses :


8
votes

Si je lis correctement, vous utilisez g_message_id sous forme de séquence d'identification et comme un drapeau pour indiquer que de nouveaux message (s) sont disponibles. Une option est de la diviser en deux variables: une pour attribuer des identificateurs de message et l'autre comme un drapeau à signaler aux clients qu'un nouveau message est disponible.

Les clients peuvent alors comparer la valeur actuelle / antérieure de g_new_message_flag < / strong> Pour savoir quand de nouveaux messages sont disponibles: xxx

alternatif possible, si vos clients peuvent le prendre en charge : Vous voudrez peut-être examiner dans la Redis Publier / S'abonner Commandes, E.G. Les cités pourraient publier des notifications de nouveaux messages et abonner à un ou plusieurs canaux de message pour recevoir des notifications. Vous pouvez conserver le g_msg_queue pour maintenir un arriéré de N messages pour les nouveaux clients, si nécessaire.

mise à jour basé sur le commentaire: si vous voulez chaque client Pour détecter, il existe des messages disponibles, POP Tout cela est disponible et zéro de la liste, une option consiste à utiliser une transaction pour lire la liste: xxx

mise à jour 2 : Compte tenu de la nouvelle information, voici ce que je ferais:

  1. Demandez à vos clients de votre écrivain utilise RPUSH pour ajouter de nouveaux messages à la liste. Cela permet aux clients des lecteurs de commencer à 0 et d'avancer sur la liste pour obtenir de nouveaux messages.
  2. Les lecteurs n'ont besoin que de rappeler l'index du dernier message qu'ils sont extraites de la liste.
  3. Les lecteurs surveillent g_new_message_flag pour savoir quand aller à partir de la liste.
  4. Chaque client de lecteur utilisera ensuite " Land Lrange Index Limit d'index " pour récupérer les nouveaux messages. Supposons qu'un client de lecture ait vu un total de 5 messages, il fonctionnerait " lrange g_msg_queue 5 15 " pour obtenir les 10 prochains messages. Supposons que 3 sont retournés, il se souvient de l'indice 8 . Vous pouvez faire la limite aussi grande que vous le souhaitez et peut parcourir la liste des petits lots.
  5. Le client Reaper devrait définir une montre sur la liste et la supprimer à l'intérieur d'une transaction, abandonner si un client en lisez simultanément.
  6. Lorsqu'un client de lecteur tente de lrange et obtient 0 messages, il peut supposer que la liste a été tronquée et réinitialiser son index sur 0 . .

4 commentaires

Intéressant. Cela conduit à un problème connexe: lorsqu'un client interroge le serveur avec sa copie de "g_new_message_flag", comment le serveur récupère-t-il les messages de la liste? Il peut simplement retirer un certain nombre de messages basés sur la différence entre le drapeau "g_new_message_flag" et le drapeau des utilisateurs ", mais si de nouveaux messages sont ajoutés entre l'opération de soustraction et le PLPOP, le mauvais nombre de messages sera affiché.


Je vois ce que vous voulez dire - si un client est censé faire pop tous les messages disponibles et zéro sortir de la liste, c'est plus délicat. Je vais mettre à jour ma réponse avec quelques pensées.


En fait, je ne veux pas que le client supprime les messages, obtenez simplement les derniers messages. J'ai plusieurs clients différents avec (éventuellement) différentes valeurs de g_msg_queue, et chacune doit lire les derniers messages arrivés. La liste n'est supprimée que périodiquement par un processus d'arrière-plan (disons une fois par jour).


Ahh je t'ai vu mentionner PLOP et supposé qu'ils retiraient les messages du g_msg_queue (LPOP supprime l'entrée la plus à gauche de la liste et le renvoie)



5
votes

Avez-vous vraiment besoin d'identifiants séquentiels uniques? Vous pouvez utiliser UUIDS pour obtenir uniques et horodatage pour vérifier les nouveaux messages. Si vous gardez les horloges sur tous vos serveurs correctement synchronisés, les horodatages avec une deuxième résolution doivent bien fonctionner.

Si vous avez vraiment besoin d'identifiants séquentiels uniques, vous devrez probablement configurer un Server de ticket de style Flickr pour gérer correctement la liste centrale des identifiants. Cela permettrait essentiellement de déplacer votre g_message_id dans une base de données avec une manipulation correcte de transaction.


1 commentaires

Résolu mon problème .. uuid convient parfaitement à mon cas



1
votes

Vous pouvez simuler automatiquement une clé unique pour de nouvelles lignes. Utilisez simplement DBSIZE pour obtenir le nombre actuel de lignes, puis dans votre code, incrémentez ce nombre par 1 et utilisez ce numéro comme clé de la nouvelle ligne. C'est simple et atomique.


0 commentaires