1 Reactor模式
1.1 概述
• 单线程模型
所有I/O操作都由一个线程完成,即多路复用、事件分发和处理都是在一个Reactor线程上完成的
适合于小容量的场景,高并发的应用场景无法承载压力,单线程无法同时处理高并发时的多条链路,包括编解码,接收响应,性能无法支撑,吞吐量小,而且客户端积压超时率一并提升,增加服务端的负载
• 多线程模型
一个Acceptor用于监听端口,负责接收客户端的TCP连接请求,一个Reactor Thread Pool负责处理I/O操作,包括IO读写及编解码和响应发送
• 主从多线程模型
一个Acceptor负责接收请求,一个Main Reactor Thread Pool负责连接,一个Sub Reactor Thread Pool负责处理I/O操作。Acceptor负责客户端的登陆握手认证,认证成功建立链路,后续由Sub Reactor负责
1.2 Netty之Reactor线程模型实现
Netty工作流程:
netty服务端启动时,通常会有两个NioEventLoopGroup:一个boss,一个worker。第一个NioEventLoopGroup正常只需要一个EventLoop,主要负责客户端的连接请求,然后打开一个Channel,交给第二个NioEventLoopGroup中的一个EventLoop来处理这个Channel上的所有读写事件。一个Channel只会被一个EventLoop处理,I/O操作、编解码都在同一个EventLoop中,确保这些操作线程安全,而一个EventLoop可能会被分配给多个Channel。netty客户端启动后与服务端建立连接,获得Channel后发送相应的请求数据。netty服务端和客户端启动代码如下
package netty;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import java.net.InetSocketAddress;
/**
* @Auther: ANYO
* @Date: 2019/3/12 23:01
* @Description:
*/
public class EchoServer {
private final int port;
public EchoServer(int port) {
this.port = port;
}
public static void main(String[] args) throws Exception {
/*if (args.length != 1) {
System.err.println(
"Usage: " + EchoServer.class.getSimpleName() +
" <port>");
return;
}*/
// int port = Integer.parseInt(args[0]);
new EchoServer(8082).start();
}
/**
* Netty 创建服务端的流程
* 1. 创建 ServerBootstrap 实例
* 2. 设置并绑定 Reactor 线程池
* 3. 设置并绑定服务端 Channel
* 4. 创建并初始化 ChannelPipeline
* 5. 添加并设置 ChannelHandler
* 6. 绑定并启动监听端口
* @throws Exception
*/
public void start() throws Exception {
NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
NioEventLoopGroup workGroup = new NioEventLoopGroup(10);
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup,workGroup)
.channel(NioServerSocketChannel.class)
// .channel(OioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,1024)
.option(ChannelOption.TCP_NODELAY,true)
.localAddress(new InetSocketAddress(port))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch)
throws Exception {
ch.pipeline().addLast(
new EchoServerHandler());
}
});
//绑定端口,同步等待成功
ChannelFuture f = b.bind().sync();
System.out.println(EchoServer.class.getName() + " started and listen on " +
f.channel().localAddress());
//挂起服务,等待服务端监听端口关闭
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully().sync();
workGroup.shutdownGracefully().sync();
}
}
}
package netty;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.net.InetSocketAddress;
/**
* @Auther: ANYO
* @Date: 2019/3/12 23:31
* @Description:
*/
public class EchoClient {
private final String host;
private final int port;
public EchoClient(String host, int port) {
this.host = host;
this.port = port;
}
public void start() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.remoteAddress(new InetSocketAddress(host, port))
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch)
throws Exception {
ch.pipeline().addLast(
new EchoClientHandler());
}
});
ChannelFuture f = b.connect().sync();
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync();
}
}
public static void main(String[] args) throws Exception {
new EchoClient(host, port).start();
}
}
2 责任链模式
2.1 概述
责任链模式:使多个对象都有机会处理请求,从而避免请求的发送者与接受者之间的耦合关系,将这个对象形成一条链并沿着链传递请求,直到找到能处理它为止。
2.2 netty之责任链模式实现
pipeline管道保存所有的handler处理器,请求到达服务端后,开启入站事件的处理,从第一个handler开始进行传递,由上往下找到相应的处理器,处理完后根据实际判断是否要进行出站处理。
责任链模式中的组件:
ChannelPipeline:采取责任链模式,将多个ChannelHandler组合在一起,形成链条,事件进行传递给相应ChannelHandler处理。ChannelHandler可实现动态添加和删除。事件传递的顺序:入站事件根据handler的注册顺序执行,出站事件根据handler的注册逆序执行
ChannelHandler:业务处理组件,分为入站处理(ChannelInboundHandler)和出站处理(ChannelOutboundHandler)两种类型,处理传递到Channel对应的事件
ChannelHandlerContext:上下文信息,每个ChannelHandler加入到pipeline后都会有对应的ChannelHandlerContext,保存着相关数据channel,handler: pipeline,主要用于维护责任链的执行
3 单例模式
3.1 单例模式概述
单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
单例模式的实现:
1. 静态初始化,分为懒汉模式(第一次引用时实例化)和饿汉模式(自己加载时就将自己实例化)
2. 双重校验锁法
3.2 Netty单例模式源码实现
DefaultSelectStrategyFactory源码
/*
* Copyright 2016 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel;
/**
* Factory which uses the default select strategy.
*/
public final class DefaultSelectStrategyFactory implements SelectStrategyFactory {
public static final SelectStrategyFactory INSTANCE = new DefaultSelectStrategyFactory();
private DefaultSelectStrategyFactory() { }
/**
* 饿汉模式:类加载时实例化单例对象,线程安全
* @return
*/
@Override
public SelectStrategy newSelectStrategy() {
return DefaultSelectStrategy.INSTANCE;
}
}
4 策略模式
4.1 策略模式概述
策略模式:定义了算法家族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化,不会影响到使用算法的客户
4.2 netty策略模式实现
netty的选择器,使用的是策略者模式,将选择的行为设计成接口,不同的选择器根据自己不同的需求用不用的方式实现选择器接口
EventExecutorChooserFactory源码
/*
* Copyright 2016 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.util.concurrent;
import io.netty.util.internal.UnstableApi;
/**
* Factory that creates new {@link EventExecutorChooser}s.
*/
@UnstableApi
public interface EventExecutorChooserFactory {
/**
* Returns a new {@link EventExecutorChooser}.
*/
EventExecutorChooser newChooser(EventExecutor[] executors);
/**
* Chooses the next {@link EventExecutor} to use.
*/
@UnstableApi
interface EventExecutorChooser {
/**
* Returns the new {@link EventExecutor} to use.
*/
EventExecutor next();
}
}
DefaultEventExecutorChooserFactory实现了EventExecutorChooserFactory接口,其实现了newChooser方法,返回不同的行为
/*
* Copyright 2016 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.util.concurrent;
import io.netty.util.internal.UnstableApi;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Default implementation which uses simple round-robin to choose next {@link EventExecutor}.
*/
@UnstableApi
public final class DefaultEventExecutorChooserFactory implements EventExecutorChooserFactory {
public static final DefaultEventExecutorChooserFactory INSTANCE = new DefaultEventExecutorChooserFactory();
private DefaultEventExecutorChooserFactory() { }
@SuppressWarnings("unchecked")
@Override
public EventExecutorChooser newChooser(EventExecutor[] executors) {
if (isPowerOfTwo(executors.length)) {
return new PowerOfTwoEventExecutorChooser(executors);
} else {
return new GenericEventExecutorChooser(executors);
}
}
private static boolean isPowerOfTwo(int val) {
return (val & -val) == val;
}
private static final class PowerOfTwoEventExecutorChooser implements EventExecutorChooser {
private final AtomicInteger idx = new AtomicInteger();
private final EventExecutor[] executors;
PowerOfTwoEventExecutorChooser(EventExecutor[] executors) {
this.executors = executors;
}
@Override
public EventExecutor next() {
return executors[idx.getAndIncrement() & executors.length - 1];
}
}
private static final class GenericEventExecutorChooser implements EventExecutorChooser {
private final AtomicInteger idx = new AtomicInteger();
private final EventExecutor[] executors;
GenericEventExecutorChooser(EventExecutor[] executors) {
this.executors = executors;
}
@Override
public EventExecutor next() {
return executors[Math.abs(idx.getAndIncrement() % executors.length)];
}
}
}