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 como un nodo independiente se puede usar independientemente de los otros nodos para realizar liberación servicios de ejecución distribuida y servicio tarea de programación distribuida en la tarea remoto.
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 Bootstrap
el 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
@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
Pipeline dentro ChannelHandler redisson más, lo que recogí
CommandEncoder
yCommandDecoder
estar análisis de código fuente.
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
.
- cuerda suelta en
+
el comienzo del símbolo. - cadena de múltiples líneas
$
al comienzo del símbolo, seguido por la longitud de la cadena. - valor entero
:
a partir símbolos, seguido por una serie de números enteros. - Los mensajes de error
-
comienzan con un símbolo. - 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\n
entre, 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 |
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
-
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
codificador