第三章:系统架构设计原则

好,咱们进入正题。这一章聊的是架构设计的四个核心原则——高内聚低耦合、模块化设计、可扩展性、高可用性。说白了,就是怎么把PIS系统搭得既结实又灵活。

我做了这么多年PIS系统,见过太多「一锅粥」式的架构。所有功能搅在一起,改一个地方崩一片。嗯,咱们今天就把这些坑一个个填上。

3.1 高内聚低耦合

先说说这个听起来有点玄乎的概念。高内聚,就是一个模块内部的东西要紧密相关。低耦合,就是模块之间要尽量少依赖。

举个例子。你想想看,列车到站信息显示和广播播报,这两个功能应该分开。它们各自管好自己的事,通过接口通信。这就是高内聚低耦合。

核心要点:

  • 每个模块只做一件事,并且做好
  • 模块间通过定义好的接口交互
  • 内部实现细节对外部不可见

我在项目中遇到过这样的情况:有个同事把LED显示逻辑和音频播放逻辑写在同一个类里。结果换LED屏的时候,音频也跟着出问题。这就是典型的耦合过紧。

3.2 模块化设计

模块化设计,说白了就是把系统拆成一个个独立的积木块。每个积木块有自己的职责,可以独立开发、测试、部署。

我个人习惯把PIS系统拆成这样:

模块名称 职责 依赖关系
数据采集模块 从信号系统获取列车位置、到站信息
数据处理模块 解析、格式化原始数据 依赖数据采集模块
显示控制模块 管理LED/LCD屏的显示内容 依赖数据处理模块
音频控制模块 管理广播播报 依赖数据处理模块
监控告警模块 监控各模块运行状态 依赖所有模块

你看,每个模块的依赖关系都很清晰。这样改一个模块,不会影响到其他模块。

我的经验:模块划分不要太细,也不要太粗。一般一个模块的代码量控制在1000-3000行比较合适。太细了管理成本高,太粗了又回到一锅粥。

3.3 可扩展性

做PIS系统,最怕的就是线路一增加,系统就撑不住了。可扩展性设计就是为了解决这个问题。

我建议从这几个方面入手:

  • 水平扩展:增加服务器节点就能提升处理能力
  • 垂直扩展:升级单机硬件配置
  • 功能扩展:新增线路时,只需添加配置,不用改代码

举个例子。我们之前做的一个项目,一开始只支持5条线路。后来要扩展到20条。因为架构设计得好,只需要在配置文件中添加新线路的信息,系统就能自动识别和处理。代码一行没改。

注意:可扩展性不是一蹴而就的。我曾经见过一个团队,为了「未来可能的需求」,把架构设计得极其复杂。结果系统上线后,80%的扩展功能根本没用上。嗯,这里要注意,适度设计就好。

3.4 高可用性设计

PIS系统要是挂了,乘客看不到到站信息,广播也不响了,那可就乱套了。所以高可用性是必须的。

我总结了几条关键策略:

  1. 冗余部署:关键服务至少部署两个实例
  2. 故障转移:一个实例挂了,自动切换到另一个
  3. 数据备份:配置数据、日志数据定期备份
  4. 健康检查:定期检查各模块是否正常运行

这里给个简单的健康检查代码示例:

// 伪代码示例
function healthCheck() {
    const modules = ['dataCollector', 'dataProcessor', 'displayController', 'audioController'];
    
    for (let module of modules) {
        let status = checkModule(module);
        if (status !== 'OK') {
            alertOperator(module + ' 异常');
            tryRestart(module);
        }
    }
}

// 每30秒执行一次
setInterval(healthCheck, 30000);

我曾经遇到过这样的情况:某个节点上的数据采集模块挂了,但因为没做健康检查,直到乘客投诉才发现。从那以后,我每个项目都会加上健康检查和自动恢复机制。

高可用性设计要点:

  • 单点故障要避免
  • 自动恢复要快
  • 人工介入要少
  • 监控告警要全

好了,这一章的内容就这些。四个原则说起来简单,但真正落地需要经验积累。你想想看,一个好的架构设计,能让后续的开发、维护、扩展都变得轻松。反之,架构设计不好,后面全是坑。

下一章咱们聊聊具体的系统模块划分和接口设计。到时候我会拿一个实际项目来拆解,看看这些原则是怎么落地的。