Netty、ZooKeeper知识点整理

472 阅读4分钟

NIO

  • Buffer类及常用方法(最常见的有:ByteBuffer、CharBuffer等)
  • IO多路复用
  • select,poll,epoll
  • Selector、SelectableChannel、SelectionKey

Netty

服务端Demo

Bootstrap b = new ServerBootstrap();
// 创建reactor 线程组
EventLoopGroup bossLoopGroup = new NioEventLoopGroup(1);
EventLoopGroup workerLoopGroup = new NioEventLoopGroup();

try {
    // 1 设置reactor 线程组
    b.group(bossLoopGroup, workerLoopGroup);
    // 2 设置nio类型的channel
    b.channel(NioServerSocketChannel.class);
    // 3 设置监听端口
    b.localAddress(serverPort);
    // 4 设置通道的参数
    b.option(ChannelOption.SO_KEEPALIVE, true);
    b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
    b.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);

    // 5 装配子通道流水线
    b.childHandler(new ChannelInitializer<SocketChannel>() {
        // 客户端有连接到达时会创建一个channel
        protected void initChannel(SocketChannel ch) throws Exception {
            // 向子channel的pipeline添加一系列handler处理器
            ch.pipeline().addLast(......);
            ch.pipeline().addLast(......);
        }
    });
    // 6 开始绑定server
    // 通过调用sync同步方法阻塞直到绑定成功
    ChannelFuture channelFuture = b.bind().sync();
    Logger.info(" 服务器启动成功,监听端口: " +
            channelFuture.channel().localAddress());

客户端Demo

Bootstrap b = new Bootstrap();
EventLoopGroup g = new NioEventLoopGroup();
try {
    b.group(g);
    b.channel(NioSocketChannel.class);
    b.option(ChannelOption.SO_KEEPALIVE, true);
    b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
    b.remoteAddress(host, port);

    // 设置通道初始化
    b.handler(......);

    ChannelFuture f = b.connect();
    ......
    // 此处的future与上面的f是同一个对象
    f.addListener((ChannelFuture future) ->
    {
        final EventLoop eventLoop
                = future.channel().eventLoop();
        if (!future.isSuccess()) {
            // 连接失败!在10s之后准备尝试重连!
            eventLoop.schedule(
                    () -> doConnect(),
                    10,
                    TimeUnit.SECONDS);

        } else {
            channel = future.channel();
        }

    });
  • bossGroup负责服务器通道新连接的IO事件的监听、workerGroup负责传输通道的IO事件的处理
  • NioServerSocketChannel负责服务器监听和接收,称为父通道;接收到的NioSocketChannel,称为子通道
  • 分配器
    • PoolByteBufAllocator:池化ByteBuf分配器
    • UnPooledByteBufAllocator:普通的ButeBuf分配器,比较占用内存
  • ByteBuf缓冲区
    • HeapByteBuf:JVM堆内存
    • DirectByteBuf:操作系统物理内存,是netty默认的缓冲区类型
  • childHandler是装配子通道的流水线,父通道的业务处理是固定的:接受新连接后,创建子通道,然后初始化子通道,所以不需要特别的配置
  • 每当有客户端连接时,会创建一个channel,同时添加一系列handler处理器
    • 发送信息时,pipeline按照从后往前的顺序执行write方法,如果调用super.write(ctx, msg, promise),将其交给下一个Handler处理
    • 发送消息完毕后,pipeline按照从后往前的顺序执行flush方法,如果调用super.flush(ctx),将其交给下一个Handler处理
    • 接收信息时,pipeline按照添加顺序执行channelRead方法,如果调用super.channelRead(ctx, msg),将其交给下一个Handler处理
    • 接收消息完毕后,pipeline按照添加顺序执行channelReadComplete方法,如果调用super.channelReadComplete(ctx),将其交给下一个Handler处理
    • 在未调用过channel.close()方法的情况下断开连接时,pipeline按照添加顺序先执行channelReadComplete方法,再执行exceptionCaught方法,如果调用super.exceptionCaught(ctx, cause),将其交给下一个Handler处理
    • 连接断开后,pipeline按照添加顺序执行channelInactive方法,如果调用super.channelInactive(ctx),将其交给下一个Handler处理;最后按照添加顺序执行channelUnregistered方法,如果调用super.channelUnregistered(ctx),将其交给下一个Handler处理
  • 在Netty中,网络连接通道的输入和输出、入站和出站操作都是异步进行的,会返回一个ChannelFuture接口的实例,可以为实例增加异步回调的监听器。在异步任务真正完成后,回调才会执行。客户端Demo的代码演示的是连接时的异步回调监听。

编码与传输协议

  • ByteToMessageDecoder,一个解码器抽象类,继承ChannelInboundHandlerAdapter,在读取消息时,如果消息是ByteBuf实现类,会执行其实现类的decode方法(如:将ByteBuf解码为Java对象)
    • 内置解码器有LineBasedFrameDecoder、DelimeterBasedFrameDecoder、LengthFieldBasedFrameDecoder等
  • MessageToByteEncoder<I>,一个编码器抽象类,继承ChannelOutboundHandlerAdapter,在发送消息时,如果消息是泛型对象I类或其子类,会执行其实现类的encode方法(如:将Java对象编码为ByteBuf)
  • MessageToMessageEncoder,将一种Java对象编码成另一种Java对象
  • 粘包:接收端收到一个ByteBuf,包含多个发送端的ByteBuf,多个ByteBuf粘在一起
  • 半包:一个接收端收到的ByteBuf是发送端的一个ByteBuf的一部分
  • ProtoBuf:一种数据交换格式,是一套类似于json或者xml的一种数据传输格式和规范,可以理解为一种序列化与反序列化方案

ZooKeeper

基本知识

  • 下载,百度搜索ZooKeeper,在Apache官网下载
  • 目录结构
日志目录:/log
数据目录:/data
    数据目录下需要创建一个myid文件,记录节点id,要求唯一
配置目录:conf下的.cfg文件
启动服务端: /bin/zkServer.cmd
启动客户端:/bin/zkCli.cmd --server ip:port
  • 集群节点要求是奇数,并且需要保证半数以上可用
  • 达到半数以上时,会推举一个节点作为Leader节点,其他是Follower节点
    • 首次选举
    • Leader节点挂了,重新选举
    • 节点间同步
  • 常用命令
    • 查看节点:ls
    • 查看节点值:get
    • 创建、修改、删除节点:create、set、delete、rmr
  • 节点类型
    • 持久化节点
    • 持久化顺序节点
    • 临时节点
    • 临时顺序节点
  • 存储模型 树形结构,一颗以"/"为根节点的数,每个圆圈是一个节点,称为ZNode,每个ZNode有一个节点值,如下图所示
    image.png

Java api类:Curator

<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.4.8</version>
</dependency>

<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-client</artifactId>
    <version>4.0.0</version>
    <exclusions>
        <exclusion>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>4.0.0</version>
    <exclusions>
        <exclusion>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>4.0.0</version>

</dependency>

ZooKeeper应用

  • 分布式Id(利用顺序节点自增)
  • 分布式锁(利用Curator的InterProcessMutex)
  • 服务监听(利用监听器实现,相关类有ZK原生Watcher、Curator的NodeCache、PathChildrenCache、TreeCache)