Qu'est-ce que Memcache?
Solution de cache dans un environnement de cluster memcache
MemCache est un système de cache d'objet de mémoire distribué haute performance. En maintenant une table de hachage unifiée et énorme en mémoire, il peut être utilisé pour stocker des données dans divers formats, y compris les images, les vidéos, les fichiers et les résultats de récupération de la base de données. En termes simples, il s'agit d'appeler les données en mémoire, puis de les lire de mémoire, améliorant ainsi considérablement la vitesse de lecture.
Memcache est un projet à Danga. Il a été servi par LiveJournal. Il a été initialement développé pour accélérer la vitesse d'accès de LiveJournal. Il a ensuite été adopté par de nombreux grands sites Web.
Memcached s'exécute sur un ou plusieurs serveurs en mode démon et reçoit à tout moment des connexions et opérations clients.
Pourquoi y a-t-il deux noms memcache et memcached?
En fait, Memcache est le nom de ce projet, et Memcached est le nom de fichier du programme principal côté serveur. Vous savez ce que je veux dire. L'un est le nom du projet et l'autre est le nom du fichier du programme principal. Je l'ai vu en ligne que beaucoup de gens ne le comprennent pas, alors je l'ai mélangé.
Memcached est un système de mise en cache d'objet de mémoire distribué haute performance utilisé pour réduire la charge de base de données et améliorer la vitesse d'accès dans les applications dynamiques. Memcached est développé par Danga Interactive pour améliorer l'accès à livejournal.com. LJ possède des milliers de visites dynamiques par seconde et 7 millions d'utilisateurs. Memcached réduit considérablement la charge de base de données, alloue mieux les ressources et un accès plus rapide.
Cet article couvrira ce qui suit:
Memcache
Memcache est une boutique de valeurs clés en mémoire pour de petites morceaux de données arbitraires (chaînes, objets) à partir des résultats des appels de données, des appels API ou un rendu de page.
Autrement dit, la base de données de cache en mémoire, qui est une base de données de paires de valeurs clés. La base de données existe pour stocker temporairement les données obtenues à partir d'autres services en mémoire et peut être renvoyée directement à partir du cache de hit lors des accès répétés. Cela accélère non seulement les taux d'accès, mais réduit également la charge sur d'autres services. Ici, une version serveur unique de Memcache sera implémentée et prend en charge les connexions simultanées entre plusieurs clients.
Le client établira une connexion Telnet avec le serveur, puis interagira avec le cache du serveur en fonction du protocole Memcache. Les instructions implémentées ici sont Get, Set et Del. Jetons un coup d'œil au format de chaque instruction
ensemble
SET est une instruction de stockage. Lors du stockage des caractéristiques de l'instruction, saisissez des informations de base dans la première ligne et saisissez sa valeur correspondante dans la deuxième ligne.
SET <CIED> <LAPLOS> <EXPTIME> <YTTES> [NOREPLY] / R / N
<value> / r / n
Si le stockage réussit, stocké sera renvoyé et si la directive contient l'attribut noreply, le serveur ne renvoie pas les informations.
Le contenu de chaque domaine de cette directive est le suivant:
Si l'instruction ne répond pas aux critères, le serveur renvoie l'erreur.
obtenir
GET est une commande get, et les caractéristiques de cette commande sont les suivantes:
obtenir <Key> * / r / n
Il prend en charge les valeurs de passage de plusieurs clés. Si le cache frappe une ou plusieurs clés, les données correspondantes seront renvoyées et se termineront par fin. Si aucun coup n'est fait, le message renvoyé ne contient pas la valeur correspondant à la clé. Le format est le suivant:
Valeur <Teyy> <Dlate> <YTESTS> / R / N <Block de données> / R / Nvalue <Key> <Dlate> <YTESTS> / R / N <Block de données> / R / NENDDEL
Supprimer la commande, le format de la commande est le suivant:
del <1 key> [noreply] / r / n
Si la suppression est réussie, elle renverra supprimé / r / n, sinon il renverra not_found. S'il y a un paramètre noreply, le serveur ne renvoie pas de réponse.
Sobre Java
Tout ce que Java Socket doit savoir est le protocole TCP, les prises et les flux IO. Je n'entrerai pas dans les détails ici. Vous pouvez vous référer à ma série d'articles. Il est également recommandé de lire la programmation du réseau Java. Un livre.
Implémentation de code
Il y a quelque chose qui ne va pas avec la fonction de carte ici. Vous pouvez accéder à mon adresse de projet à la fin de l'article pour afficher le diagramme de la classe.
Ici, le mode d'instruction et le mode d'usine sont utilisés pour implémenter le découplage de la création et de l'exécution d'instructions. L'usine de commande recevra la ligne de commande et renverra une instance de commande. Chaque commande a une méthode d'exécution pour effectuer ses propres opérations uniques. Seule la mise en œuvre spéciale de l'instruction DEL est publiée ici.
/ ** * Diverses directives * prend actuellement en charge GET, SET, DELETE * * et Custom * Erreur, end * / Commande d'interface publique {/ ** * EXECUTER COMMAND * @Param Reader * @param écrivain * / void execute (Reader Reader, écrivain écrivain); / ** * Obtenez le type de la commande * @return * / CommandType getType ();} / ** * Instance unique de Directive Factory * / public class commandFactory {private static CommandFactory CommandFactory; cache statique privé <élément> memcache; CommandFactory privé () {} public static CommandFactory getInstance (cache <teticle> cache) {if (CommandFactory == null) {CommandFactory = new CommandFactory (); memcache = cache; } return CommandFactory; } / ** * Obtenez la commande en fonction du type de directive * @param Commandline * @return * / public Command GetCommand (String Commandline) {if (Commandline.matches ("^ set. * $")) {Return new SetCommand (Commandline, MemCache); } else if (Commandline.matches ("^ get. * $")) {return new GetCommand (Commandline, memcache); } else if (Commandline.matches ("^ del. * $")) {return new DeleteCommand (Commandline, memcache); } else if (Commandline.matches ("^ end $")) {return new EndCommand (Commandline); } else {return new ErrorCommand (Commandline, errorCommand.errorType.Error); }}} / ** * Supprimer la directive de cache * / classe publique DeleteCommand implémente la commande {Commande de chaîne finale privée; cache final privé <élément> cache; clé de chaîne privée; booléen privé norcé; public DeleteCommand (Commande finale de chaîne, cache final <élément> cache) {this.command = commande; this.cache = cache; initCommand (); } private void initCommand () {if (this.command.contains ("noreply")) {noreply = true; } String [] info = command.split (""); key = info [1]; } @Override public void execute (Reader Reader, écrivain écrivain) {BufferedWriter bfw = (BufferedWriter) Writer; Item item = cache.delete (key); if (! noreply) {try {if (item == null) {bfw.write ("not_found / r / n"); } else {bfw.write ("supprimé / r / n"); } bfw.flush (); } catch (ioException e) {try {bfw.write ("error / r / n"); bfw.flush (); } catch (ioException e1) {e1.printStackTrace (); } e.printStackTrace (); }}} @Override public CommandType getType () {return commandType.Search; }}Ensuite, implémentez le serveur de mémoire. Afin de prendre en charge la fonction de première sortie, LinkedTreemap est utilisée comme implémentation sous-jacente et la méthode de supprimer le plus est réécrite. Dans le même temps, le thread d'arrière-plan de CacheManager est également utilisé pour effacer les entrées de cache expirées dans le temps.
classe publique MemCache implémente Cache <teticle> {private logger logger = logger.getLogger (memcache.class.getName ()); // Utilisez LinkedHashmap pour implémenter LRU Private Static LinkedHashMap <String, élément> Cache; Final privé int MaxSize; // Facteur de chargement privé final float default_load_factor = 0,75f; public memcache (final int maxSize) {this.maxsize = maxSize; // Assurez-vous que le cache ne se développera pas automatiquement après que MaxSize est atteint int la capacité = (int) math.ceil (maxsize / default_load_factor) + 1; this.cache = new LinkedHashmap <String, item> (capacité, default_load_factor, true) {@Override protégée booléen devatelDestentry (map.entry <string, item> aîné) {if (size ()> maxSize) {Logger.info ("le numéro de cache a atteint la limite supérieure, et la moindre entrée récemment utilisée sera dissoute"); } return size ()> maxSize; }}; // Implémentez les collections d'accès synchronisées.SynchronizedMap (Cache); } public synchronisé boolean isfull () {return cache.size ()> = maxSize; } @Override public item get (string key) {item item = cache.get (key); if (item == null) {logger.info ("key in cache:" + key + "not exist"); retourner null; } else if (item! = null && item.isexpired ()) {// Si le cache expire, supprimez et renvoyez Null Logger.info ("Lire Key From Cache:" + Key + "Value:" + item.getValue () + "a expiré"); cache.remove (clé); retourner null; } logger.info ("Lire Key de Cache:" + Key + "Value:" + item.getValue () + "Temps valide restant" + item.remaintime ()); return item; } @Override public void set (string key, item value) {logger.info ("key write to cache:" + key + "value:" + value); cache.put (clé, valeur); } @Override public item delete (string key) {logger.info ("supprimer la touche de cache:" + key); return cache.remove (key); } @Override public int size () {return cache.size (); } @Override public int Capacité () {return maxSize; } @Override public iterator <map.entry <string, item >> iterator () {return cache.entryset (). Iterator (); }} / ** * Cache Manager * Thread d'arrière-plan * Supprimer le cache expiré dans le cache * / classe publique CacheManager implémente Runnable {private logger logger = logger.getLogger (cacheManager.class.getName ()); // cache cache cache <temment> cache; public cacheManager (cache <teticle> cache) {this.cache = cache; } @Override public void run () {while (true) {iterator <map.entry <string, item >> iteleTiterator = cache.iterator (); while (iteTiterator.hasnext ()) {map.entry <string, item> entry = iteTiterator.next (); Élément item = entry.getValue (); if (item.isexpired ()) {logger.info ("key:" + entry.getKey () + "value" + item.getValue () + "Expired, supprimé de la base de données"); iteleterator.remove (); }} essayez {// exécuter le programme d'arrière-plan toutes les 5 secondes timeunit.seconds.sleep (5); } catch (InterruptedException e) {e.printStackTrace (); }}}}Enfin, implémentez un serveur de socket multi-thread, où le SERVERSOCKET est lié à une interface et remettez la prise acceptée à un thread supplémentaire pour le traitement.
/ ** * Server * / public class ioServer implémente Server {private boolean stop; // Numéro de port privé Port final int; // Fermer Thread private serversocket serversocket; Logger final privé = logger.getLogger (ioServer.class.getName ()); // Pool de thread, la capacité du thread est MaxConnection Private Final ExecutorService ExecutorService; cache final privé <élément> cache; public ioServer (port int, int maxconnection, cache <temate> cache) {if (maxconnection <= 0) lance un nouveau IllégalArgumentException ("Le nombre maximum de connexions prises en charge doit être un entier positif"); this.port = port; ExecutorService = exécutor.NewFixEdThreadPool (MaxConnection); this.cache = cache; } @Override public void start () {try {serversocket = new serversocket (port); Logger.info ("le serveur démarre sur le port" + port + "); while (true) {try {socket socket = serversocket.accept (); logger.info (" a reçu une connexion de "+ socket.getLocalAddress () +" "); EMEMPORORSERVICE.SUBMIT (New Sockethandler (socket, cache)); E.PrintStackTrace ();}}} Catch (ioException e) {Logger.log (niveau. ! SERVERSOCKET.Assled ();} / ** * Arrêtez le serveur * / public void shutdown () {try {if (serversocket! = null) {serversocket.close ();}}}}}} / ** * Gérer les connexions de chaque client * Fermez la connexion après avoir obtenu l'instruction de fin s * / classe publique Sockethandler implémente Runnable {private static logger logger = logger.getLogger (sockethandler.class.getName ()); Prise à douille finale privée; cache final privé <élément> cache; finition booléenne privée; Public Sockethandler (socket s, cache <élément> cache) {this.socket = s; this.cache = cache; } @Override public void run () {try {// Get Socket Input Stream Final BuffereDReader Reader = new BufferedReader (new InputStreamReader (socket.getInputStream ())); // Obtenir le flux de sortie de socket final bufferedwriter writer = new BufferedWriter (new OutputStreamWriter (socket.getOutputStream ())); CommandFactory CommandFactory = CommandFactory.getInstance (Cache); while (! finir) {final string commandline = reader.readline (); Logger.info ("IP:" + socket.getLocalAddress () + "Directive:" + Commandline); if (Commandline == null || Commandline.trim (). IsEmpty ()) {Continuer; } // Utilisez l'usine de commande pour obtenir l'instance de commande final commande command command = CommandFactory.getCommand (Commandline); Command.execute (lecteur, écrivain); if (Command.getType () == CommandType.end) {logger.info ("Demande pour fermer la connexion"); finition = true; }}} catch (ioException e) {e.printStackTrace (); Logger.info ("Fermez la connexion à partir de" + socket.getLocalAddress () + ""); } enfin {try {if (socket! = null) {socket.close (); }} catch (ioException e) {e.printStackTrace (); }}}}Veuillez cliquer ici pour l'adresse du projet. Si vous pensez que c'est plutôt bien, j'espère que vous pourrez me donner une étoile.
Références
Site officiel Memcached
Protocole Memcache
Ce qui précède est tout le contenu de cet article. J'espère que cela sera utile à l'apprentissage de tous et j'espère que tout le monde soutiendra davantage Wulin.com.