4 Matching Annotations
  1. Last 7 days
    1. 我们都知道 TCP 连接建立是需要三次握手

      同一个端口的两个 socket:默认不能同时绑定监听,因此无法各自建立连接(特殊配置下的复用不改变 “四元组唯一” 的核心规则)。 端口的作用是 “区分服务”,而连接的唯一性由 “四元组” 保证,因此多个端口自然支持更多独立连接,这也是服务器通常会开放多个端口(如 80、443、3306 等)提供不同服务的原因。

  2. Sep 2025
    1. 分布式 ID 常见解决方案

      数据库

      • 美团的期数用的是单纯的数据库访问(并发量不高)
      • 号段+CAS
      • Redsi自增命令(原子操作)

      算法

      • UUID(引擎的ID- 不自增)
      • 雪花算法(符号 + 时间戳 + 机房号)

      开源框架

    1. Netty 的 I/O 模型是基于非阻塞 I/O 实现的,底层依赖的是 NIO 框架的多路复用器 Selector。采用 epoll 模式后,只需要一个线程负责 Selector 的轮询。当有数据处于就绪状态后,需要一个事件分发器(Event Dispather),它负责将读写事件分发给对应的读写事件处理器(Event Handler)。事件分发器有两种设计模式:Reactor 和 Proactor,Reactor 采用同步 I/O, Proactor 采用异步 I/O。

      在 Java NIO 和操作系统 I/O 模型里,epollselectpoll 都是 I/O 多路复用机制,主要用来监控多个文件描述符(socket 等)是否可读/可写。它们的区别可以从以下几个方面理解:


      1. select

      • 原理:使用一个固定大小的 bitmask(位图)来表示文件描述符集合,每次调用时需要把整个 fd 集合从用户态拷贝到内核态。
      • 限制

      • 最大监控 fd 数量有限(一般 1024,依赖编译时 FD_SETSIZE)。

      • 每次调用都需要重新构造 fd 集合,效率低。
      • 复杂度:O(n),每次轮询都要扫描所有 fd。

      2. poll

      • 原理:用一个数组存储待监听的 fd,每次调用时同样要把数组拷贝到内核。
      • 改进

      • 没有 select 的 1024 限制,可以监听更多 fd。

      • 缺点

      • 每次调用依然需要 线性扫描整个数组,性能随 fd 数量线性下降。

      • 复杂度:O(n)。

      3. epoll

      • 原理:Linux 特有的高效 I/O 多路复用机制。采用 事件驱动(event-driven),在内核中维护一个红黑树存放所有监听的 fd,以及一个就绪队列。
      • 特点

      • 注册事件时(epoll_ctl)只需要传一次,内核会保存,不必像 select/poll 那样每次传整个 fd 集合。

      • 内核通过 回调机制 在 fd 状态变化时把其放入就绪队列,用户调用 epoll_wait 时直接返回活跃的 fd。
      • 没有数量限制(上限是系统可打开的文件描述符数量)。
      • 复杂度

      • 添加/删除 fd 是 O(log n)(红黑树)。

      • 等待事件是 O(1),只返回活跃的 fd,不需要扫描所有集合。

      4. 对比总结

      | 特性 | select | poll | epoll | | ------- | ------------------ | ------------- | ------------------- | | 数据结构 | 位图 | 数组 | 红黑树 + 就绪链表 | | fd 数量限制 | 1024 (FD_SETSIZE) | 无限制 | 无限制 | | 拷贝开销 | 每次调用都拷贝 fd 集合 | 每次调用都拷贝 fd 数组 | 注册时一次,之后无需重复拷贝 | | 事件检测方式 | 轮询(线性扫描) | 轮询(线性扫描) | 事件驱动(就绪队列) | | 性能 | O(n),低效 | O(n),低效 | O(1),高效 | | 适用场景 | 小规模连接 | 中等规模连接 | 大规模高并发(如 NIO、Netty) |


      5. Java NIO 中的对应

      • Java 的 Selector 底层在不同操作系统上会使用不同实现:

      • Linux:优先用 epoll(高性能)。

      • macOS:用 kqueue
      • Windows:用 select 或 IOCP。
      • 所以你在 Java NIO 里调用 Selector.select(),在 Linux 下实际上就是基于 epoll