Ignite端口管理组件GridPortProcessor全解析
这个 GridPortProcessor
类是 Apache Ignite 中一个非常实用的 端口管理组件,它的核心职责是:
🎯 统一跟踪和管理 Ignite 节点在运行过程中所使用的各种网络端口。
它不直接打开或关闭端口,而是作为一个“端口注册中心”,记录哪些组件(类)使用了哪些端口,并在端口状态变化时通知监听器。
🧱 一、类概览
public class GridPortProcessor extends GridProcessorAdapter
- 继承自
GridProcessorAdapter
→ 是 Ignite 内核的一个标准组件 - 功能:集中式端口使用情况登记簿
- 用于:
- 调试
- 监控
- 防止端口冲突
- 提供“当前节点用了哪些端口”的统一视图
🔩 二、关键字段解析
字段 | 类型 | 作用 |
---|---|---|
recs | Collection<GridPortRecord> | 存储所有已注册的端口记录(按端口号排序) |
lsnrs | Collection<GridPortListener> | 端口变化监听器列表 |
1. recs
:端口记录集合
- 使用
TreeSet
+ 自定义Comparator
→ 按 端口号升序 排序 - 元素类型:
GridPortRecord(port, protocol, clazz)
port
:端口号(如 47100)protocol
:协议类型(如 TCP, HTTP, JMX)clazz
:哪个类(组件)使用了这个端口(如TcpDiscoverySpi
)
✅ 这样可以方便地查看“谁用了哪个端口”。
2. lsnrs
:监听器列表
- 使用
LinkedHashSet
→ 保证唯一性和插入顺序 - 当端口注册/注销时,会通知所有监听器
🔐 三、线程安全设计
所有对 recs
和 lsnrs
的操作都加了 synchronized
锁:
synchronized (recs)
:保护端口记录synchronized (lsnrs)
:保护监听器列表
⚠️ 虽然性能不如并发集合(如
ConcurrentHashMap
),但这里数据量小,且操作不频繁,简单synchronized
更安全、易维护。
📥 四、核心方法详解
✅ 1. registerPort(...)
:注册端口使用
public void registerPort(int port, IgnitePortProtocol proto, Class cls)
- 用途:当某个组件(如 SPI)绑定了一个端口后,调用此方法登记
- 示例:
portProcessor.registerPort(47100, TCP, TcpDiscoverySpi.class); portProcessor.registerPort(8080, HTTP, JettyRestProcessor.class);
🔍 断言检查:确保端口范围合法(1~65534),协议和类非空
✅ 2. deregisterPorts(Class cls)
:注销某个类的所有端口
public void deregisterPorts(Class cls)
- 用途:当某个组件关闭时,清理它占用的所有端口
- 场景:SPI 停止、Manager 销毁
✅ 3. deregisterPort(...)
:注销特定端口
public void deregisterPort(int port, IgnitePortProtocol proto, Class cls)
- 更精确的注销,用于只释放某个特定端口
✅ 4. records()
:获取当前所有端口记录
public Collection<GridPortRecord> records()
- 返回一个 不可修改的副本
- 外部可以安全遍历,不会影响内部状态
- 内部先
new ArrayList<>(recs)
再unmodifiableCollection
→ 避免迭代时被修改
✅ 5. addPortListener(...)
/ removePortListener(...)
- 允许其他组件监听端口变化
- 典型用途:
- 监控系统:端口变化时上报
- 调试工具:实时刷新端口列表
- 安全审计:记录端口使用历史
✅ 6. notifyListeners()
:通知所有监听器
private void notifyListeners() {synchronized (lsnrs) {for (GridPortListener lsnr : lsnrs)lsnr.onPortChange();}
}
- 每次注册/注销端口后都会调用
- 实现 观察者模式(Observer Pattern)
🧩 五、GridPortRecord
和 GridPortListener
是什么?
1. GridPortRecord
一个简单的 值对象(VO),包含:
class GridPortRecord {private final int port;private final IgnitePortProtocol protocol;private final Class clazz;
}
- 不可变对象(Immutable),线程安全
2. GridPortListener
一个监听接口:
interface GridPortListener {void onPortChange();
}
- 当端口注册/注销时触发
- 可用于刷新 UI、写日志、触发检查等
🎯 六、典型使用场景
场景 1:SPI 启动时注册端口
// 在 TcpDiscoverySpi.start() 中
int boundPort = serverSocket.bind(port);
portProcessor.registerPort(boundPort, TCP, TcpDiscoverySpi.class);
场景 2:SPI 停止时注销端口
// 在 TcpDiscoverySpi.stop() 中
portProcessor.deregisterPorts(TcpDiscoverySpi.class);
场景 3:运维命令查看端口
# ignite.sh --show-ports
Used ports:47100: TCP, TcpDiscoverySpi47500: TCP, TcpCommunicationSpi8080: HTTP, JettyRestProcessor9999: JMX, JmxLocalServer
✅ 这些信息就是从
GridPortProcessor.records()
获取的。
🛠 七、printMemoryStats()
:内存统计(调试用)
@Override
public void printMemoryStats() {X.println(">>> Task session processor memory stats...");X.println(">>> recsSize: " + recs.size());X.println(">>> lsnrsSize: " + lsnrs.size());
}
- 输出当前记录数和监听器数
- 用于 内存泄漏排查 或 运行时诊断
- 通过 JMX 或控制台命令触发
🎨 八、设计亮点总结
特性 | 说明 |
---|---|
集中管理 | 所有组件统一注册端口,避免“黑盒” |
可观测性 | 提供 API 查询当前端口使用情况 |
事件驱动 | 支持监听端口变化,便于集成监控 |
线程安全 | 正确使用 synchronized 保护共享状态 |
防御性编程 | 断言 + 不可变返回值 + 空值检查 |
简洁清晰 | 单一职责,代码易读 |
📌 九、一句话理解
GridPortProcessor
是 Ignite 的 “端口户口本” —— 每个组件在使用网络端口时都要“上户口”(注册),关闭时要“销户”(注销),系统可以随时查“户口簿”了解当前端口使用情况,并在变化时通知“片警”(监听器)。
💡 十、你可以借鉴的设计模式
1. 注册-通知模式(Registry + Observer)
class PortRegistry {private Set<PortRecord> records = new TreeSet<>(...);private List<PortListener> listeners = new CopyOnWriteArrayList<>();void register(PortRecord r) {synchronized(records) { records.add(r); }notifyListeners();}void notifyListeners() {for (PortListener l : listeners) l.onChange();}
}
2. 不可变返回值
public Collection<PortRecord> getRecords() {synchronized(records) {return Collections.unmodifiableList(new ArrayList<>(records));}
}
避免外部修改内部状态。
🏁 总结
GridPortProcessor
虽然功能简单,但它体现了大型分布式系统中 资源管理的规范性 和 可观测性的重要性。
它不是一个“必须”的组件,但有了它:
- 运维人员可以快速诊断端口冲突
- 开发者可以清晰看到组件依赖
- 监控系统可以实时感知网络变化
🔔 好的系统,不仅要“能跑”,还要“看得见、管得住” ——
GridPortProcessor
正是为此而生。