专栏首页编程坑太多『互联网架构』软件架构-netty线程模型源码(55)

『互联网架构』软件架构-netty线程模型源码(55)

netty其实针对nio做了封装,其实最核心的就是BOOS线程和WORK线程。有人了解netty3 有人了解netty4,其实这2个差别并不大。其实netty就是高性能的事件驱动型的NIO框架。 源码:https://github.com/limingios/netFuture/tree/master

(一)netty架构

这次要说netty3,目前dubbo,google,facebook的RPC框架都是基于netty3实现的。目前netty已经到5了。

  • 主要分为五個部分 1.Core是核心层,netty最以为傲的东西,Extensible Event Model可扩展的基于拦截器链式实现的。 2.Universal Communication API 统一的通信API,主要是对NIO,BIO统一的封装 3.Zero-Copy-Capable Rich Byte Buffer 0拷贝的 4.Transport Services 传输层服务 5.Protocol Support 应用层协议支持
  • 模块组件

1.bootstrap Netty服务端及客户端启动类 2.buffer 缓冲相关,对NIO Buffer做了一些优化、封装 3.channel 处理客户端与服务端之间的连接通道 4.container 连接其他容器的代码,例如Spring 5.handler 实现协议编解码等附加功能 6.logging 日志 7.util工具类

  • netty中的主从线程模型

使用EventLoop来处理连接上的读写事件,而一个连接上的所有请求都保证在一个EventLoop中被处理,一个EventLoop中只有一个Thread,所以也就实现了一个连接上的所有事件只会在一个线程中被执行。一个EventLoopGroup包含多个EventLoop,可以把一个EventLoop当做是Reactor线程模型中的一个线程。

举个例子吧:在Netty的里面有一个Boss,他开了一家公司(开启一个服务端口)对外提供业务服务,它手下有一群做事情的workers。Boss一直对外宣传自己公司提供的业务,并且接受(accept)有需要的客户(client),当一位客户找到Boss说需要他公司提供的业务,Boss便会为这位客户安排一个worker,这个worker全程为这位客户服务(read/write)。如果公司业务繁忙,一个worker可能会为多个客户进行服务。这就是Netty里面Boss和worker之间的关系。 Server.java

import java.net.InetSocketAddress;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ServerBootstrap;import org.jboss.netty.channel.ChannelPipeline;import org.jboss.netty.channel.ChannelPipelineFactory;import org.jboss.netty.channel.Channels;import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;import org.jboss.netty.handler.codec.string.StringDecoder;import org.jboss.netty.handler.codec.string.StringEncoder;/** * netty服务端 * @author idig8.com */public class Server {
    public static void main(String[] args) {
        //  服务类        ServerBootstrap bootstrap = new ServerBootstrap();
        //  boss线程,主要监听端口和获取worker线程及分配socketChannel给worker线程        ExecutorService boss = Executors.newCachedThreadPool();        //  worker线程负责数据读写        ExecutorService worker = Executors.newCachedThreadPool();
        //  设置niosocket工厂        bootstrap.setFactory(new NioServerSocketChannelFactory(boss, worker));
        //  设置管道的工厂        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            @Override            public ChannelPipeline getPipeline() throws Exception {                ChannelPipeline pipeline = Channels.pipeline();                // 管道过滤器                pipeline.addLast("decoder", new StringDecoder());                pipeline.addLast("encoder", new StringEncoder());                pipeline.addLast("myServerMessageHandler", new MyServerMessageHandler());                return pipeline;            }        });
        // 服务类绑定端口        bootstrap.bind(new InetSocketAddress(7777));
        System.out.println("服务端启动...");
    }
}

处理的handler

import org.jboss.netty.channel.ChannelHandlerContext;import org.jboss.netty.channel.ChannelStateEvent;import org.jboss.netty.channel.ExceptionEvent;import org.jboss.netty.channel.MessageEvent;import org.jboss.netty.channel.SimpleChannelHandler;/** * 消息处理类 * @author idig8.com */public class MyServerMessageHandler extends SimpleChannelHandler {
    /**     * 接收消息     */    @Override    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {        System.out.println("messageReceived");
        String s = (String) e.getMessage();        System.out.println("服务端收到数据:"+s);
        //回写数据给客户端        ctx.getChannel().write("hello...");        super.messageReceived(ctx, e);    }
    /**     * 异常处理     */    @Override    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {        System.out.println("exceptionCaught");        super.exceptionCaught(ctx, e);    }
    /**     * 获取新连接事件     */    @Override    public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {        System.out.println("channelConnected");        super.channelConnected(ctx, e);    }
    /**     * 关闭通道的时候触发 (必须是链接已经建立)     */    @Override    public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {        System.out.println("channelDisconnected");        super.channelDisconnected(ctx, e);    }
    /**     * 通道关闭的时候触发     */    @Override    public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {        System.out.println("channelClosed");        super.channelClosed(ctx, e);    }}
  • 处理流程 1.标记nio selector唤醒状态(wakeUp状态位,true有请求,false没有请求) 2.Selector(注册) 3.处理任务队列 4.处理自己的业务(客户端的读写请求等)
  • dubbo底层
  • netty启动一个服务所经过的流程 1.设置boss线程 和 worker线程,boss安排,worker干活,让他们入厂,准备由boss安排worker干活。 2.设置启动类参数,最重要的就是设置channel。 3.创建server对应的channel,创建各大组件,包括ChannelConfig,ChannelId,ChannelPipeline,ChannelHandler,Unsafe。 4.初始化server对应的channel,设置一些attr,option,以及设置子channel的attr,option,给server的channel添加新channel接入器,并出发addHandler,register等事件。 5.调用到jdk底层做端口绑定,并触发active事件,active触发的时候,真正做服务端口绑定。

PS:Netty是Java程序员进阶的必备神奇。随着网站规模的不断扩大,系统并发访问量也越来越高,传统基于 Tomcat 等 Web 容器的垂直架构已经无法满足需求,需要拆分应用进行服务化,以提高开发和维护效率。从组网情况看,垂直的架构拆分之后,系统采用分布式部署,各个节点之间需要远程服务调用,高性能的 RPC 框架必不可少,Netty 作为异步高性能的通信框架,往往作为基础通信组件被这些 RPC 框架使用。

本文分享自微信公众号 - 编程坑太多(idig88),作者:诸葛阿明

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-05-20

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 『互联网架构』软件架构-netty粘包分包编码解码(57)

    (1)粘包: 1.服务端 原因收到的数据放在系统接收缓冲区,用户进程从该缓冲区取数据 2.客户端 原因TCP为提高传输效率,要收集到足够多的数据后才发送一包数据

    IT故事会
  • 「小程序JAVA实战」小程序的视频点赞功能开发(62)

    IT故事会
  • 『互联网架构』软件架构-分布式系列并发编程Lock锁和Tools限制(30)

    对象锁也叫方法锁,是针对一个对象实例的,它只在该对象的某个内存位置声明一个标识该对象是否拥有锁,所有它只会锁住当前的对象,而并不会对其他对象实例的锁产生任何影响...

    IT故事会
  • 『互联网架构』软件架构-netty粘包分包编码解码(57)

    (1)粘包: 1.服务端 原因收到的数据放在系统接收缓冲区,用户进程从该缓冲区取数据 2.客户端 原因TCP为提高传输效率,要收集到足够多的数据后才发送一包数据

    IT故事会
  • SSM Spring SpringMVC Mybatis框架整合Java配置完整版

      以前用着SSH都是老师给配好的,自己直接改就可以。但是公司主流还是SSM,就自己研究了一下Java版本的配置。网上大多是基于xnl的配置,但是越往后越新的项...

    用户2417870
  • drools规则引擎的动态数据库交接使用和压力测试

    技术从心
  • 配置Eclipse可以查看JDK源码

    Window->Preferences->Java->Installed JREs

    SmileNicky
  • 分布式事务系列--SpringCloud整合byteTCC框架0.5.x版本2

    在使用tcc框架处理分布式事务时,需要我们自己来编写tcc业务代码。这里演示一个简单的加钱的操作。

    IT云清
  • Appium系列|Appium测试框架完善(三)

    当测试脚本有一定数量的情况下,每次执行完所有的测试脚本会发现或多或少的测试脚本执行失败了,失败主要是两种原因一种是源程序bug,另外一种是测试脚本由于各方面的原...

    测试邦
  • 绕过验证码

    所以我开始寻找验证码最常见的地方,比如注册、登录和密码重置页面,我找到的那个是在登录页面。

    用户1631416

扫码关注云+社区

领取腾讯云代金券