Lettuce异步读取过程分析

总体展示一个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;
        }

  

猜你喜欢

转载自www.cnblogs.com/wei-zw/p/9157618.html