Este artigo é um resumo combinado com JavaGuide
Resumo Netty
- Conhecimento básico de IO
- Java NIO
- Modo reator reator
- Netty
-
- O que é Netty
- O que há de tão bom no Netty?
- Componentes principais do Netty
- Qual é a forma de realização do uso do modo reator Reator no Netty?
- EventloopGroup entende? Qual é a relação com EventLoop?
- Você conhece Bootstrap e ServerBootstrap?
- Quantos threads o construtor padrão de NioEventLoopGroup iniciará?
- Modelo de threading de Netty
- O que é TCP dip / unpack? Sua solução?
- Netty longa conexão
- Mecanismo de batimento cardíaco de Netty
- Cópia zero de Netty
Conhecimento básico de IO
Princípios básicos de leitura e escrita IO
read
Chamadas de write
sistema e chamadas de sistema são apenas operações no buffer do kernel e no buffer do processo.
A chamada do sistema de leitura copia os dados do buffer do kernel para o buffer do processo
A chamada do sistema de gravação copia os dados do buffer do processo para o buffer do kernel.
至于具体的内核缓冲区到磁盘的过程则由操作系统内核进行
.
Pode-se ver que as operações de IO de programas do usuário, como Socket e file IO, são todas de desenvolvimento de aplicativo de nível superior e seu processamento de entrada e saída são consistentes no processo de programação.
A função dos buffers
Reduza a troca frequente de dados com dispositivos físicos. Ocorrerá uma interrupção durante o processo de gravação de dados no disco. Quando o sistema é interrompido, o sistema precisa manter as informações de processo correspondentes e deve ser restaurado após a interrupção. O buffer reduz a sobrecarga dessa interrupção para o sistema.
Quatro modelos principais de IO
- Bloqueio de E / S: refere-se ao estado do programa de espaço do usuário. Após a operação de IO do kernel ser completamente concluída, ele retorna ao espaço do usuário para realizar as operações do usuário. O soquete criado por padrão em Java está bloqueando IO
- IO síncrono e IO assíncrono: IO
síncrono significa que o encadeamento do programa de espaço do usuário é a parte que inicia IO, e o espaço do kernel é a parte que aceita passivamente.
IO assíncrono refere-se à parte que inicia o IO no espaço do kernel e o programa do espaço do usuário é a parte aceitante.
同步阻塞IO(Blocking IO)
: O programa do usuário precisa aguardar a conclusão da operação de E / S do kernel antes de continuar.
同步非阻塞IO(Non-bolcking IO):
O programa do usuário não precisa esperar a conclusão da operação IO do kernel para realizar a próxima operação. Durante esse processo, o kernel retornará um valor de status para o espaço do usuário.
Não NIO em JAVA (Novo IO)
IO多路复用
:又称为异步阻塞IO,就是Reactor反应器模式,Java中的Selector选择器和Linux中的epoll都是这种模型。
异步IO(Asynchronous IO)
: As threads do processo do usuário registram várias funções de retorno de chamada de evento de IO no espaço do kernel, que são ativamente chamadas pelo kernel.
Como oferecer suporte a milhões de conexões simultâneas por meio de uma configuração razoável
Ao desenvolver um sistema de alta simultaneidade, é necessário eliminar as restrições de manipulação de arquivos do Linux. O padrão do Linux é 1024. Ou seja, um processo pode aceitar 1024 conexões de soquete.
Identificador de arquivo, também chamado de descritor de arquivo.
文件句柄是内核为了高效管理已经被打开的文件所常创建的索引。
Linux通过ulimite -n 文件句柄数量 来修改文件句柄数
. Mas esse método só é eficaz quando o usuário efetua login.
Se você deseja modificá-lo permanentemente, você precisa modificar o /etc/rc.local
arquivo de inicialização e adicionar: ulimite -SHn
quantidade.
Você também pode etc/secuity/limites.conf’
adicionar diretamente o seguinte conteúdo por meio de modificação :
soft nofile 1000000 //(最大值为100万)
hard nofile 1000000
//soft nofile表示软性极限,
//hard nofile表示硬性极限,
Java NIO
Java NIO (New IO) foi introduzido no Java 4 para resolver o problema de bloqueio síncrono orientado a stream, portanto, muitas pessoas também o chamam de Non-Block IO.
Java NIO também pertence ao modelo de multiplexação IO.
NIO consiste em três componentes principais: Seletor de seletor de buffer de
canal
A diferença entre NIO e OIO
OIO foi usado antes do Java4, IO de bloqueio síncrono orientado a fluxo, fluxo de bytes ou fluxo de caracteres, ler dados do fluxo de bytes (fluxo de caracteres). Ler um ou mais de cada vez não pode alterar a posição do ponteiro à vontade. OIO não tem o conceito de seletor
NIO foi introduzido por Java4 para resolver IO de bloqueio síncrono e IO de não bloqueio orientado por buffer. Cada leitura é do canal para o buffer, e a operação de gravação é do buffer para o canal.
Você pode ler dados em qualquer lugar do buffer.
- Como o NIO consegue não bloquear?
Através da tecnologia de multiplexação de canais e canais- NIO tem o conceito de seletor, e a implementação de NIO é baseada na chamada do seletor do sistema.
Como usar o Buffer
- Use o método allocate () para criar um objeto buffer
- Use put para gravar dados no buffer pool
- Use filp () para mudar o modo de gravação para o modo de leitura
- Use get () para ler os dados do buffer
- Após a leitura, você pode usar o método Buffer.clear () ou Buffe.compat () para mudar o buffer para o modo de gravação.
Tipo de canal
FileChannel文件通道
, Usado para ler e gravar dados de arquivosSocketChannel套接字通道
, Usado para conexão TCP socket socket e leitura e gravação de dados. Normalmente usado ServerSoketChannel descentralizado para conexão.ServerSocketChannel服务器套接字通道
, Permite ouvir as solicitações de conexão TCP e criar um SockeTChannel para cada solicitação de conexão.DatagramChannl数据报通道
: Usado para leitura e gravação de dados UDP.
Ao usar o SocketChannel, o padrão é o bloqueio síncrono, portanto, ele precisa ser chamado
configureBlocking(false)
para configurar e se tornar o IO sem bloqueio assíncrono.
NIO Selector
A função do seletor é completar a multiplexação IO. Um canal representa uma conexão, e a função de monitorar vários canais de conexão pode ser realizada por meio do seletor. Permite que um thread conclua o monitoramento de vários canais.
- Tipo de evento de IO do seletor
- Leia OP_READ
- OP_WRITE gravável
- A conexão de OP_CONNECT concluiu o handshake da extremidade oposta e está no
连接就绪
estado. - Ao receber OP_ACCEPT, está em
接收就绪
estado de transição quando uma nova conexão é detectada .
FileChannel
Não há herança e,SelectableChannel
portanto, não pode ser gerenciado pelo seletor.
Processo de uso do seletor
- Obtenha a instância do seletor
- Registre o canal para o seletor
- Pesquisa de eventos IO prontos de interesse (um conjunto de teclas de seleção)
Modo reator reator
Qual é o modo do reator?
O modo de reator é composto de threads de reator de reator e processadores Manipuladores.
- Responsabilidades do encadeamento do reator do reator: Responsável por responder a eventos de E / S e distribuído para o processador Handlers.
Responsabilidades do processador: Execução sem bloqueio da lógica de negócios. Conclui o estabelecimento da conexão real, leitura do canal, processamento da lógica de negócios e responsável por gravar os resultados no canal.
Netty
O que é Netty
Netty é uma estrutura cliente-servidor baseada em NIO (NEW IO of Java), que pode ser usada para desenvolver aplicativos de rede de forma rápida e fácil.
O que há de tão bom no Netty?
O Netty é mais organizado do que o NIO que vem com o JDK.
- Suporta vários protocolos, FTP, SMTP, HTTP e vários protocolos tradicionais binários e baseados em texto.
- Modelo de threading simples e poderoso
- Vem com vários codecs
- Suporte para soquete de pacote sem conexão verdadeiro
- Suporte total para SSL, / TLS e StartTLS
- O ambiente da comunidade de desenvolvimento é bom e há muitas soluções de projeto de código aberto.
Componentes principais do Netty
Channel
, A interface é uma classe abstrata do Netty para operações de rede. Inclui operações básicas de E / S, como bind (), connect (), read (), write (), etc.
A classe de implementação mais comum é o servidor NioServerSocketChannel, NioSocketChannel (cliente).EventLoop(事件循环)接口
, O conceito central do Netty.主要作用实际就是负责监听网络事件并调用事件处理器进行相关 I/O 操作的处理。
ChannelFuture
Netty é assíncrono e sem bloqueio, e todas as operações de E / S são assíncronas. E ChannelFuture é a solução assíncrona do Netty, por meio da qual você pode retornar o valor e saber se a operação foi executada com sucesso.
Registre um ChannelFutureListener por meio do método addListener () da interface ChannelFuture. Quando a operação for bem-sucedida ou falhar, o ouvinte acionará automaticamente o resultado de retorno.
E você também pode obter o canal associado por meio do método channel () de ChannelFuture
-
ChannelHandler
: Processador específico de mensagem, responsável por operações de leitura e gravação, conexão de cliente, etc. -
ChannelPipeline(通道流水线)
: Para a cadeia ChannelHandler, um contêiner é fornecido e APIs para propagar fluxos de eventos de entrada e saída ao longo da cadeia são definidos.当 Channel 被创建时,它会被自动地分配到它专属的ChannelPipeline。
Vários processadores Handler vinculados a um canal são adicionados a ele.
ChannelPipline é projetado como uma lista duplamente vinculada, e o Handler é seu nó.
Qual é a forma de realização do uso do modo reator Reator no Netty?
O modo do reator do Reactor no Netty é refletido em:
Channel
: Em primeiro lugar, embora o Netty não use diretamente o componente Canal do Java NIO, o Netty o encapsula para torná-lo adequado para vários protocolos, enquanto mantém IO assíncrono e IO bloqueador. A camada inferior do Canal encapsula a camada inferior do SelectableChannel.Netty中的Reactor反应器
: O nome do reator do Netty é: NioEventLoop. Sua função é semelhante à do reator do JavaNIO.Tem um thread de thread e uma pesquisa de eventos IO.Netty中的Handler
: O processador Handler da Netty é dividido em duas categorias, uma é o processador in-stack do canal ChannelInboundHandler e a segunda é o processador de saída do canal ChannelOutboundHandler. Todos herdados de ChannelHandler.
EventloopGroup entende? Qual é a relação com EventLoop?
- O reator no Netty é um reator multithread. EventLoop é equivalente a um sub-reator. EventLoopGroup é o grupo de encadeamentos que gerencia esses sub-reatores.
- Ao usar o Netty, o grupo de threads EventLoopGroup é usado em vez de um único EventLoop. Os parâmetros de construção de EventLoopGroup podem especificar o número de threads (o padrão é 2 vezes a CPU), e o número de threads corresponde a EventLoop um para um. Um EventLoop tem um thread dedicado para lidar com eventos de E / S. (Monitor, processador de chamadas)
Como pode ser visto na figura acima: Quando o cliente se conecta ao servidor por meio do método de conexão, o bossGroup processa a solicitação de conexão do cliente. Quando o processamento do cliente for concluído, a conexão será enviada ao workerGroup para processamento e, em seguida, o workerGroup é responsável pelo processamento de suas operações relacionadas ao IO.
Você conhece Bootstrap e ServerBootstrap?
- Bootstrap é a classe de inicialização / classe auxiliar do cliente
EventLoopGroup group = new NioEventLoopGroup();
try {
//创建客户端启动引导/辅助类:Bootstrap
Bootstrap b = new Bootstrap();
//指定线程模型
b.group(group).
......
// 尝试建立连接
ChannelFuture f = b.connect(host, port).sync();
f.channel().closeFuture().sync();
} finally {
// 优雅关闭相关线程组资源
group.shutdownGracefully();
}
O bootstrap geralmente usa o método connet () para se conectar a um host remoto e porta como um cliente na comunicação do protocolo TCP Netty. O bootstrap também pode vincular uma porta local por meio do método bind () como uma extremidade da comunicação do protocolo UDP.
- Classe de inicialização de inicialização do lado do servidor ServerBootstrap / classe auxiliar
/1.创建线程反应组
//bossGroup 处理连接监听IO事件
//workerGroup 用于负责数据IO事件和Handler业务处理
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//.创建服务端启动引导/辅助类:ServerBootstrap
ServerBootstrap b = new ServerBootstrap();
//.给引导类配置两大线程组,确定了线程模型
b.group(bossGroup, workerGroup).
/2.设置通道的IO类型
b.channel(NioServerSocketChannel.class)
/3.设置监听端口
b.localAddress(new InetSocketAddress(port))
/4.设置通道传输参数
b.option(给父通道接收连接通道设置的选项)
/5.装配流水线
b.pipeline().addLast(new Handler)
/ 6.绑定服务器新连接的端口号
ChannelFuture f = b.bind(port).sync();
// 等待连接关闭
f.channel().closeFuture().sync();
} finally {
//7.优雅关闭相关线程组资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
O ServerBootstrap geralmente usa o método bind () para vincular à porta local e, em seguida, aguarda a conexão do cliente.
O Bootstrap só precisa configurar um grupo de thread - EventLoopGroup, enquanto o ServerBootstrap precisa configurar dois grupos de thread - EventLoopGroup, um para receber conexões e outro para processamento específico.
Quantos threads o construtor padrão de NioEventLoopGroup iniciará?
O padrão é CPU*2
, mas pode ser alterado por meio do construtor.
Modelo de threading de Netty
No Netty, o pool de threads NioEventLoopGroup é usado principalmente para realizar o modelo de thread específico (modo de reator).
O modo Reactor é baseado em eventos orientados e usa multiplexação para distribuir eventos ao manipulador correspondente para processamento, o que é muito adequado para lidar com cenários de E / S massivos.
O que é TCP dip / unpack? Sua solução?
- A colagem / descompactação do TCP ocorre quando você envia dados com base no TCP, várias strings são "coladas" juntas ou uma string é "desmontada".
- O problema de mergulhar e descompactar no Netty: A capacidade de ler os dados subjacentes a cada vez é limitada.Quando o datagrama TCP subjacente é relativamente grande, um datagrama subjacente será empacotado e copiado, o que resultará em um meio pacote.
- Quando o pacote de dados armazenado em buffer pela camada inferior do TCP é relativamente pequeno, ele é responsável por mais de um pacote de buffer do kernel por vez, fazendo com que o buffer do programa leia o pacote sujo.
- Solução?
(1) Você pode usar o decodificador fornecido pela Netty:
- LineBasedFrameDecoder: quando o remetente envia pacotes de dados, cada pacote de dados é separado por um caractere de nova linha. O princípio de funcionamento de LineBasedFrameDecoder é que ele percorre os bytes legíveis em ByteBuf por sua vez, determina se há um caractere de nova linha e, em seguida, executa a interceptação correspondente.
- DelimiterBasedFrameDecoder: você pode personalizar o decodificador do delimitador,
- LineBasedFrameDecoder é na verdade um decodificador DelimiterBasedFrameDecoder especial.
- FixedLengthFrameDecoder: decodificador de comprimento fixo, que pode descompactar a mensagem de acordo com o comprimento especificado.
- LengthFieldBasedFrameDecoder: decodificador de pacote de comprimento personalizado.
(2) Empacotador de decodificador de serialização personalizado: como: serialização JSON.
Netty longa conexão
Sabemos que antes das leituras e gravações do TCP, uma conexão deve ser estabelecida com antecedência entre o servidor e o cliente. O processo de estabelecer uma conexão requer o aperto de mão de três vias que costumamos dizer, e quatro ondas de mãos são necessárias para liberar / fechar a conexão. Este processo consome recursos da rede e tem um atraso de tempo.
Portanto, o TCP usa uma conexão longa.
Mecanismo de batimento cardíaco de Netty
Várias condições anormais podem ocorrer no TCP em uma conexão longa, fazendo com que o servidor seja desconectado. Se não houver mecanismo de pulsação, o cliente não saberá que o servidor está inativo e, após a reinicialização do servidor, não saberá que o cliente pensou que ele estava conectado. Quando o cliente se desconecta acidentalmente, se o servidor não sabe que o TCP subjacente foi desconectado, a conexão se tornará uma conexão falsa, ocupando muitos recursos. Portanto, um mecanismo de pulsação é necessário para resolvê-lo.
Na verdade, o TCP vem com uma opção de conexão longa e também tem um mecanismo de pacote de pulsação, que é a opção de TCP: SO_KEEPALIVE. No entanto, a longa flexibilidade de conexão no nível do protocolo TCP não é suficiente. Portanto, em geral, implementamos um mecanismo de pulsação personalizado no protocolo da camada de aplicativo, ou seja, por meio de codificação no nível Netty. Se o mecanismo de pulsação for implementado por meio do Netty, a classe principal será IdleStateHandler.
Cópia zero de Netty
Cópia zero (inglês: cópia zero; também traduzido como cópia zero)
- Tecnologia significa que quando o computador executa uma operação, a CPU não precisa primeiro copiar os dados de uma memória para outra área específica. Essa técnica geralmente é usada para economizar ciclos de CPU e largura de banda de memória ao transferir arquivos pela rede.
- Da arquitetura de nível de sistema operacional, significa evitar a cópia de dados entre o modo de usuário e o modo kernel.
A cópia zero de Netty se reflete principalmente em:
- Usando a classe CompositeByteBuf fornecida pelo Netty, vários ByteBufs podem ser mesclados em um ByteBuf lógico, evitando a cópia entre cada ByteBuf.
- ByteBuf suporta operação de slice, então ByteBuf pode ser decomposto em vários ByteBuf compartilhando a mesma área de armazenamento, evitando cópia de memória.
- A transferência de arquivos é realizada através de FileChannel.tranferTo empacotado por FileRegion, que pode enviar diretamente os dados do buffer de arquivo para o Canal de destino, evitando o problema de cópia de memória causado pelo método tradicional de escrita circular.