总体展示一个Lettuce异步get时序
通过时序图可以发现MasterSlaveChannelWriter主要提供一个负载分配的功能,并不是真正的命令发送服务
下面通过源码分析实现过程
public static <K, V> StatefulRedisMasterSlaveConnection<K, V> connect(RedisClient redisClient, RedisCodec<K, V> codec, Iterable<RedisURI> redisURIs) { LettuceAssert.notNull(redisClient, "RedisClient must not be null"); LettuceAssert.notNull(codec, "RedisCodec must not be null"); LettuceAssert.notNull(redisURIs, "RedisURIs must not be null"); List<RedisURI> uriList = LettuceLists.newList(redisURIs); LettuceAssert.isTrue(!uriList.isEmpty(), "RedisURIs must not be empty"); if (isSentinel(uriList.get(0))) { return connectSentinel(redisClient, codec, uriList.get(0)); } else { return connectStaticMasterSlave(redisClient, codec, uriList); } }
private static <K, V> StatefulRedisMasterSlaveConnection<K, V> connectSentinel(RedisClient redisClient, RedisCodec<K, V> codec, RedisURI redisURI) { //创建拓扑提供者为哨兵拓扑 TopologyProvider topologyProvider = new SentinelTopologyProvider(redisURI.getSentinelMasterId(), redisClient, redisURI); //创建哨兵拓扑刷新服务 SentinelTopologyRefresh sentinelTopologyRefresh = new SentinelTopologyRefresh(redisClient, redisURI.getSentinelMasterId(), redisURI.getSentinels()); //利用拓扑提供者和redisClient创建主备拓扑刷新服务 MasterSlaveTopologyRefresh refresh = new MasterSlaveTopologyRefresh(redisClient, topologyProvider); //创建主备连接提供者 MasterSlaveConnectionProvider<K, V> connectionProvider = new MasterSlaveConnectionProvider<>(redisClient, codec, redisURI, Collections.emptyMap()); //使用主备拓扑刷新服务获取所有节点将其设置到连接提供者中 connectionProvider.setKnownNodes(refresh.getNodes(redisURI)); //使用连接提供者创建主备通道写入器 MasterSlaveChannelWriter<K, V> channelWriter = new MasterSlaveChannelWriter<>(connectionProvider); //创建连接 StatefulRedisMasterSlaveConnectionImpl<K, V> connection = new StatefulRedisMasterSlaveConnectionImpl<>(channelWriter, codec, redisURI.getTimeout()); connection.setOptions(redisClient.getOptions()); Runnable runnable = () -> { try { LOG.debug("Refreshing topology"); List<RedisNodeDescription> nodes = refresh.getNodes(redisURI); if (nodes.isEmpty()) { LOG.warn("Topology refresh returned no nodes from {}", redisURI); } LOG.debug("New topology: {}", nodes); connectionProvider.setKnownNodes(nodes); } catch (Exception e) { LOG.error("Error during background refresh", e); } }; try { //向连接注册可关闭服务 connection.registerCloseables(new ArrayList<>(), sentinelTopologyRefresh); //绑定哨兵拓扑结构变化执行逻辑 sentinelTopologyRefresh.bind(runnable); } catch (RuntimeException e) { connection.close(); throw e; } return connection; }
public StatefulRedisConnectionImpl(RedisChannelWriter writer, RedisCodec<K, V> codec, Duration timeout) { super(writer, timeout); this.codec = codec; //创建异步步连接 this.async = newRedisAsyncCommandsImpl(); //创建同步连接 this.sync = newRedisSyncCommandsImpl(); //创建响应式连接 this.reactive = newRedisReactiveCommandsImpl(); }
protected RedisAsyncCommandsImpl<K, V> newRedisAsyncCommandsImpl() { //使用装饰器模式对当前实例进行增强 return new RedisAsyncCommandsImpl<>(this, codec); }
public RedisAsyncCommandsImpl(StatefulRedisConnection<K, V> connection, RedisCodec<K, V> codec) { super(connection, codec); }
public AbstractRedisAsyncCommands(StatefulConnection<K, V> connection, RedisCodec<K, V> codec) { this.connection = connection; this.codec = codec; this.commandBuilder = new RedisCommandBuilder<>(codec); }
StatefulRedisConnectionImpl
@Override public <T> RedisCommand<K, V, T> dispatch(RedisCommand<K, V, T> command) { //前置处理 RedisCommand<K, V, T> toSend = preProcessCommand(command); try { //通过父类进行派发,父类中对writer为当前类对构造方法对入参 return super.dispatch(toSend); } finally { if (command.getType().name().equals(MULTI.name())) { multi = (multi == null ? new MultiOutput<>(codec) : multi); } } }
protected <T> RedisCommand<K, V, T> dispatch(RedisCommand<K, V, T> cmd) { if (debugEnabled) { logger.debug("dispatching command {}", cmd); } //将发送命令对处理委派给channelWriter处理 return channelWriter.write(cmd); }
MasterSlaveChannelWriter
@Override public <K, V, T> RedisCommand<K, V, T> write(RedisCommand<K, V, T> command) { LettuceAssert.notNull(command, "Command must not be null"); if (closed) { throw new RedisException("Connection is closed"); } //获取命令意图 Intent intent = getIntent(command.getType()); //根据读写意图获取连接 StatefulRedisConnection<K, V> connection = (StatefulRedisConnection) masterSlaveConnectionProvider .getConnection(intent); //通过这个connection派发命令 return connection.dispatch(command); }
//根据意图获取连接 public StatefulRedisConnection<K, V> getConnection(Intent intent) { if (debugEnabled) { logger.debug("getConnection(" + intent + ")"); } //如果readFrom不为null且是READ if (readFrom != null && intent == Intent.READ) { //根据readFrom配置从已知节点中选择可用节点描述 List<RedisNodeDescription> selection = readFrom.select(new ReadFrom.Nodes() { @Override public List<RedisNodeDescription> getNodes() { return knownNodes; } @Override public Iterator<RedisNodeDescription> iterator() { return knownNodes.iterator(); } }); //如果可选择节点集合为空则抛出异常 if (selection.isEmpty()) { throw new RedisException(String.format("Cannot determine a node to read (Known nodes: %s) with setting %s", knownNodes, readFrom)); } try { //遍历所有可用节点 for (RedisNodeDescription redisNodeDescription : selection) { //获取节点连接 StatefulRedisConnection<K, V> readerCandidate = getConnection(redisNodeDescription); //如果节点连接不是打开到连接则继续查找下一个连接 if (!readerCandidate.isOpen()) { continue; } //返回可用连接 return readerCandidate; } //如果没有找到可用连接,默认返回第一个 return getConnection(selection.get(0)); } catch (RuntimeException e) { throw new RedisException(e); } } //如果没有配置readFrom或者不是READ 则返回master连接 return getConnection(getMaster()); }
protected StatefulRedisConnection<K, V> getConnection(RedisNodeDescription redisNodeDescription) { //如果没有则创建新节点,并添加到缓存中 return connections.computeIfAbsent( new ConnectionKey(redisNodeDescription.getUri().getHost(), redisNodeDescription.getUri().getPort()), connectionFactory); }
创建实际的connectio
@Override public StatefulRedisConnection<K, V> apply(ConnectionKey key) { //构建URI RedisURI.Builder builder = RedisURI.Builder .redis(key.host, key.port) .withSsl(initialRedisUri.isSsl()) .withVerifyPeer(initialRedisUri.isVerifyPeer()) .withStartTls(initialRedisUri.isStartTls()); if (initialRedisUri.getPassword() != null && initialRedisUri.getPassword().length != 0) { builder.withPassword(initialRedisUri.getPassword()); } if (initialRedisUri.getClientName() != null) { builder.withClientName(initialRedisUri.getClientName()); } builder.withDatabase(initialRedisUri.getDatabase()); //创建连接 StatefulRedisConnection<K, V> connection = redisClient.connect(redisCodec, builder.build()); //设置是否自动提交 synchronized (stateLock) { connection.setAutoFlushCommands(autoFlushCommands); } return connection; }