Netty框架简介

概览

  • https://netty.io/
  • 网络应用开发框架
    • 异步
    • 事件驱动
    • 基于NIO
  • 适用于
    • 服务端
    • 客户端
    • TCP/UDP
  • 特性
    • 高吞吐
    • 低延迟
    • 低开销
    • 零拷贝
    • 可扩容
    • 松耦合
    • 使用方便可维护

netty.png

Server分级

  • HTTP Server
    • 只实现基础的HTTP协议
    • 无状态
  • Web Server
    • 在HTTP Server之上支持Web组件
    • Session机制、JSP等
  • JavaEE

    • 在WebServer之上支持 Bean等

      基本概念

  • Channel

    • 通道
    • NIO中的基础概念,代表一个打开的连接,可执行读取/写入IO操作
    • netty对Channel的所有IO操作都是非阻塞的
  • ChannelFuture
    • Java的Future接口,只能查询操作的完成情况或阻塞当前线程等待操作完成
    • netty封装一个ChannelFuture接口,我们可以将回调方法传给ChannelFuture,操作完成时自动执行
  • ChannelPipline
    • 数据处理管道就是事件处理器链
    • 有顺序、同一个Channel的出站处理器和入站处理器在同一个列表中
  • Event&Handler
    • 基于事件驱动
    • 事件和处理器可以关联到入站和出站数据流
    • 入站事件
      • 通道激活和停用
      • 读操作事件
      • 异常事件
      • 用户事件
    • 出站事件
      • 打开连接
      • 关闭连接
      • 写入数据
      • 刷新数据
    • 事件处理程序接口
      • ChannelHandler
      • ChannelOutboundHandler
      • ChannelInboundHandler
    • 适配器(空实现,需要继承使用)
      • ChannelInboundHandlerAdapter
      • ChannelOutboundHandlerAdapter
  • Encoder&Decoder

    • 处理网络IO时,需要进行序列化和反序列化,转换Java对象和字节流
    • 对入站数据进行解码,基类是ByteToMessageDecoder
    • 对出站数据进行编码,基类是MessageToByteEncoder

      netty应用组成

  • 网络事件

  • 应用程序逻辑事件
  • 事件处理程序

    使用示例

    netty-server.zip

    Netty原理

    启动和处理流程

    netty启动和处理流程.png

    高性能

    指标

  • 高并发用户ConcurrentUsers(业务角度)

    • 日活/月活
    • 同时在线
  • 高吞吐量Throughout(技术角度)
    • QPS
    • TPS
  • 低延迟Latency(技术角度)
    • RT 响应时间是从用户角度看
    • Latency 延迟时间是从系统内部看,不包括RT中的网络延迟时间
    • 通常要重点观测P90/P99的延迟分布 ```shell

      wrk -c 40 -d 30s —latency http://localhost:8088

-c 40 指并发连接40

得到的QPS/TPS 指吞吐量

得到的latency 指延迟,

  1. <a name="Lfq0w"></a>
  2. ### 副作用
  3. - 系统复杂度
  4. - 建设与维护成本
  5. - 故障或Bug导致的破坏性
  6. <a name="cm3Sp"></a>
  7. ### 应对策略
  8. - 稳定性建设(混沌工程、Netflix公司的SpringCloud类似解决方案)
  9. - 容量(系统现状和业务需求)
  10. - 爆炸半径(微服务拆分)
  11. - 工程方面积累与改进(变更流程控制和技术研究)
  12. <a name="ljNYy"></a>
  13. ## 如何实现高性能
  14. <a name="EjqF0"></a>
  15. ### 统一开发框架
  16. - 异步
  17. - 事件驱动
  18. - 基于NIO
  19. <a name="Fcnwn"></a>
  20. ### 事件处理机制
  21. ![事件处理机制.png](https://cdn.nlark.com/yuque/0/2020/png/1491874/1605414263273-099c51ff-976d-46fd-964d-27474baed5af.png#align=left&display=inline&height=1088&margin=%5Bobject%20Object%5D&name=%E4%BA%8B%E4%BB%B6%E5%A4%84%E7%90%86%E6%9C%BA%E5%88%B6.png&originHeight=1088&originWidth=1420&size=603627&status=done&style=none&width=1420)
  22. <a name="z6fSo"></a>
  23. ### 从事件驱动机制到Reactor模型
  24. - Reactor模型首先是事件驱动的
  25. - 有一个或多个并发输入源
  26. - 有一个ServiceHandler和多个EventHandlers
  27. - ServiceHandler会同步的将输入的请求多路复用的分发给相应的EventHandler
  28. ![Reactor模型.png](https://cdn.nlark.com/yuque/0/2020/png/1491874/1605414672701-bd9c7fca-cc77-4e19-8f90-aada99d3ae39.png#align=left&display=inline&height=1082&margin=%5Bobject%20Object%5D&name=Reactor%E6%A8%A1%E5%9E%8B.png&originHeight=1082&originWidth=1714&size=821577&status=done&style=none&width=1714)
  29. <a name="cYXws"></a>
  30. ### 从Reactor模型到NettyNIO
  31. - BossEventLoopGroup
  32. - WorkerEventLoopGroup
  33. ![NettyNIO.png](https://cdn.nlark.com/yuque/0/2020/png/1491874/1605414884535-dad46f7a-c470-4473-92ea-f5f9971aaa64.png#align=left&display=inline&height=922&margin=%5Bobject%20Object%5D&name=NettyNIO.png&originHeight=922&originWidth=1470&size=856184&status=done&style=none&width=1470)<br />![Netty运行原理.png](https://cdn.nlark.com/yuque/0/2020/png/1491874/1605415122598-0bc4f698-d477-484d-9c12-6b96217903fe.png#align=left&display=inline&height=1468&margin=%5Bobject%20Object%5D&name=Netty%E8%BF%90%E8%A1%8C%E5%8E%9F%E7%90%86.png&originHeight=1468&originWidth=1440&size=852197&status=done&style=none&width=1440)
  34. <a name="iter8"></a>
  35. ## 关键对象
  36. <a name="yH5Po"></a>
  37. ### 全局
  38. - Bootstrap:启动线程,开启socket
  39. - EventLoopGroup/EventLoop
  40. - SocketChannel:连接
  41. - ChannelInitializer:初始化
  42. - ChannelPipline:处理器链
  43. - ChannelHandler:处理器
  44. ![Bootstrap.png](https://cdn.nlark.com/yuque/0/2020/png/1491874/1605425227299-48a90479-3e6b-40d1-a719-ed0f39995ec8.png#align=left&display=inline&height=510&margin=%5Bobject%20Object%5D&name=Bootstrap.png&originHeight=510&originWidth=928&size=141478&status=done&style=none&width=928)<br />![关键对象.png](https://cdn.nlark.com/yuque/0/2020/png/1491874/1605425367429-2ff7ee2a-30a8-43c1-b24e-7ed78c552ab8.png#align=left&display=inline&height=1104&margin=%5Bobject%20Object%5D&name=%E5%85%B3%E9%94%AE%E5%AF%B9%E8%B1%A1.png&originHeight=1104&originWidth=984&size=253017&status=done&style=none&width=984)
  45. <a name="ylEcV"></a>
  46. ### ChannelPipline
  47. ![ChannelPipline.png](https://cdn.nlark.com/yuque/0/2020/png/1491874/1605425871549-fd42f760-07fe-40c3-8eeb-1ab410d2a3da.png#align=left&display=inline&height=1086&margin=%5Bobject%20Object%5D&name=ChannelPipline.png&originHeight=1086&originWidth=944&size=370295&status=done&style=none&width=944)
  48. <a name="KOm3k"></a>
  49. ### Event&Handler
  50. - 入站事件
  51. - 通道激活和停用
  52. - 读操作事件
  53. - 异常事件
  54. - 用户事件
  55. - 出站事件
  56. - 打开连接
  57. - 写入数据
  58. - 刷新数据
  59. - 关闭连接
  60. - 事件处理程序接口
  61. - ChannelHandler
  62. - ChannelInboundHandler
  63. - ChannelOutboundHandler
  64. - 适配器(空实现,需要继承使用)
  65. - ChannelInboundHandlerAdapter
  66. - ChannelOutboundHandlerAdapter
  67. <a name="VmTgb"></a>
  68. ## 三种模式
  69. <a name="2w9xB"></a>
  70. ### Reactor单线程模型
  71. ```java
  72. EventLoopGroup elg = new NioEventLoopGroup(1);
  73. ServerBootstrap serverBootstrap = new ServerBootstrap();
  74. serverBootstrap.group(elg);

非主从Reactor多线程模型

  1. EventLoopGroup elg = new NioEventLoopGroup(); // 默认2倍的cpu核心数
  2. ServerBootstrap serverBootstrap = new ServerBootstrap();
  3. serverBootstrap.group(elg);

主从Reactor多线程模型

EventLoopGroup bossGroup = new NioEventLoopGroup(); // 默认2倍的cpu核心数
EventLoopGroup workerGroup = new NioEventLoopGroup(); // 默认2倍的cpu核心数
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup,workerGroup);

Netty网络程序优化

粘包与拆包

  • 都是人为的上层问题,没有协商好ContentLength,和底层的TCP没有关系
  • 解决方案就是协商好包的边界/ContentLength
  • TCP有粘包问题,HTTP/UDP没有,因为UDP是单工的,HTTP做了校验
  • ByteToMessageDecoder提供的一些常见的实现类:
    • FixedLengthFrameDecoder
      • 定长解码器
      • 可以指定固定的字节数算一个完整的报文
    • LineBasedFrameDecoder
      • 行分隔符解码器
      • 遇到\n或\r\n则认为是一个完整的报文
    • DelimiterBasedFrameDecoder
      • 分隔符解码器
      • 分隔符可以自己指定
    • LengthFieldBasedFrameDecoder
      • 长度编码解码器
      • 将报文划分为报文头/报文体
    • JsonObjectDecoder
      • json格式解码器
      • 检测到匹配数量的{} 或 []时,则认为是一个完整的Json对象或Json数组

粘包与拆包.png

Nagle与TCP_NODELAY

  • 概念
    • MTU:MaximumTransmissionUnit 最大传输单元,标准1500
    • MSS:MaximumSegmentSize 最大分段大小,标准1460(=1500-20字节的IP头-20字节的TCP头)
    • MSL:MaximumSegmentLifetime 最大分段生命值,标准1/2分钟
  • 网络拥堵与Nagle算法优化,为了最高效实现通信,需要对网络进行优化,避免应用层直接发送/接收数据
  • 操作系统真正发送网络包的条件
    • 缓冲区满
    • 达到超时(200ms)
  • TCP_NODELAY

    • 开启后操作系统发送包时机直接由应用决定,这时上层应用需要考虑MSS尽量控制在阈值内
    • 所以在高并发场景下要设置为true

      连接优化

  • TCP经过2MSL后被真正释放优化点

    • 降低MSL时间
    • 重用TIME-WAIT阶段被占用的端口

三次握手四次挥手.png

Netty优化

  • 不要阻塞EventLoop
  • 系统参数优化
    • ulimit -a 调整fd
    • /proc/sys/net/ipv4/tcp_fin_timeout或windows的注册表中的TcpTimedWaitDelay
  • 缓冲区优化
    • SO_RCVBUF 通常设置为32K
    • SO_SNDBUF 通常设置为32K
    • SO_BACKLOG 未正常建立连接的连接记录
    • REUSEXXX
  • 心跳周期优化
    • 心跳机制
      • 心跳周期,如果一直有数据传输则关闭心跳
      • 心跳频率
    • 断线重连
  • 内存与ByteBuffer优化
    • DirectBuffer
    • HeapBuffer
  • 其他优化

    • ioRatio
    • Watermark
    • TrafficShaping

      API网关

      网关

      四大职能

  • 请求接入

    • 作为所有API接口服务请求的接入点
  • 业务聚合
    • 作为所有后端业务服务的聚合点
  • 中介策略
    • 实现安全、验证、路由、过滤、流控等策略
  • 统一管理

    • 对所有API服务和策略进行统一管理

      两大分类

  • 流量网关(关注稳定与安全)

    • 全局性流控
    • 日志统计
    • 防止SQL注入
    • 防止Web攻击
    • 屏蔽工具扫描
    • 黑白IP名单
    • 证书/加解密处理
  • 业务网关(提供更好的服务)

    • 服务级别流控
    • 服务降级与熔断
    • 路由与负载均衡、灰度策略
    • 服务过滤、聚合、发现
    • 权限验证与用户等级策略
    • 业务规则与参数校验
    • 多级缓存策略

      对比推荐

  • 流量网关(高性能)

    • OpenResty
    • Kong
  • 业务网关(扩展性好,适合二次开发)

    • SpringCloudGateway
    • Zuul2

      典型应用

      zuul

  • Netflix开源的API网关系统

  • 主要设计目标是动态路由、监控、弹性、安全
  • 内部可以看作不同功能filter的集合,最主要的就是pre、routing、post三种过滤器

zuul.png

zuul2

  • 基于netty内核重构

zuul2.png

SpringCloudGateway

springcloudgateway.png

实践

  • 参考下面代码的nio02

https://github.com/JavaCourse00/JavaCourseCodes

  • 架构设计
    • 设计:技术复杂度和业务复杂度
    • 抽象:理清概念,正确命名
    • 组合:组件之间的相互关系