水煮Redisson(二)-threads和nettyThreads

2,185 阅读2分钟

前言

这个系列的文章,基于Redisson版本3.13.2
Redisson是redis的一个客户端组件,依赖于netty网络框架,实现高并发读写redis缓存。redisson中的线程池主要有两类,一个是nettyThread【EventLoopGroup】和threads【ExecutorService】。从实现类来看,可以得知前一个是netty中封装过的线程池,后一个是java原生的线程池;

定义

threads:
Threads amount shared across all listeners of RTopic object, invocation handlers of RRemoteService object and RExecutorService tasks.
主要用于消费订阅、远程方法调用和框架内的一些任务调度;还有就是redis数据的解码环节【特定场景】、RedissonMap中如果用到了Read-through、Write-through和Write-behind策略,也会用到此线程池;
nettyThreads:
Threads amount shared between all redis clients used by Redisson.
主要用于redis客户端的网络通讯,发送命令和接收返回数据;

线程池初始化

源代码位于MasterSlaveConnectionManager.class类中。
nettyThreads的初始化 -- 175行

if (cfg.getEventLoopGroup() == null) {
    this.group = new EpollEventLoopGroup(cfg.getNettyThreads(), new DefaultThreadFactory("redisson-netty"));
} else {
    this.group = cfg.getEventLoopGroup();
}

threads的初始化 -- 215行

if (cfg.getExecutor() == null) {
    int threads = Runtime.getRuntime().availableProcessors() * 2;
    if (cfg.getThreads() != 0) {
        threads = cfg.getThreads();
    }
    executor = Executors.newFixedThreadPool(threads, new DefaultThreadFactory("redisson"));
} else {
    executor = cfg.getExecutor();
}

使用场景举例

nettyThreads

创建redis客户端时,使用了公用nettyThreads线程池,所有的redis client会使用同一个线程组进行收发消息。源代码位于RedisClient.class 125行。

private Bootstrap createBootstrap(RedisClientConfig config, Type type) {
    Bootstrap bootstrap = new Bootstrap()
                    .resolver(config.getResolverGroup())
                    .channel(config.getSocketChannelClass())
                    // 公用nettyThreads线程池
                    .group(config.getGroup());
    bootstrap.handler(new RedisChannelInitializer(bootstrap, config, this, channels, type));
    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;
}  

threads

消费订阅模式下,接收消息时,会根据消息的类型,分发到列表中的各个订阅者。源代码位于CommandPubSubDecoder.class 142行。

@Override
protected void decodeResult(CommandData<Object, Object> data, List<Object> parts, Channel channel,
        Object result) throws IOException {
    // ignore ...
    executor.execute(new Runnable() {
        @Override
        public void run() {
            if (result instanceof PubSubStatusMessage) {
                pubSubConnection.onMessage((PubSubStatusMessage) result);
            } else if (result instanceof PubSubMessage) {
                pubSubConnection.onMessage((PubSubMessage) result);
            } else if (result instanceof PubSubPatternMessage) {
                pubSubConnection.onMessage((PubSubPatternMessage) result);
            }
        }
    });
    // ignore ...
}

注:
解码使用线程池的代码见CommandDecoder.class 122行