Redisson新增连接过程分析

255 阅读1分钟

流程图

image.png

详细流程

ConnectionPool#add(ClientConnectonsEntry entry)链接池新增链接逻辑如下

public RFuture<Void> add(final ClientConnectionsEntry entry) {
    //新建一个RedissonPromise
    final RPromise<Void> promise = connectionManager.newPromise();
    //订阅完成后把entry放入entries
    promise.addListener(new FutureListener<Void>() {
        @Override
        public void operationComplete(Future<Void> future) throws Exception {
            entries.add(entry);
        }
    });
    //初始化链接
    initConnections(entry, promise, true);
    return promise;
}

看下主要初始化的逻辑,即initConnections方法

private void initConnections(final ClientConnectionsEntry entry, final RPromise<Void> initPromise, boolean checkFreezed) {
    //获取连接池中的最小空闲连结数
    final int minimumIdleSize = getMinimumIdleSize(entry);

    if (minimumIdleSize == 0 || (checkFreezed && entry.isFreezed())) {
        initPromise.trySuccess(null);
        return;
    }

    final AtomicInteger initializedConnections = new AtomicInteger(minimumIdleSize);
    int startAmount = Math.min(50, minimumIdleSize);
    final AtomicInteger requests = new AtomicInteger(startAmount);
    for (int i = 0; i < startAmount; i++) {
        createConnection(checkFreezed, requests, entry, initPromise, minimumIdleSize, initializedConnections);
    }
}

上面的逻辑会循环创建最小空闲链接数的connection

private void createConnection(final boolean checkFreezed, final AtomicInteger requests, final ClientConnectionsEntry entry, final RPromise<Void> initPromise,
        final int minimumIdleSize, final AtomicInteger initializedConnections) {

    if ((checkFreezed && entry.isFreezed()) || !tryAcquireConnection(entry)) {
        Throwable cause = new RedisConnectionException(
                "Can't init enough connections amount! Only " + (minimumIdleSize - initializedConnections.get()) + " from " + minimumIdleSize + " were initialized. Server: "
                                    + entry.getClient().getAddr());
        initPromise.tryFailure(cause);
        return;
    }
    
    acquireConnection(entry, new Runnable() {
        @Override
        public void run() {
            RPromise<T> promise = connectionManager.newPromise();
            createConnection(entry, promise);
            promise.addListener(new FutureListener<T>() {
                @Override
                public void operationComplete(Future<T> future) throws Exception {
                    if (future.isSuccess()) {
                        T conn = future.getNow();

                        releaseConnection(entry, conn);
                    }

                    releaseConnection(entry);

                    if (!future.isSuccess()) {
                        Throwable cause = new RedisConnectionException(
                                "Can't init enough connections amount! Only " + (minimumIdleSize - initializedConnections.get()) + " from " + minimumIdleSize + " were initialized. Server: "
                                                    + entry.getClient().getAddr(), future.cause());
                        initPromise.tryFailure(cause);
                        return;
                    }

                    int value = initializedConnections.decrementAndGet();
                    if (value == 0) {
                        log.info("{} connections initialized for {}", minimumIdleSize, entry.getClient().getAddr());
                        if (!initPromise.trySuccess(null)) {
                            throw new IllegalStateException();
                        }
                    } else if (value > 0 && !initPromise.isDone()) {
                        if (requests.incrementAndGet() <= minimumIdleSize) {
                            createConnection(checkFreezed, requests, entry, initPromise, minimumIdleSize, initializedConnections);
                        }
                    }
                }
            });
        }
    });

}

acquireConnection的实际逻辑是使用传入entryfreeConnectionsCounter调用acquire方法

public class ClientConnectionsEntry {

    private final Queue<RedisPubSubConnection> freeSubscribeConnections = new ConcurrentLinkedQueue<RedisPubSubConnection>();
    private final AsyncSemaphore freeSubscribeConnectionsCounter;

    private final Queue<RedisConnection> freeConnections = new ConcurrentLinkedQueue<RedisConnection>();
    private final AsyncSemaphore freeConnectionsCounter;

    private ConnectionManager connectionManager;

    private final AtomicInteger failedAttempts = new AtomicInteger();

    public ClientConnectionsEntry(RedisClient client, int poolMinSize, int poolMaxSize, int subscribePoolMinSize, int subscribePoolMaxSize,
            ConnectionManager connectionManager, NodeType serverMode) {
        this.client = client;
        //定义一个poolMaxSize的semaphore
        this.freeConnectionsCounter = new AsyncSemaphore(poolMaxSize);
        this.connectionManager = connectionManager;
        this.freeSubscribeConnectionsCounter = new AsyncSemaphore(subscribePoolMaxSize);

        if (subscribePoolMaxSize > 0) {
            connectionManager.getConnectionWatcher().add(subscribePoolMinSize, subscribePoolMaxSize, freeSubscribeConnections, freeSubscribeConnectionsCounter);
        }
        connectionManager.getConnectionWatcher().add(poolMinSize, poolMaxSize, freeConnections, freeConnectionsCounter);
    }

    public int getFreeAmount() {
        return freeConnectionsCounter.getCounter();
    }
    //将获取connection的逻辑放入counter队列
    public void acquireConnection(Runnable runnable) {
        freeConnectionsCounter.acquire(runnable);
    }