Read book Netty in action (Chapter II) (Netty Introduction)

前言

支持15W的并发客户端,我们应该视为理所当然的事情,很多公司甚至能够支撑更多,例如我们熟知的 BAT,当几年前双十一的夜晚,并发量是不可估计的。还有春节的时候购票的时候的并发。作为一个优秀的开发人员,我们要把自己的期望提高,例如:老板说要支持15W,你最少要做到20W甚至30W。因为总会有更高的吞吐量和可扩展性的要求,在漫长的历史长河中,直接使用底层的API是很复杂的,所以有了Spring,Mybatis等史诗级框架。对于我们技术人员而言,他们已经不可或缺了。
在网络编程领域,Netty是Java的史诗级看框架,他将复杂的事情简单化。让我们去做我们真正感兴趣的事。

WHY

在首次深入之前,我们需要了解一下nettty的好处。
首先它是易于使用的,而且性能比JAVA核心的API有更多的吞吐量和耕地的延迟,因为池化(例如:线程池和德鲁伊)和复用,更低的资源消耗和更少的内存复制,健壮性不会导致OOM(不得不说,OOM的确令人头疼,我曾经做过SAP,在对接的时候务必十分小心,不然就会OOM,还有POI解析几百万数据的时候,不仅慢,而且内存容易溢出,所以我选择SAX),安全。(其实书上说的更多,我做了剪切,有需要可以去读原文。)

异步和事件驱动

异步事件可能很熟悉,例如:你可能永远也不会收到你发出去的电子邮箱对应的回复(给并发大师Lee或者给你喜欢的superstar写一封电子邮箱,你就会有体验。),你也不会傻傻的等着。或者我正在写信的时候收到垃圾邮箱,异步事件也可以有序。通常来说:你只有写信了,人家才有可能回复你,你在等待的时候也可以做一些其他的事情,例如:读一些杂志,喝一点开发或者中国茶。
在日常的生活中,异步因为常见可能会被你忽视,但是让计算机以相同的方式去做事,可能会产生一些特殊的问题。本质上,一个即是异步的又是事件驱动的程序的系统会表现出一些行为,它可以以任意的顺序响应在任意时间发生的事情。
这种能力对于实现可伸缩性至关重要,定义为:一种系统或者网络需要处理的工作不断增长的时候,可以通过某种行为扩大它的处理能力来适应增长

异步和可伸缩性之间的联系

非阻塞网络调用使得我们可以不必等待一个操作的完成(写邮件),完全异步的IO正是基于这个特性构建的,并且更进一步:异步方法会立刻返回,并且在它完成的时候通知客户(参考:未来任务)。选择器可以使得我们使用较少的程序去监控许多连接上的事件。

What

Netty是什么,有什么核心构成的。正是例如:Spring Cloud的组件有哪些类似。
可以先看一下核心组件,我们并不需要知道代码意思。

Channel

Channel是JAVA NIO的一个基本构造,说白了,它就是一个实体(一个硬件设备,一个文件,一个网络套接字或者能够执行一个或者多个不同的IO操作的程序组件)的开放连接,例如:read\write。因此它是可以打开或者关闭的,是数据传入传出的载体。

回调

一个回调就是一个方法,一个指向已经被提供给另外一个方法的方法的引用。这使得后者可以调用前者,这是操作之后通知的常用手段之一。
Netty在内部使用了回调处理事件,当一个回调被触发的时候,相关的事件可以被Hanlder去处理。参照下面的例子:
导入

<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.51.Final</version>
</dependency>

public class ConnectHandler  extends ChannelInboundHandlerAdapter {
    @Override
    //当一个新的连接已经被建立时,channelActive(ChannelHandlerContext)将会被调用
    public void channelActive(ChannelHandlerContext ctx)
            throws Exception {
        System.out.println(
                "Client " + ctx.channel().remoteAddress() + " connected");
    }
}

当一个新的连接被建立的时候,回调方法就会被调用。

Future

大家应该听过FutureTask,或者用过,它提供了另一种在操作完成时通知应用程序的方式。这个对象可以看做是一个异步结果的占用符,它会在完成之后,提供你对结果的访问。
juc包里有Future类并且有所实现,可以动手检查,或者阻塞到其完成。netty有ChannelFuture。用于执行异步操作的时候用。
代码:

public interface ChannelFuture extends Future<Void> {
    Channel channel();

    ChannelFuture addListener(GenericFutureListener<? extends Future<? super Void>> var1);

    ChannelFuture addListeners(GenericFutureListener<? extends Future<? super Void>>... var1);

    ChannelFuture removeListener(GenericFutureListener<? extends Future<? super Void>> var1);

    ChannelFuture removeListeners(GenericFutureListener<? extends Future<? super Void>>... var1);

    ChannelFuture sync() throws InterruptedException;

    ChannelFuture syncUninterruptibly();

    ChannelFuture await() throws InterruptedException;

    ChannelFuture awaitUninterruptibly();

    boolean isVoid();
}

这一段代码展示了一个ChannelFuture作为IO操作的一部分返回的样子。这里,connect()方法会直接返回,不会阻塞,该调用会在后台完成。这样可以更高效的利用资源。

public class ConnectExample {
    private static final Channel CHANNEL_FROM_SOMEWHERE = new NioSocketChannel();

  
    public static void connect() {
        Channel channel = CHANNEL_FROM_SOMEWHERE; //reference form somewhere
        // Does not block
        //异步地连接到远程节点
        ChannelFuture future = channel.connect(
                new InetSocketAddress("192.168.5.30", 29));
        //注册一个 ChannelFutureListener,以便在操作完成时获得通知
        future.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) {
                //检查操作的状态
                if (future.isSuccess()) {
                    //如果操作是成功的,则创建一个 ByteBuf 以持有数据
                    ByteBuf buffer = Unpooled.copiedBuffer(
                            "Hello", Charset.defaultCharset());
                    //将数据异步地发送到远程节点。返回一个 ChannelFuture
                    ChannelFuture wf = future.channel()
                            .writeAndFlush(buffer);
                    // ...
                } else {
                    //如果发生错误,则访问描述原因的 Throwable
                    Throwable cause = future.cause();
                    cause.printStackTrace();
                }
            }
        });
    }
}

怎么去处理失败完全取决你自己。

事件和ChannelHandler

Netty使用不同的事件来通知我们状态是什么。这使得我们可以基于操作来引发一些动作。可能是:记录日志,数据转换,流的控制,一些逻辑。
Netty是一个网络编程框架,所以事件是按照相关性分类的。入站包括:开启(连接、激活、开始读取、用户事件等)。
出站是未来将会触发的动作的结果。
每个事件都可以被分发给ChannelHandler类中的某个用户实现的方法。

把他们放在一起

Future、回调和ChannerHandler

Nettty是基于Future和回调的,然后将事件派发给ChannerHandler。这样组成了一个netty的设计思想。

选择器、事件和EventLoop

Netty通过触发事件为Selector从应用程序中抽象出来,没有代码污染,为每一个通道配备一个EventLoop。用以处理所有事件。EventLoop顾名思义。本身是一个县城驱动,处理通道中的所有IO事件,而且在整个EventLoop的生命周期中都不会改变。我们只需要专注于程序开发即可。

结束语

初步了解了Metty之后,将会在下次正式得去编写一个netty的程序。其实Netty就是一个网络API的演变过程,用异步、非阻塞并且可介入操作的形式让我们的程序变得更加的牛逼(高可用,高可靠性,高稳定等)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值