Java 网络编程最佳实践
1. 通信层
- 直接使用最成熟的网络框架,如 Netty
- 单连接 & 连接复用 & 长连接
- 建议提前设计心跳机制
- 集群较小,长连接无需开启心跳
- 如果网络情况比较复杂,建议开启心跳。如有防火墙,会将连接清掉且不会向客户端发送 RST 信令,导致长连接变成一个脏连接
2. 线程模型
如果采用了 Netty 这样的框架,线程模型基本已经决定了,但是 Netty 只需负责 IO 处理,需要提供额外的业务线程池负责处理业务请求。
- 序列化过程在业务线程中处理
- 请求/响应包多个批量从 IO 线程交给业务线程处理
- 服务端线程池需要有保护策略
- 框架层面的 RejectExcetpion
- 业务层面的限流策略
- 需要定时打印线程池大小,方便性能分析
3. 序列化
- 全站都是 Java 系
为了以后能让其它语言更好的交互,协议设计越扁平越好,切忌将整个协议类对象序列化,仅整个序列化方法参数对象列表及返回值对象。
- 全站各种语言百花齐放
可以考虑直接使用 Protobuf 或者 msgpack 这样的跨语言的序列化协议,但我个人没使用经验。
4. 容灾
- 必须要有超时时间,分布式环境下无超时机制对整体环境影响非常大
- 需要有连接隔离机制(根据请求量、错误率等)
- 可参考 Netflix 的 ribbon
5. 故障定位
- 客户端发送、服务端接收均需要打印日志,日志必须要有的几个字段:
- 时间戳
- 唯一ID: 由于客户端和服务端的请求量较大,所以需要有唯一 ID 能够将客户端日志和服务端请求串起来
- IP 信息
- 如下:
- client:time,unique-id,server-ip
- server:time,unique-id,client-ip
- 提供较好的方式打印网络层日志
- 经常会发生客户端有请求日志,但是服务端没有接收日志的情况
- 这个时候无法判断是客户端出错还是服务端出错,可以提供 debug 日志打印网络层的请求日志