¿Qué es Memcache?
Solución de caché en el entorno de clúster Memcache
MEMCACHE es un sistema de caché de objetos de memoria de memoria distribuido de alto rendimiento. Al mantener una tabla hash unificada y enorme en la memoria, se puede usar para almacenar datos en varios formatos, incluidas imágenes, videos, archivos y resultados de recuperación de bases de datos. En pocas palabras, es llamar a los datos a la memoria y luego leerlos desde la memoria, mejorando enormemente la velocidad de lectura.
Memcache es un proyecto en Danga. Primero fue servido por Livejournal. Originalmente se desarrolló para acelerar la velocidad de acceso de LiveJournal. Más tarde fue adoptado por muchos sitios web grandes.
Memcached se ejecuta en uno o más servidores en modo de demonio y recibe conexiones y operaciones del cliente en cualquier momento.
¿Por qué hay dos nombres Memcache y Memcached?
De hecho, Memcache es el nombre de este proyecto, y Memcached es el nombre principal del archivo del programa en su lado del servidor. Usted sabe lo que quiero decir. Uno es el nombre del proyecto y el otro es el nombre principal del archivo del programa. Lo vi en línea que muchas personas no lo entienden, así que lo mezclé.
MEMCACHED es un sistema de almacenamiento de caché de objetos de memoria de memoria distribuido de alto rendimiento utilizado para reducir la carga de la base de datos y mejorar la velocidad de acceso en aplicaciones dinámicas. Memcached es desarrollado por Danga Interactive para mejorar el acceso a LiveJournal.com. LJ tiene miles de visitas de página dinámicas por segundo y tiene 7 millones de usuarios. Memcached reduce en gran medida la carga de la base de datos, asigna mejor recursos y un acceso más rápido.
Este artículo cubrirá lo siguiente:
Memcache
Memcache es un almacén de valor clave en memoria para pequeñas fragmentos de datos arbitrarios (cadenas, objetos) de los resultados de DataBASECALLS, llamadas de API o representación de páginas.
Es decir, la base de datos de caché en memoria, que es una base de datos de par de valores clave. La base de datos existe para almacenar temporalmente los datos obtenidos de otros servicios en la memoria y se pueden devolver directamente desde el caché HIT cuando los accesos repetidos. Esto no solo acelera las tasas de acceso, sino que también reduce la carga en otros servicios. Aquí, se implementará una versión de un solo servidor de MEMCACHE y admite conexiones simultáneas entre varios clientes.
El cliente establecerá una conexión Telnet con el servidor y luego interactuará con el caché del servidor de acuerdo con el protocolo MEMCACHE. Las instrucciones implementadas aquí son Get, Set y Del. Echemos un vistazo al formato de cada instrucción
colocar
El conjunto es una instrucción de almacenamiento. Al almacenar las características de la instrucción, ingrese la información básica en la primera línea e ingrese su valor correspondiente en la segunda línea.
Establezca <Key> <Signs> <pptime> <bytes> [noreply]/r/n
<valor>/r/n
Si el almacenamiento es exitoso, se devolverá el almacenamiento, y si la Directiva contiene el atributo NorePly, el servidor no devolverá la información.
El contenido de cada dominio en esta directiva es el siguiente:
Si la instrucción no cumple con los criterios, el servidor devolverá el error.
conseguir
Get es un comando Get, y las características de este comando son las siguientes:
Obtener <key>*/r/n
Admite valores de paso de múltiples claves. Si el caché golpea una o más claves, los datos correspondientes se devolverán y finalizarán con END. Si no se realiza un golpe, el mensaje devuelto no contiene el valor correspondiente a la clave. El formato es el siguiente:
Valor <Key> <Stars> <bytes>/r/n <bloque de datos>/r/nValue <Key> <signs> <bytes>/r/n <bloque de datos>/r/nenddel
Eliminar el comando, el formato del comando es el siguiente:
Del <Key> [NorePly]/R/N
Si la eliminación es exitosa, volverá eliminada/r/n, de lo contrario volverá no_found. Si hay un parámetro NorePly, el servidor no devolverá una respuesta.
Zócalo de java
Todo el socket de Java necesita saber es el protocolo TCP, los enchufes y las transmisiones IO. No entraré en detalles aquí. Puede consultar mi serie de artículos. También se recomienda leer la programación de la red Java. Un libro.
Implementación del código
Hay algo mal con la función del mapa aquí. Puede ir a mi dirección de proyecto al final del artículo para ver el diagrama de clases.
Aquí, el modo de instrucción y el modo de fábrica se utilizan para implementar el desacoplamiento de la creación y ejecución de instrucciones. La fábrica de comandos recibirá la línea de comandos y devolverá una instancia de comando. Cada comando tiene un método de ejecución para realizar sus propias operaciones únicas. Solo se publica la implementación especial de la instrucción del Del.
/** * Varias directivas * Actualmente es compatible con Get, SET, Eliminar * * y Custom * Error, End */Public Interface Command {/** * Execute Command * @param lector * @param escritor */void ejecute (lector lector, escritor escritor); / *** Obtenga el tipo de comando* @return*/ comandype getType ();} /*** Instancia única de Directive Factory*/public class CommandFactory {private static commandFactory commandFactory; caché estático privado <emem> memcache; Private CommandFactory () {} public static CommandFactory getInStance (Cache <emitem> Cache) {if (comandante == null) {comandyFactory = new CommandFactory (); memcache = caché; } return CommandFactory; } / ** * Obtener el comando de acuerdo con el tipo de directiva * @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); }}} /*** Eliminar directive de caché*/clase public deletecommand implementa el comando {comando privado final de cadena; Cache final privado <emem> caché; clave de cadena privada; booleano privado noreply; public deletecommand (comando de cadena final, caché final <emitem> cache) {this.command = command; this.cache = caché; initCommand (); } private void initCommand () {if (this.command.contains ("noreply")) {noreply = true; } String [] info = command.split (""); clave = info [1]; } @Override public void ejecute (lector lector, escritor escritor) {bufferedwriter bfw = (bufferedwriter) escritor; Artículo elemento = cache.delete (clave); if (! noreply) {try {if (item == null) {bfw.write ("non_found/r/n"); } else {bfw.write ("eliminado/r/n"); } bfw.flush (); } catch (ioException e) {try {bfw.write ("error/r/n"); bfw.flush (); } catch (ioException e1) {e1.printstackTrace (); } E.PrintStackTrace (); }}} @Override public comandtype getType () {return comandype.search; }}Luego, implementa el servidor de memoria. Para admitir la primera función en primera salida, LinkEdTreeP se utiliza como implementación subyacente, y el método RemoLEdest se reescribe. Al mismo tiempo, el hilo de fondo de Cachemanager también se usa para borrar las entradas de caché vencidos a tiempo.
public class Memcache implementa caché <emem> {private logger logger = logger.getLogger (memcache.class.getName ()); // Use LinkedHashMap para implementar LRU STICATIC ESTÁTICO LINKEDHASHMAP <cadena, elemento> caché; Private final int maxsize; // Cargar factor privado Flotador final default_load_factor = 0.75f; public memcache (final int maxSize) {this.maxSize = maxSize; // Asegúrese de que Cache no se expandirá automáticamente después de que se alcanza MaxSize int this.cache = new LinkedHashMap <String, item> (capacidad, default_load_factor, true) {@Override protegido boolean remoLeLDestEntry (map.entry <string, item> eldest) {if (size ()> maxsize) {logger.info ("El número de caché ha alcanzado el límite superior, y el menos se usará recientemente recientemente ser delecado"); ");"); } size de retorno ()> maxSize; }}; // implementar colecciones de acceso sincronizado. SynchronizedMap (caché); } public sincronizado boolean isfull () {return cache.size ()> = maxSize; } @Override public item get (clave de cadena) {item item = cache.get (clave); if (item == null) {logger.info ("clave en caché:" + clave + "no existir"); regresar nulo; } else if (item! = null && element.isexpired ()) {// Si el caché expira, elimina y return null logger.info ("Lea la clave de la caché:" + clave + "valor:" + item.getValue () + "ha expirado"); cache.remove (clave); regresar nulo; } logger.info ("Leer clave de caché:" + clave + "valor:" + item.getValue () + "tiempo válido restante" + item.remaintime ()); artículo de devolución; } @Override public void set (tecla de cadena, valor de elemento) {logger.info ("Escribir clave para caché:" + clave + "valor:" + valor); cache.put (clave, valor); } @Override public item Elelete (tecla de cadena) {logger.info ("Eliminar la tecla de caché:" + tecla); devolver cache.remove (clave); } @Override public int size () {return cache.size (); } @Override public int capacidad () {return maxSize; } @Override public Iterator <map.entry <string, item >> iterator () {return cache.entryset (). Iterator (); }} /*** Cache Manager* Background Thread* Eliminar caché vencido en caché*/public class Cachemanager implementa Runnable {private logger logger = logger.getLogger (Cachemanager.class.getName ()); // caché público caché <emem> caché; public Cachemanager (caché <emem> cache) {this.cache = cache; } @Override public void run () {while (true) {iterator <map.entry <string, item >> itemIterator = cache.iterator (); while (itemIterator.hasNext ()) {map.entry <string, item> entry = itemIterator.next (); Artículo item = Entry.getValue (); if (item.isexpired ()) {logger.info ("key:" + entry.getKey () + "valor" + item.getValue () + "expirado, eliminado de la base de datos"); itemIterator.remove (); }} try {// Ejecute el programa de fondo cada 5 segundos TimeUnit.seconds.sleep (5); } catch (InterruptedException e) {E.PrintStackTrace (); }}}}Finalmente, implementa un servidor de socket de múltiples subprocesos, donde el SerververSocket está vinculado a una interfaz y entrega el socket aceptado a un hilo adicional para el procesamiento.
/*** servidor*/public class iOServer implementa servidor {stop private boolean; // Número de puerto Private Final Int Port; // Servidor Thread Private ServerSocket Serversocket; Private final logger logger = logger.getLogger (ioserver.class.getName ()); // grupo de subprocesos, la capacidad del hilo es maxconnection private ejecutorservice ejecutorsorservice; Cache final privado <emem> caché; Public iOServer (int Port, int maxconnection, caché <emitem> cache) {if (maxconnection <= 0) tirar nueva ilegalArgumentException ("El número máximo de conexiones compatibles debe ser entero positivo"); this.port = puerto; EjecutorService = Ejecutors.NewFixedThreadPool (maxconnection); this.cache = caché; } @Override public void start () {try {Serversocket = new Serversocket (puerto); logger.info ("El servidor comienza en el puerto"+puerto+"); while (true) {try {Socket Socket = Serversocket.accept (); logger.info (" Recibió una conexión de "+Socket.getLocalAddress ()+" "); ExecutorService.SubMit (New Sockethandler (Shower, cache));} Catch (IoCception E) E.PrintStackTrace (); !serverSocket.isClosed(); } /** * Stop the server*/ public void shutDown(){ try { if (serverSocket!=null){ serverSocket.close(); } } catch (IOException e) { e.printStackTrace(); } }} /*** Manejar las conexiones de cada cliente* Cierre la conexión después de obtener la instrucción final S*/public class SocketHandler implementa Runnable {private static logger logger = logger.getlogger (sockethandler.class.getName ()); enchufe final privado de enchufe; Cache final privado <emem> caché; acabado booleano privado; Public Sockethandler (Socket S, Cache <emitem> Cache) {this.socket = s; this.cache = caché; } @Override public void run () {try {// Get Socket Input Stream final BufferedReader lector = new BufferedReader (new InputStreamReader (Socket.getInputStream ())); // Get Socket Outtut Stream Final BufferedWriter Writer = new BufferedWriter (nuevo OutputStreamWriter (Socket.getOutputStream ())); CommandFactory CommandFactory = CommandFactory.getInStance (caché); while (! Finalizar) {String final Commandline = Reader.Readline (); logger.info ("IP:" + Socket.getLocalAddress () + "Directiva:" + Commandline); if (commandline == null || commandline.trim (). isEmpty ()) {continuar; } // Use la fábrica de comandos para obtener el comando comando comando final de comando = commandFactory.getCommand (línea de comandos); Command.Execute (lector, escritor); if (command.gettype () == comandype.end) {logger.info ("solicitar para cerrar la conexión"); acabado = verdadero; }}} Catch (ioException e) {E.PrintStackTrace (); logger.info ("Cerrar la conexión de" + Socket.getLocalAddress () + ""); } finalmente {try {if (socket! = null) {socket.close (); }} catch (ioException e) {E.PrintStackTrace (); }}}}Haga clic aquí para la dirección del proyecto. Si crees que es bastante bueno, espero que puedas darme una estrella.
Referencias
Sitio web oficial de Memcached
Protocolo de Memcache
Lo anterior es todo el contenido de este artículo. Espero que sea útil para el aprendizaje de todos y espero que todos apoyen más a Wulin.com.