2011-02-04 1 views
0

Je suis en train de concevoir un système de cache de données qui pourrait contenir une très grande quantité d'enregistrements à la fois, et j'ai besoin de savoir quel conteneur stl utiliser et comment l'utiliser. L'application est que j'ai une très grande base de données d'enregistrements pour les utilisateurs - quand ils se connectent à mon système, je veux tirer leur dossier et mettre en cache des données telles que le nom d'utilisateur et plusieurs propriétés importantes. En interagissant avec le système, je mets à jour et accède à leurs propriétés. Plusieurs propriétés sont très volatiles et je le fais pour éviter de "claquer" sur la base de données avec de nombreuses transactions. Aussi, j'ai rarement besoin d'utiliser la base de données pour le tri ou quoi que ce soit - j'utilise cela comme un fichier de sauvegarde binaire glorifié (c'est pourquoi je suis heureux de mettre les enregistrements en mémoire cache ..); un objectif plus important pour moi est de pouvoir évoluer vers un grand nombre d'utilisateurs.Mise en cache des données de MySQL DB - technique et conteneur STL approprié?

Lorsque l'utilisateur se déconnecte, le serveur s'arrête, ou périodiquement de manière circulaire (juste au cas où ..), je veux écrire leurs données dans la base de données.

Le serveur conserve son propre:

vector <UserData *> loggedInUsers; 

Avec des choses comme nom d'utilisateur tenue UserData (string) et d'autres propriétés de la DB, ainsi que d'autres données temporaires comme les poignées de réseau. Mon premier Q est, si j'ai besoin de trouver un utilisateur spécifique dans ce vecteur, quel est le le plus rapide moyen de le faire et y at-il un autre conteneur stl que je peux utiliser pour le faire plus rapidement? Qu'est-ce que je fais maintenant est de créer un itérateur, démarrez-le à loggedInUsers.begin() et itérer à .end(), en vérifiant * iter-> nom d'utilisateur == "foo" et retour quand il est trouvé. Si le nom d'utilisateur est à la fin du vecteur, ou si le vecteur a 5000 utilisateurs, il s'agit d'un délai important.

Mon deuxième Q est, comment est-ce que je peux planifier à tour de rôle ces données à réécrire dans la base de données? Je peux appeler une fonction chaque fois que je suis prêt à écrire quelques enregistrements dans la base de données. Mais je ne peux pas tenir un itérateur au vecteur, car il deviendra invalide. Ce que je voudrais faire est d'avoir une file d'attente en rotation où je peux accéder à la tête de la file d'attente, la persister dans la base de données, puis la faire pivoter pour être la fin de la file d'attente. Cela semble beaucoup de frais généraux .. quel type pourrais-je utiliser pour faire mieux?

Mon troisième Q est, j'utilise le serveur MySQL et le connecteur libmysqlclient/C .. existe-t-il une sorte de cache intégré qui pourrait résoudre ce problème "gratuitement", ou existe-t-il une autre technique? Je suis ouvert aux suggestions

Répondre

1

A1. vous êtes mieux avec une carte, c'est un arbre qui fait la recherche pour vous. Testez avec une carte et (en supposant que vous avez le bon compilateur) ou une hash_map (qui fait la même chose, mais le mécanisme de recherche est différent).Ils ont des caractéristiques de performance différentes pour différents types de charges de travail de stockage de données.

A2. Une liste serait probablement mieux pour vous - pousser vers l'avant, retirer la fin. (une deque peut aussi être utilisée, mais vous ne pouvez pas garder un itérateur si vous l'effacez, vous pouvez le faire avec une liste). push_back et pop_front (ou vice-versa) vous permettra de conserver une file d'attente de données en cache.

A3. Vous pouvez essayer SQLite, qui est une mini-base de données conçue pour les besoins simples de stockage de DB au niveau de l'application. Il peut aussi fonctionner entirely in-memory.

+0

A1: Merci. A2: Qu'en est-il de la performance de tirer/pousser, chaque opération supposera que je suis en train de jeter/ajouter un nouvel élément, n'est-ce pas? Y a-t-il une structure de données qui est faite pour simplement «tourner»? A3: Plusieurs applications peuvent atteindre la base de données. Plus grande question de suivi: A1 et A2 Je veux combiner en une seule chose afin que je puisse conserver toutes ces données dans une carte et faire pivoter à travers pour persister des mises à jour vers la base de données .. comment puis-je accomplir cela? – Nektarios

+0

Je suis désolé sur A3 Je réalise que vous suggérez d'utiliser SQLite en mémoire comme structure de données. Ce serait génial en fait – Nektarios

1

Vous ne dites pas ce que votre système fait ou comment il est accédé, mais ce genre de technique ne sera probablement pas bien à l'échelle (parce que finalement vous manquerez de mémoire et de tout ce que vous utilisez pour trouver des informations ne sera pas aussi efficace qu'une base de données) et ne traitera pas nécessairement correctement les utilisateurs simultanés, sauf si vous vous assurez que les données peuvent être partagées correctement entre eux. Cela dit .. vous pourriez être mieux d'utiliser une carte (http://www.cplusplus.com/reference/stl/map/) avec le nom d'utilisateur comme clé.

En termes d'écriture dans la base de données, pourquoi ne pas stocker une structure séparée (une file d'attente) que vous pouvez effacer chaque fois que vous l'écrivez dans la base de données? Tant que vous stockez des pointeurs, il n'utilisera pas beaucoup plus de mémoire. Ce qui m'amène à .. plutôt que d'utiliser des pointeurs, vous devriez jeter un oeil aux pointeurs intelligents (par exemple boost's shared_ptr) qui vous permettent de les passer sans vous soucier de la propriété.

+0

Merci, bon conseil, et vous avez raison, j'aurais pu mieux définir mon application. Mes données sont petites, disons 64 octets absolus max. Cela signifie que dans 1 Go de RAM, j'ai 16 millions d'utilisateurs en mémoire, donc ce n'est pas un problème (je vais d'abord manquer de descripteurs de socket réseau). J'aime votre idée de juste tenir les pointeurs et voir ce que vous voulez dire avec shared_ptr aider – Nektarios

Questions connexes