Netty 实战入门
这一章不追求复杂协议,而是站在“博客项目可能怎么用 Netty”的角度,讲清楚落地思路。
博客项目为什么会用到 Netty
最常见的几个方向:
- WebSocket 在线聊天。
- 实时通知推送。
- 管理后台消息提醒。
- 长连接在线状态管理。
一个实时通知系统的大致结构
mermaid
flowchart TD
A["业务系统<br/>文章评论 / 点赞 / 私信"] --> B["通知服务<br/>生成通知事件"]
B --> C["Netty 或 WebSocket 服务<br/>维护长连接"]
C --> D["在线用户连接<br/>userId -> Channel"]
D --> E["浏览器实时收到消息"]核心原理
实时通知的本质不是“接口更快”,而是服务端能够主动找到用户的长连接并写入消息。传统 HTTP 请求通常是客户端主动拉取,服务端不能随时把新消息推给浏览器;Netty/WebSocket 维护长连接后,服务端就可以在业务事件发生时主动推送。
mermaid
flowchart TD
A["用户登录"] --> B["建立 WebSocket / TCP 长连接"]
B --> C["鉴权通过后绑定 userId 和 Channel"]
C --> D["业务系统产生通知事件"]
D --> E{"用户是否在线"}
E -- "在线" --> F["找到 Channel 并推送"]
E -- "离线" --> G["保存离线消息"]
F --> H["客户端确认或展示"]
G --> I["用户下次上线后拉取"]如果不理解这条链路,很容易把实时通知做成“前端每几秒轮询一次接口”。轮询简单但有明显代价:请求量高、消息不够实时、用户越多数据库压力越大。长连接也不是没有成本,它需要处理鉴权、心跳、断线清理、多节点路由和消息可靠性。
一个典型开发步骤
- 启动 Netty 服务端。
- 配置 BossGroup 和 WorkerGroup。
- 初始化 ChannelPipeline。
- 处理连接事件。
- 处理消息收发。
- 维护用户连接关系。
- 做心跳和断线清理。
典型消息流转
mermaid
sequenceDiagram
participant U as 用户浏览器
participant N as Netty服务
participant B as 博客业务服务
U->>N: 建立长连接
B->>N: 某文章收到新评论
N->>N: 找到文章作者在线连接
N-->>U: 推送评论通知本章小结
Netty 对博客项目最现实的价值,不是替代所有接口开发,而是承担“实时通信能力”。
如果你的博客后续想做:
- 实时通知。
- 聊天。
- 在线状态。
那么 Netty 会是一个非常值得深入的方向。
常见风险和设计取舍
| 问题 | 为什么会发生 | 处理方式 |
|---|---|---|
| 用户刷新页面后旧连接还在 | 旧 Channel 没有及时触发清理 | 在 channelInactive 中解绑,并定期校验连接活跃状态 |
| 多节点部署找不到用户连接 | 用户连接分散在不同 Netty 节点 | 使用 Redis 记录 userId 到节点的映射,或让消息先进入 MQ |
| 客户端假在线 | 网络断开但服务端暂时没感知 | 增加心跳和读空闲检测 |
| 消息丢失 | 推送时连接断开或写失败 | 重要通知先落库,再推送,客户端可补拉 |
| 推送太快导致堆积 | 客户端消费慢或网络差 | 做限流、批量、丢弃低价值消息或断开异常连接 |
代码 Demo:维护用户连接
java
public class OnlineChannelManager {
private static final Map<Long, Channel> USER_CHANNELS = new ConcurrentHashMap<>();
public static void bind(Long userId, Channel channel) {
USER_CHANNELS.put(userId, channel);
}
public static void unbind(Long userId) {
USER_CHANNELS.remove(userId);
}
public static void push(Long userId, String message) {
Channel channel = USER_CHANNELS.get(userId);
if (channel == null || !channel.isActive()) {
return;
}
channel.writeAndFlush(message);
}
}业务系统产生通知后,可以调用:
java
OnlineChannelManager.push(authorId, "你的文章收到了新评论");真实项目中还要处理多节点连接分布、用户鉴权、心跳检测、消息确认和离线消息。
