FantasticMao 技术笔记
BlogGitHub
  • README
  • C & Unix
    • C
      • 《C 程序设计语言》笔记
      • C 语言中的陷阱
      • CMake 示例
      • GNU make
      • LLVM Clang
      • Nginx 常用模块
      • Vim 常用命令
    • Unix-like
      • 《深入理解计算机系统》笔记
      • 《UNIX 环境高级编程》笔记 - UNIX 基础知识
      • 《UNIX 环境高级编程》笔记 - 文件 IO
      • 《UNIX 环境高级编程》笔记 - 标准 IO 库
      • 《鳥哥的 Linux 私房菜》笔记 - 目录配置
      • 《鳥哥的 Linux 私房菜》笔记 - 认识与学习 bash
      • 《鳥哥的 Linux 私房菜》笔记 - 任务管理
      • OpenWrt 中的陷阱
      • iptables 工作机制
  • Go
    • 《A Tour of Go》笔记
    • Go vs C vsJava
    • Go 常用命令
    • Go 语言中的陷阱
  • Java
    • JDK
      • 《Java 并发编程实战》笔记 - 线程池的使用
      • 设计模式概览
      • 集合概览
      • HashMap 内部算法
      • ThreadLocal 工作机制
      • Java Agent
    • JVM
      • 《深入理解 Java 虚拟机》笔记 - Java 内存模型与线程
      • JVM 运行时数据区
      • 类加载机制
      • 垃圾回收算法
      • 引用类型
      • 垃圾收集算法
      • 垃圾收集器
    • Spring
      • Spring IoC 容器扩展点
      • Spring Transaction 声明式事务管理
      • Spring Web MVC DispatcherServlet 工作机制
      • Spring Security Servlet 实现原理
    • 其它
      • 《Netty - One Framework to rule them all》演讲笔记
      • Hystrix 设计与实现
  • JavaScript
    • 《写给大家看的设计书》笔记 - 设计原则
    • 《JavaScript 权威指南》笔记 - jQuery 类库
  • 数据库
    • ElasticSearch
      • ElasticSearch 概览
    • HBase
      • HBase 数据模型
    • Prometheus
      • Prometheus 概览
      • Prometheus 数据模型和指标类型
      • Prometheus 查询语法
      • Prometheus 存储原理
      • Prometheus vs InfluxDB
    • Redis
      • 《Redis 设计与实现》笔记 - 简单动态字符串
      • 《Redis 设计与实现》笔记 - 链表
      • 《Redis 设计与实现》笔记 - 字典
      • 《Redis 设计与实现》笔记 - 跳跃表
      • 《Redis 设计与实现》笔记 - 整数集合
      • 《Redis 设计与实现》笔记 - 压缩列表
      • 《Redis 设计与实现》笔记 - 对象
      • Redis 内存回收策略
      • Redis 实现分布式锁
      • Redis 持久化机制
      • Redis 数据分片方案
      • 使用缓存的常见问题
    • MySQL
      • 《高性能 MySQL》笔记 - Schema 与数据类型优化
      • 《高性能 MySQL》笔记 - 创建高性能的索引
      • 《MySQL Reference Manual》笔记 - InnoDB 和 ACID 模型
      • 《MySQL Reference Manual》笔记 - InnoDB 多版本
      • 《MySQL Reference Manual》笔记 - InnoDB 锁
      • 《MySQL Reference Manual》笔记 - InnoDB 事务模型
      • B-Tree 简述
      • 理解查询执行计划
  • 中间件
    • gRPC
      • gRPC 负载均衡
    • ZooKeeper
      • ZooKeeper 数据模型
    • 消息队列
      • 消息积压解决策略
      • RocketMQ 架构设计
      • RocketMQ 功能特性
      • RocketMQ 消息存储
  • 分布式系统
    • 《凤凰架构》笔记
    • 系统设计思路
    • 系统优化思路
    • 分布式事务协议:二阶段提交和三阶段提交
    • 分布式系统的技术栈
    • 分布式系统的弹性设计
    • 单点登录解决方案
    • 容错,高可用和灾备
  • 数据结构和算法
    • 一致性哈希
    • 布隆过滤器
    • 散列表
  • 网络协议
    • 诊断工具
    • TCP 协议
      • TCP 报文结构
      • TCP 连接管理
由 GitBook 提供支持
在本页
  • 作者介绍
  • 演讲视频
  • Netty 4 中的优化
  • ChannelPipeline
  • 减少内存垃圾
  • 使用 JNI
  • 更友好的 Buffers
  • 线程模型
  • 与 JVM
  1. Java
  2. 其它

《Netty - One Framework to rule them all》演讲笔记

最后更新于1年前

作者介绍

这次演讲的讲师是 Netty 项目领导者,同时也是经典书籍 的作者 。

演讲视频

Netty 4 中的优化

Netty 3 存在诸多明显的设计缺陷:

  • 很多内存垃圾(在高并发的场景下,GC 的负担会变得更重);

  • 很多内存拷贝(Java Heap -> OS 内存 -> Socket);

  • 缺少一个好的内存池(频繁地创建和销毁直接内存将会非常损耗性能);

  • 缺少对于 Linux 操作系统的优化(不能使用 Linux 操作系统下的特性);

  • 不太合理的线程模型(Inbound 和 Outbound 的操作是在不同线程中的)。

Netty 4 对以上问题做了优化:

  1. 产生更少的内存垃圾,也会更少地触发 GC;

  2. 使用 JNI 来支持某些 Linux 操作系统下仅有的特性;

  3. 提供了一个高性能的 Buffer Pool;

  4. 定义了一个易于使用的线程模型。

ChannelPipeline

Netty 中的 Channel 是对 Socket 的抽象,可以用于网络数据的读取和写入。每个 Channel 会对应一个 ChannelPipeline,ChannelPipeline 是一个包含了不同 ChannelHandler 的双向链表,ChannelHandler 可以用于处理 Inbound 和 Outbound 事件。

+------------------+
|    Channel       |
|                  |
|          +-------+----------------------------------+
|          |       |           ChannelPipeline        |
+----------+-------+                                  |
  ^   |    |                                          |
  |   |    |     +-------+   +-------+   +-------+    |
  |   v    |     |Channel|   |Channel|   |Channel|    |
  |  IN -->|---->|Inbound|-->|Inbound|-->|Inbound|    |
  |        |     |Handler|   |Handler|   |Handler|    |
  |        |     +-------+   +-------+   +-------+    |
  |        |                                          |
  |        |        +--------+      +--------+        |
  |        |        |Channel |      |Channel |        |
  OUT <----|<-------|Outbound|<-----|Outbound|        |
           |        |Handler |      |Handler |        |
           |        +--------+      +--------+        |
           |                                          |
           +------------------------------------------+

减少内存垃圾

Netty 中引入了一个非常轻量级的对象池。在 Netty 中存在着许多可以被复用的对象,并且这些对象会被限制在同一个线程中,例如在把 Byte 转换为 List<Object> 的编解码器中,Netty 不需要每次都创建一个新的 List,而是会把这个 List 缓存起来并且会重用它。

使用 JNI

JDK 中的 NIO 是对 Socket 的抽象,可以运行在不同操作系统上,但是 NIO 并没有针对具体的操作系统来做优化。

Netty 使用 JNI 来提供了 NIO 中所有没有提供的、与操作系统相关的高级特性,例如 epoll。

// NIO Transport
Bootstrap bootstrap = new Bootstrap()
            .group(new NioEventLoopGroup())
            .channel(NioSocketChannel.class);

// Native Transport
Bootstrap bootstrap = new Bootstrap()
            .group(new KQueueEventLoopGroup())
            .channel(EpollSocketChannel.class);

更友好的 Buffers

JDK 中提供的 ByteBuffer 接口并不友好,Netty 中实现了一套更加友好的 Buffer 实现:ByteBuf。

Netty 中的 ByteBuf 是基于引用计数算法来管理内存的,并且 Netty 提供了一个内存溢出的检测器:ResourceLeakDetector,可以用于检测潜在的资源泄漏问题。

线程模型

Netty 中的 EventLoop 是对 I/O 线程的抽象,用于处理 I/O 操作和触发事件。EventLoop 继承了 EventExecutor,EventExecutor 继承了 ScheduledExecutorService,这意味着开发者可以在一个处理 Channel 的 I/O 线程里编排事件。

Netty 提供了 EventExecutor,可以用于处理 Handler 中的一些可能会导致阻塞的事件。

与 JVM

当在 Java 中做很多底层性能相关的事情,例如网络编程,便会经常接触到 JVM。

在 JVM 中,对直接内存的管理仅是通过 finalizer 或 cleaner 机制来实现的,并且 JVM 只有在堆空间耗尽的时候才会进行 GC。然而,Netty 在被用于网络编程的时候,可以确切地知道某个对象在何时应该被回收,因此 JVM 对直接内存的管理方式并不适用于 Netty。

在 JVM 中,JIT 编译器会重新布局 class 文件,为了减少内存间隙和避免浪费内存。但有时,这会产生内存伪共享(False-Sharing)问题。

在 JDK 中的 NIO 也存在诸多问题:

  • NIO2 并没有真正地提供 NIO 的可用性;

  • NIO 会产生很多内存垃圾,例如 Selector、Keyset 等等;

  • ByteBuffer API 并不友好;

《Netty in Action》
Norman Maurer
https://www.bilibili.com/video/BV14t411G7Lp