La aplicación de alto rendimiento / concurrentes asegurar -Netty en el redisson

fondo

prefacio

Redisson Github: https://github.com/redisson/redisson

Redisson web oficial: https://redisson.pro/

Redisson se lleva a cabo sobre la base de un Redis en Java en memoria cuadrícula de datos (datos en memoria Grid). No sólo proporciona una serie de objetos distribuidos Java utilizado comúnmente también proporciona una serie de servicios distribuidos. Incluyendo ( BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish / Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service, Scheduler service) redisson proporciona el método más simple y más conveniente de Redis. Redisson objetivo es promover la separación de preocupaciones para los usuarios de Redis (Separación de preocupación), por lo que los usuarios podrán centrarse más estrechamente en la lógica de negocio.

Los siguientes son estructura redisson:

Redisson inferior utiliza Netty marco. Soporte Redis 2.8 o posterior, apoyan Java1.6 + o posterior.

cliente de inicialización

createBootstrap

org.redisson.client.RedisClient # createBootstrap

private Bootstrap createBootstrap(RedisClientConfig config, Type type) {
        Bootstrap bootstrap = new Bootstrap()
                        .resolver(config.getResolverGroup())
          							//1.指定配置中的IO类型
                        .channel(config.getSocketChannelClass())
          							//2.指定配置中的线程模型
                        .group(config.getGroup());
  			//3.IO处理逻辑
        bootstrap.handler(new RedisChannelInitializer(bootstrap, config, this, channels, type));
  			//4. 指定bootstrap配置选项
        bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, config.getConnectTimeout());
        bootstrap.option(ChannelOption.SO_KEEPALIVE, config.isKeepAlive());
        bootstrap.option(ChannelOption.TCP_NODELAY, config.isTcpNoDelay());
        config.getNettyHook().afterBoostrapInitialization(bootstrap);
        return bootstrap;
    }

Se puede ver en el código anterior, los iniciados cliente la clase de arranque es Bootstrapel responsable de iniciar el cliente y el servidor de conexión, la clase de arranque creado después de la finalización de los siguientes, que describen el proceso iniciado por el cliente.

R. En primer lugar, tenemos que especificar el modelo de hilos a la misma, unidades de lectura y escritura de datos de conexión. Entonces, por defecto especificado redisson modelo IPNioSocketChannel

II. A continuación, a las especifica la clase de enlace guía una serie de procesamiento, esta es la definición de las principales conexiones lógicas de procesamiento de servicio, no entiendo que no importa, vamos a analizar en detalle más adelante

RedisChannelInitializer

org.redisson.client.handler.RedisChannelInitializer

RedisChannelInitializer

 @Override
    protected void initChannel(Channel ch) throws Exception {
      	// 开启SSL终端识别能力
        initSsl(config, ch);
        
        if (type == Type.PLAIN) {
          	//Redis正常连接处理类
            ch.pipeline().addLast(new RedisConnectionHandler(redisClient));
        } else {
          	//Redis订阅发布处理类
            ch.pipeline().addLast(new RedisPubSubConnectionHandler(redisClient));
        }
        
        ch.pipeline().addLast(
          	//链路检测狗
            connectionWatchdog,
          	//Redis协议命令编码器
            CommandEncoder.INSTANCE,
          	//Redis协议命令批量编码器
            CommandBatchEncoder.INSTANCE,
          	//Redis命令队列
            new CommandsQueue());
        
        if (pingConnectionHandler != null) {
           //心跳包连接处理类
            ch.pipeline().addLast(pingConnectionHandler);
        }
        
        if (type == Type.PLAIN) {
          	//Redis协议命令解码器
            ch.pipeline().addLast(new CommandDecoder(config.getExecutor(), config.isDecodeInExecutor()));
        } else {
          	//Redis订阅发布解码器
            ch.pipeline().addLast(new CommandPubSubDecoder(config.getExecutor(), config.isKeepPubSubOrder(), config.isDecodeInExecutor()));
        }

        config.getNettyHook().afterChannelInitialization(ch);
    }

procesamiento de enlace de la figura 1 redisson en la figura.

cadena de procesamiento redisson

cadena de procesamiento redisson

Pipeline dentro ChannelHandler redisson más, lo que recogí CommandEncodery CommandDecoderestar análisis de código fuente.

CommandDecoder_Encoder

reconexión fracaso

mecanismo org.redisson.client.handler.ConnectionWatchdog # reconexión reconexión

private void reconnect(final RedisConnection connection, final int attempts){
		//重试时间越来越久
    int timeout = 2 << attempts;
    if (bootstrap.config().group().isShuttingDown()) {
        return;
    }
    
    try {
        timer.newTimeout(new TimerTask() {
            @Override
            public void run(Timeout timeout) throws Exception {
                tryReconnect(connection, Math.min(BACKOFF_CAP, attempts + 1));
            }
        }, timeout, TimeUnit.MILLISECONDS);
    } catch (IllegalStateException e) {
        // skip
    }
}

Netty en la gestión del temporizador, modo de uso de la rueda de tiempo con la función Hash, Rueda Tiempo traduce en todo el tiempo, que es implementar un temporizador temporizador algoritmo clásico.

Este método de declaración es la siguiente:

 /**
     * Schedules the specified {@link TimerTask} for one-time execution after
     * the specified delay.
     *
     * @return a handle which is associated with the specified task
     *
     * @throws IllegalStateException       if this timer has been {@linkplain #stop() stopped} already
     * @throws RejectedExecutionException if the pending timeouts are too many and creating new timeout
     *                                    can cause instability in the system.
     */
    Timeout newTimeout(TimerTask task, long delay, TimeUnit unit);

Este método requiere un tiempo cuando los objetos TimerTask saben lo que se va a realizar a la lógica, y requiere que el retardo de valores de tiempo y unidad de tiempo TimeUnit.

Redis codificador comando de protocolo

Los autores creen que el cuello de botella del sistema de base de datos Redis generalmente no es el tráfico de la red, pero la base de datos en su propia lógica interna. Así que incluso si el protocolo Redis utilizando el flujo de texto de los residuos todavía puede obtener acceso a un alto rendimiento. REDIS todos los datos en la memoria, usando un único subproceso para proporcionar servicios desde el exterior, en el caso de un único nodo para ejecutar un núcleo CPU completo puede alcanzar ultra-altas QPS 10w / s de.

RESP es una secuencia corta de protocolo Redis. Se trata de un protocolo basado en texto intuitiva, la ventaja es lograr un excelente rendimiento muy simple, analítica.

La estructura del protocolo de transferencia de datos REDIS Los cinco tipos diferentes de la unidad mínima, junto con avance de línea uniforme en el extremo de la unidad de transporte \r\n.

  1. cuerda suelta en +el comienzo del símbolo.
  2. cadena de múltiples líneas $al comienzo del símbolo, seguido por la longitud de la cadena.
  3. valor entero :a partir símbolos, seguido por una serie de números enteros.
  4. Los mensajes de error -comienzan con un símbolo.
  5. En la matriz de *número de longitud principio, seguido de la matriz.

cuerda suelta hola mundo

+hello world\r\n

Multi-línea de la cadena hola mundo

$11\r\nhello world\r\n

líneas múltiples pueden por supuesto ser expresados ​​cadena de línea.

entero 1024

:1024\r\n

Mal tipo incorrecto

-WRONGTYPE Operation against a key holding the wrong kind of value\r\n

Matriz [1,2,3]

*3\r\n:1\r\n:2\r\n:3\r\n

NULL indica una cadena de una pluralidad de filas, pero la longitud debe ser escrito -1.

$-1\r\n

cadena vacía se representa mediante líneas múltiples cuerdas de 0 relleno.

$0\r\n\r\n

Tenga en cuenta que hay dos \r\n. ¿Por qué dos? Debido a que dos \r\nentre, a través de la cadena vacía.

org.redisson.client.handler.CommandEncoder # encode ()

private static final char ARGS_PREFIX = '*';
private static final char BYTES_PREFIX = '$';
private static final byte[] CRLF = "\r\n".getBytes();


@Override
    protected void encode(ChannelHandlerContext ctx, CommandData<?, ?> msg, ByteBuf out) throws Exception {
        try {
          	//redis命令前缀
            out.writeByte(ARGS_PREFIX);
            int len = 1 + msg.getParams().length;
            if (msg.getCommand().getSubName() != null) {
                len++;
            }
            out.writeCharSequence(Long.toString(len), CharsetUtil.US_ASCII);
            out.writeBytes(CRLF);
            
            writeArgument(out, msg.getCommand().getName().getBytes(CharsetUtil.UTF_8));
            if (msg.getCommand().getSubName() != null) {
                writeArgument(out, msg.getCommand().getSubName().getBytes(CharsetUtil.UTF_8));
            }
          	......
        } catch (Exception e) {
            msg.tryFailure(e);
            throw e;
        }
    }

private void writeArgument(ByteBuf out, ByteBuf arg) {
    out.writeByte(BYTES_PREFIX);
    out.writeCharSequence(Long.toString(arg.readableBytes()), CharsetUtil.US_ASCII);
    out.writeBytes(CRLF);
    out.writeBytes(arg, arg.readerIndex(), arg.readableBytes());
    out.writeBytes(CRLF);
}

REDIS decodificador comando de protocolo

org.redisson.client.handler.CommandDecoder # readBytes

 private static final char CR = '\r';
 private static final char LF = '\n';
 private static final char ZERO = '0';

private ByteBuf readBytes(ByteBuf is) throws IOException {
    long l = readLong(is);
    if (l > Integer.MAX_VALUE) {
        throw new IllegalArgumentException(
                "Java only supports arrays up to " + Integer.MAX_VALUE + " in size");
    }
    int size = (int) l;
    if (size == -1) {
        return null;
    }
    ByteBuf buffer = is.readSlice(size);
    int cr = is.readByte();
    int lf = is.readByte();
  	//判断是否以\r\n开头
    if (cr != CR || lf != LF) {
        throw new IOException("Improper line ending: " + cr + ", " + lf);
    }
    return buffer;
}

serialización de datos

clase de objeto redisson se utiliza para codificar una serialización de objetos y deserialización, con el fin de conseguir el objeto que se lee y se almacena en el interior Redis. Redisson ofrece la siguiente aplicación objeto de codificación, para su elección:

Codificación nombre de la clase explicación
org.redisson.codec.JsonJacksonCodec Jackson JSON codifica codificación predeterminada
org.redisson.codec.AvroJacksonCodec Avro un binario JSON codificación
org.redisson.codec.SmileJacksonCodec Sonrisa otra codificación JSON binario
org.redisson.codec.CborJacksonCodec CBOR y una codificación binaria JSON
org.redisson.codec.MsgPackJacksonCodec MsgPack de nuevo una codificación JSON binario
org.redisson.codec.IonJacksonCodec Ion Amazon Amazon ión formato de codificación similar a JSON
org.redisson.codec.KryoCodec Kryo objeto binario serialización codificación
org.redisson.codec.SerializationCodec JDK secuencia de codificación
org.redisson.codec.FstCodec La FST 10 veces JDK rendimiento serialización y 100% de codificación compatible
org.redisson.codec.LZ4Codec LZ4 secuencia de codificación de objeto compacto
org.redisson.codec.SnappyCodec Snappy Otra secuencia objeto tipo de codificación de compresión
org.redisson.client.codec.JsonJacksonMapCodec Jackson codifica mediante la asignación basada en la clase. La información se puede utilizar para evitar la clase de serialización, y para su uso para resolver byte[]los problemas encontrados.
org.redisson.client.codec.StringCodec código de cadena pura (sin conversión)
org.redisson.client.codec.LongCodec Pure codificación digital de longitud completa (sin conversión)
org.redisson.client.codec.ByteArrayCodec matriz de bytes codificada
org.redisson.codec.CompositeCodec Para combinar juntos una pluralidad de diferentes codificación

códec

codec

public interface Codec {

  	//返回用于HMAP Redis结构中哈希映射值的对象解码器
    Decoder<Object> getMapValueDecoder();

  	//返回用于HMAP Redis结构中哈希映射值的对象编码器
    Encoder getMapValueEncoder();

  	//返回用于HMAP Redis结构中哈希映射键的对象解码器
    Decoder<Object> getMapKeyDecoder();

  	//返回用于HMAP Redis结构中哈希映射键的对象编码器
    Encoder getMapKeyEncoder();

    //返回用于除HMAP之外的任何存储Redis结构的对象解码器
    Decoder<Object> getValueDecoder();

    //返回用于除HMAP之外的任何存储Redis结构的对象编码器
    Encoder getValueEncoder();

    //返回用于加载解码过程中使用的类的类加载器对象
    ClassLoader getClassLoader();

}

BaseCodec

org.redisson.client.codec.BaseCodec

BaseCodec

  1. Llaves del codec HashMap para el procesamiento de una clase de objeto usando el proceso de descomposición clase codec común.

    //返回用于除HMAP之外的任何存储Redis结构的对象解码器
        Decoder<Object> getValueDecoder();
    
    //返回用于除HMAP之外的任何存储Redis结构的对象编码器
        Encoder getValueEncoder();
    

SerializationCodec

org.redisson.codec.SerializationCodec

Descifrador

SerializationCodec-decodificador

codificador

SerializationCodec-codificador

Supongo que te gusta

Origin www.cnblogs.com/sanshengshui/p/12669011.html
Recomendado
Clasificación