序文
RedissonのGithub:https://github.com/redisson/redisson
Redisson公式サイト:https://redisson.pro/
Redissonは、Javaインメモリデータグリッド(メモリ内データグリッド)上のRedisに基づいて実現されます。これは、一般的に使用されるJava分散オブジェクトのシリーズは、分散サービスの数を提供して提供するだけでなく。含む(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はRedisのが最も簡単で便利な方法を提供します。Redisson目的は、ユーザーがビジネスロジックにより狭く焦点を当てることができるようになりますように、Redisの(関心の分離)の利用者のための関心事の分離を促進することです。
以下はRedisson構造です:
-
独立したノードとしてRedissonが放出実行するために独立して他のノードの使用することができる分散実行サービスと分散スケジューリングタスクサービスをリモートタスクに。
Redisson底が使用ネッティーのフレームを。サポートのRedis 2.8以降、後でJava1.6 +をサポートしますか。
クライアントの初期化
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;
}
あなたは上記のコードから見ることができ、ブートクラスがあるクライアントを開始Bootstrap
、クライアントとサーバーの接続は、次の完了後に作成されたブートストラップクラスを開始する責任は、私たちは、クライアントが開始したプロセスを説明します。
A.まず、我々はそれに、ドライブは読み取りと書き込みのデータ接続をスレッドモデルを指定する必要があります。その後、redissonのデフォルトはIOモデルを指定しましたNioSocketChannel
II。次に、ガイドリンククラスに一連の処理を指定し、これは論理接続を処理する主なサービスの定義である、それは問題で、私たちは、後に詳細に分析し、しません理解していません
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);
}
図中、図1 Redissonリンク処理。
Redisson処理チェーン
私が選んだよりChannelHandler Redisson内部のパイプライン、
CommandEncoder
およびCommandDecoder
ソースコード解析すること。
故障の再接続
org.redisson.client.handler.ConnectionWatchdog#再接続、再接続メカニズム
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
}
}
タイマー管理でネッティー、ハッシュ時間ホイールモードの使用は、タイムホイールは、それは、古典的なアルゴリズムタイマータイマーを実装することで、時間のラウンドに翻訳しました。
声明のこのメソッドは、この次のとおりです。
/**
* 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);
この方法は、TimerTaskをオブジェクトがロジックに実行されるかを知る時間を必要とし、単位遅延時間値と時間TimeUnitでを必要とします。
Redisのprotocolコマンドエンコーダ
著者は、Redisのデータベースシステムのボトルネックは、一般的にネットワークトラフィックではなく、独自の内部ロジック上のデータベースと信じています。だから、廃棄物のテキストフローを使用してのRedisプロトコルは依然として高いパフォーマンスへのアクセスを得ることができる場合であっても。使用して、メモリ内のすべてのデータをRedisのシングルスレッドの超高QPS 10ワット/秒に達することができ、完全なCPUコアを実行する単一ノードの場合には、外部サービスを提供します。
RESPはRedisのプロトコルの短い配列です。これは、利点は非常に単純な、優れた分析性能を達成することである、直感的なテキストベースのプロトコルです。
データ転送プロトコルの構造は、搬送部の端部で均一なラインフィードと共に、最小単位の5種類をRedisの\r\n
。
- で単一の文字列
+
のシンボルの始まり。 - 複数行の文字列
$
シンボルの先頭には、文字列の長さが続きます。 - 整数値
:
シンボルを開始するには、整数の文字列が続きます。 - エラーメッセージは
-
記号で始まります。 - アレイ内の
*
長番号最初、アレイが続きます。
単一の文字列ハローワールド
+hello world\r\n
マルチライン文字列のハローワールド
$11\r\nhello world\r\n
複数行の文字列はもちろん、行の文字列を表現することができます。
整数 1024
:1024\r\n
間違った間違ったタイプ
-WRONGTYPE Operation against a key holding the wrong kind of value\r\n
配列 [1,2,3]
*3\r\n:1\r\n:2\r\n:3\r\n
NULLは、複数行の文字列を示しているが、長さが書き込まれるべき-1。
$-1\r\n
空の文字列は 0塗りつぶし複数行の文字列で表されます。
$0\r\n\r\n
2があることに注意してください\r\n
。なぜ2?2ため、\r\n
空の文字列の間、間。
org.redisson.client.handler.CommandEncoder#エンコード()
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のプロトコルコマンドデコーダ
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;
}
シリアル化データ
Redissonオブジェクトクラスが読み込まれ、Redisの内部に格納されている目的を達成するために、オブジェクトのシリアライゼーションおよびデシリアライゼーションを符号化するために使用されます。Redissonはあなたの選択のために、アプリケーションをコードする以下のオブジェクトが用意されています。
コーディングクラス名 | 説明 |
---|---|
org.redisson.codec.JsonJacksonCodec |
ジャクソンJSONエンコーディングデフォルトのエンコーディング |
org.redisson.codec.AvroJacksonCodec |
アブロ AバイナリJSONエンコーディング |
org.redisson.codec.SmileJacksonCodec |
スマイル別のバイナリJSONエンコーディングを |
org.redisson.codec.CborJacksonCodec |
CBORバイナリJSONエンコーディング |
org.redisson.codec.MsgPackJacksonCodec |
MsgPack再びバイナリJSONエンコーディング |
org.redisson.codec.IonJacksonCodec |
アマゾンイオンアマゾンイオンは、JSONのような形式をコーディング |
org.redisson.codec.KryoCodec |
Kryoバイナリオブジェクトシリアライゼーションエンコーディング |
org.redisson.codec.SerializationCodec |
JDKのコード配列 |
org.redisson.codec.FstCodec |
FST 10倍JDKシリアライゼーション性能と100%互換性のある符号化 |
org.redisson.codec.LZ4Codec |
LZ4コンパクトなオブジェクトコード配列 |
org.redisson.codec.SnappyCodec |
スナッピー圧縮タイプをコードする別のオブジェクトの配列を |
org.redisson.client.codec.JsonJacksonMapCodec |
ジャクソンは、クラスベースのマッピングを使用してエンコードされました。情報は、シリアライゼーションクラスを避けるために使用することができ、かつ使用のために解決するためにbyte[] 発生した問題を。 |
org.redisson.client.codec.StringCodec |
純粋な文字列コード(変換しません) |
org.redisson.client.codec.LongCodec |
コーディング純粋デジタル全長(変換なし) |
org.redisson.client.codec.ByteArrayCodec |
エンコードされたバイト配列 |
org.redisson.codec.CompositeCodec |
互いに異なる複数のコーディングを結合するため |
コーデック
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
-
共通コーデッククラス分解プロセスを使用してオブジェクトのクラスを処理するためのHashMapコーデックのキー。
//返回用于除HMAP之外的任何存储Redis结构的对象解码器 Decoder<Object> getValueDecoder(); //返回用于除HMAP之外的任何存储Redis结构的对象编码器 Encoder getValueEncoder();
SerializationCodec
org.redisson.codec.SerializationCodec
デコーダ
エンコーダ