Netty优化

260 阅读3分钟

Netty优化

扩展序列化算法

  1. 序列化,反序列化主要用在消息正文的转换上。
  2. 为了可扩展性,后续代码可以支持更多的序列化算法,需要进行优化。
  3. 通过读取配置的方式动态获取需要使用的序列化算法。
  4. 步骤如下
  • 导入Gson的pom
<!-- 引入gson -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.6</version>
        </dependency>
  • 定义一个抽象的序列化接口,分别包含有序列化和反序列化方法。并且实现接口(这里采用枚举的方式)
/**
 * 序列化接口,实现该类都需要实现序列化和反序列化方法
 */
/**
 * 序列化接口,实现该类都需要实现序列化和反序列化方法
 */
public interface Serializer {

    /**
     * 序列化,将对象转化为字节数组
     * @param object
     * @return
     */
    <T> byte[] serialize(T object);

    /**
     * 反序列化,将字节数组转化为指定类型的对象
     * @param clazz
     * @param bytes
     * @param <T>
     * @return
     */
    <T> T deserialize(Class<T> clazz,byte[] bytes);


        enum Algorithm implements Serializer{

        JDK{
            @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);
                }
            }

            @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);
                }

            }
        },
        GSON{
            @Override
            public <T> byte[] serialize(T object) {
                return new Gson().toJson(object).getBytes(StandardCharsets.UTF_8);
            }

            @Override
            public <T> T deserialize(Class<T> clazz, byte[] bytes) {
                return new Gson().fromJson(new String(bytes,StandardCharsets.UTF_8),clazz);
            }
        }

    }
}
  • 配置文件
# 配置序列化算法
serializer:
  type: Gson
  
  
/**
 * 配置文件
 */
@Component
public class PropertyConfig {
    
    //默认为JDK
    private static String value = "JDK";

    //通过Value注解读取配置文件,如果属性不是static可以直接加在属性上。注意这里的方法不能为static
    @Value("${serializer.type}")
    public void setValue(String value) {
        PropertyConfig.value = value;
    }

    /**
     * 根据配置文件来决定返回的序列化算法
     * @return
     */
    public static Serializer.Algorithm getSerialize(){
        System.out.println("value:"+value);
        return Serializer.Algorithm.valueOf(value);
    }
}

  • 修改编解码代码(编码时根据配置文件动态决定选择哪一种序列化算法,解码时根据协议传过来的序列化类型去解码)枚举类型在定义时自带顺序,可以获取下标ordinal()方法作为序列化的类型传参。
//编码阶段(省略了协议的其他部分)
// 1个字节的序列化算法的类型(通过ordinal()方法获取枚举的下标)
out.writeByte(PropertyConfig.getSerialize().ordinal());
// 获取正文的字节数组(根据配置文件动态选择序列化算法)
byte[] bytes = PropertyConfig.getSerialize().serialize(msg);
// 7. 4个字节的正文长度
out.writeInt(bytes.length);
// 8. 正文
out.writeBytes(bytes);


//解码阶段(省略了协议的其他部分)
// 1个字节的序列化算法的类型
byte serializeMethod = in.readByte();
// 1个字节的指令类型
byte messageType = in.readByte();

// 正文
Serializer.Algorithm algorithm = PropertyConfig.getSerialize();
// 根据指令类型转换后的对象类型
Class<?> clazz = MessageConstant.getMessageClass(messageType);
// values()方法获取所有的枚举,利用serializeMethod即传递过来的序列化算法(枚举的下标)获取枚举,调用反序列方法
Object message = algorithm.values()[serializeMethod].deserialize(clazz, bytes);
out.add(message);

参数调优

  1. 客户端可以通过Bootstrap的option()来配置参数。
  2. 服务端的ServerBootstrap中有两个方法,option()用来配置ServerSocketChannel,childOption()用来配置SocketChannel。
  3. 配置参数都封装在了CannelOption.中。

connect_timeout_millis

  1. 用于在客户端建立连接时,如果在指定毫秒时无法连接,会抛出timeout异常。
  2. netty中的promise用于线程之间的通信。

SO_BACKLOG

  1. 复习三次握手:
  • 第一次握手:client发送syn到server,状态改变为syn_send,server收到,状态改变为syn_revd,并将该请求放到sync queue队列。
  • 第二次握手:server回复syn+ack给client,client收到,状态改变为established,并发送ack给server。
  • 第三次握手:server收到ack,将状态改成established,将该请求从sync queue放入accept queue队列中。
  1. 如果全连接队列满了,server将发送一个拒绝连接的错误消息到client。