Netty 学习笔记(二)

244 阅读2分钟

这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战

Reactor线程模型

单线程模型

异步非阻塞i/o,所有的i/o操作都不会导致阻塞。理论上一个线程可以独立处理所有的i/o相关的操作。和node.js类似

多线程模型

和单线程相比多了一组线程组:

有一个nio线程负责处理客户端的连接;

增加了一组nio线程池来处理网络io操作

reactor-多例.png

主要问题是一个线程处理客户端连接,可能存在安全和性能问题,例如并发百万客户端连接,或者服务端需要对客户端握手进行安全认证,但是认证本身非常损耗性能。

主从模式

为了解决上述的两种模式的缺点,这种模式是相对来说合理的,也是官网推荐的

reactor-主从.png

采用的是一个线程池去处理客户端连接,监听客户端的连接包括安全认证,但是等到链路创建完成就创建一个线程去处理具体的业务逻辑

Bootstrapping

引导客户端和服务端构建netty应用

Boostrap

Bootstrap用来连接远程主机,有1个EventLoopGroup

image.png

ServerBootstrap

引导服务端完成netty配置

image.png

组件源码

ChannelHandler

channel处理器

  // 在ChannelHandler添加到handlerContext中触发
    void handlerAdded(ChannelHandlerContext ctx) throws Exception;

    // 在ChannelHandler从context中移除时触发
    void handlerRemoved(ChannelHandlerContext ctx) throws Exception;

    // 异常捕获
    @Deprecated
    void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;

    // 标注一个channel handler可以被多个channel安全地共享。
  // 因为一个ChannelHandler可以从属于多个ChannelPipeline,所以它也可以绑定到多个ChannelHandlerContext实例。用于这种用法的ChannelHandler必须要使用@Sharable注解标注
    @Inherited
    @Documented
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface Sharable {
        // no value
    }

ChannelHandlerAdapter

实现ChannelHandler接口,新增如下两个方法

// 没有shared注解则抛出异常
protected void ensureNotSharable() {
  if (isSharable()) {
    throw new IllegalStateException("ChannelHandler " + getClass().getName() + " is not allowed to be shared");
  }
}

/**
         * 验证是否可被加入到ChannelPipline,建立缓存
         */
public boolean isSharable() {
  Class<?> clazz = getClass();
  Map<Class<?>, Boolean> cache = InternalThreadLocalMap.get().handlerSharableCache();
  Boolean sharable = cache.get(clazz);
  if (sharable == null) {
    sharable = clazz.isAnnotationPresent(Sharable.class);
    cache.put(clazz, sharable);
  }
  return sharable;
}