Netty学习笔记五Netty参数

8 篇文章 0 订阅
8 篇文章 0 订阅

Netty学习笔记五

五. 优化与参数

1. 优化

1.1 扩展序列化算法

序列化,反序列化主要用在消息正文的转换上

  • 序列化时,需要将 Java 对象变为要传输的数据(可以是 byte[],或 json 等,最终都需要变成 byte[])
  • 反序列化时,需要将传入的正文数据还原成 Java 对象,便于处理
  • package com.sunyang.netty.study.protocol;
    
    import com.google.gson.*;
    
    import java.io.*;
    import java.lang.reflect.Type;
    import java.nio.charset.StandardCharsets;
    
    /**
     * 用于扩展序列化、反序列化算法
     */
    public interface Serializer {
    
        // 反序列化方法
        // Class<T> clazz 反序列化时许需要把字节数组转化成哪个类型的对象
        //  JDK的反序列化是不需要类型信息的,因为JDK在序列化时也会把类信息放在字节数组里。但是用其他类型的序列化算法时,就必须指定要反序列化的类型。
        <T> T deserialize(Class<T> clazz, byte[] bytes);
    
        // 序列化方法
        <T> byte[] serialize(T object);
    
        enum Algorithm implements Serializer {
            Java {
                @Override
                public <T> T deserialize(Class<T> clazz, byte[] bytes) {
                    try {
                        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
                        return (T) ois.readObject();
                    } catch (IOException | ClassNotFoundException e) {
                        throw  new RuntimeException("反序列化失败", e);
                    }
                }
    
                @Override
                public <T> byte[] serialize(T object) {
                    try {
                        ByteArrayOutputStream bos = new ByteArrayOutputStream();
                        ObjectOutputStream oos = new ObjectOutputStream(bos);
                        oos.writeObject(object);
                        return bos.toByteArray();
                    } catch (IOException e) {
                        throw new RuntimeException("序列化失败", e);
                    }
                }
            },
    
            Json {
                @Override
                public <T> T deserialize(Class<T> clazz, byte[] bytes) {
                    String json = new String(bytes, StandardCharsets.UTF_8);
                    return new Gson().fromJson(json, clazz);
                }
    
                @Override
                public <T> byte[] serialize(T object) {
                    String json = new Gson().toJson(object);
                    return json.getBytes(StandardCharsets.UTF_8);
                }
            }
        }
    }
    

1.2 参数调优

客户端通过

  • .option()方法配置参数 给SocketChannel配置参数

服务端:

  • .option() 方法是ServerSocketChannel配置参数
  • .childOption() 是给SocketChannel配置参数。
1)CONNECT_TIMEOUT_MILLIS
  • 属于 SocketChannal 参数

  • 用在客户端建立连接时,如果在指定毫秒内无法连接,会抛出 timeout 异常

  • SO_TIMEOUT 主要用在阻塞 IO,阻塞 IO 中 accept,read 等都是无限等待的,如果不希望永远阻塞,使用它调整超时时间

@Slf4j
public class TestConnectionTimeout {
    public static void main(String[] args) {
        NioEventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap()
                    .group(group)
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 300)
                    .channel(NioSocketChannel.class)
                    .handler(new LoggingHandler());
            ChannelFuture future = bootstrap.connect("127.0.0.1", 8080);
            future.sync().channel().closeFuture().sync(); // 断点1
        } catch (Exception e) {
            e.printStackTrace();
            log.debug("timeout");
        } finally {
            group.shutdownGracefully();
        }
    }
}
源码

目的:了解Netty中Promise和eventLoop的使用

连接超时的实现其实就是eventLoop的定时任务加上用Promise在主线程和eventLoop线程之间传递数据用。

io.netty.channel.nio.AbstractNioChannel.AbstractNioUnsafe#connect

@Override
public final void connect(
        final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {
    // ...
    // Schedule connect timeout.
    int connectTimeoutMillis = config().getConnectTimeoutMillis();
    if (connectTimeoutMillis > 0) {
        connectTimeoutFuture = eventLoop().schedule(new Runnable() {
            @Override
            public void run() {                
                ChannelPromise connectPromise = AbstractNioChannel.this.connectPromise;
                ConnectTimeoutException cause =
                    new ConnectTimeoutException("connection timed out: " + remoteAddress); // 断点2
                if (connectPromise != null && connectPromise.tryFailure(cause)) {
                    close(voidPromise());
                }
            }
        }, connectTimeoutMillis, TimeUnit.MILLISECONDS);
    }
	// ...
}
2)SO_BACKLOG
  • 属于 ServerSocketChannal 参数

image-20210824133317150

  1. 第一次握手,client 发送 SYN 到 server,状态修改为 SYN_SEND,server 收到,状态改变为 SYN_REVD,并将该请求放入 sync queue 队列

  2. 第二次握手,server 回复 SYN + ACK 给 client,client 收到,状态改变为 ESTABLISHED,并发送 ACK 给 server

  3. 第三次握手,server 收到 ACK,状态改变为 ESTABLISHED,将该请求从 sync queue 放入 accept queue

    • 服务器在三次握手连接建立以后并不能立刻直接拿到连接使用,而是从半连接队列放到全连接队列。

    • 因为服务器端的accept()能力是有限的,所以要存在一个全连接队列,将不能被即时处理的连接信息存储在全连接队列中,等待accept()。

其中

  • 在 linux 2.2 之前,backlog 大小包括了两个队列的大小,在 2.2 之后,分别用下面两个参数来控制

  • sync queue - 半连接队列

    • 大小通过 /proc/sys/net/ipv4/tcp_max_syn_backlog 指定,在 syncookies 启用的情况下,逻辑上没有最大值限制,这个设置便被忽略
  • accept queue - 全连接队列

    • 其大小通过 /proc/sys/net/core/somaxconn 指定,在使用 listen 函数时,内核会根据传入的 backlog 参数与系统参数,取二者的较小值
    • 如果 accpet queue 队列满了,server 将发送一个拒绝连接的错误信息到 client

NIO中

  • 通过bind(8080, backlog);来设置大小

netty 中

  • 可以通过 option(ChannelOption.SO_BACKLOG, 值) 来设置大小
  • 默认值:Windows 200 Linux和MAC 128
3)ulimit -n
  • 属于操作系统参数
  • 限制一个进程能打开的最大文件描述符(FD)的数量
4)TCP_NODELAY
  • 默认false ,开启了nagle算法
  • 属于 SocketChannal 参数
  • 建议设置为true,不延迟,直接发送。
5)SO_SNDBUF & SO_RCVBUF
  • SO_SNDBUF 属于 SocketChannal 参数
  • SO_RCVBUF 既可用于 SocketChannal 参数,也可以用于 ServerSocketChannal 参数(建议设置到 ServerSocketChannal 上)
6)ALLOCATOR

分配器

  • 属于 SocketChannal 参数
  • 用来分配 ByteBuf, ctx.alloc(),设置池化还是非池化,堆内存还是直接内存
  • 默认是池化 pooled 直接内存
  • 但是如果你设置了非直接内存,但是网络IO操作用的还是直接内存(Netty强制)但是自己创建的缓冲区(也就是用来本地IO操作的ByteBuf)可以设置。
7)RCVBUF_ALLOCATOR
  • 属于 SocketChannal 参数
  • 控制 netty 接收缓冲区大小
  • 负责入站数据的分配,决定入站缓冲区的大小(并可动态调整),统一采用 direct 直接内存,具体池化还是非池化由 allocator 决定

image-20210824143553476

的缓冲区(也就是用来本地IO操作的ByteBuf)可以设置。

7)RCVBUF_ALLOCATOR
  • 属于 SocketChannal 参数
  • 控制 netty 接收缓冲区大小
  • 负责入站数据的分配,决定入站缓冲区的大小(并可动态调整),统一采用 direct 直接内存,具体池化还是非池化由 allocator 决定

[外链图片转存中…(img-U7AqEjVY-1629966016440)]

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值