4938 words
25 minutes
高并发IO系统的架构演变
NOTE

所有内容均已去除敏感信息部分,企业技术并非对外开源,仅以非保密部分为例展开描述。

业务背景#

企业平台(父系统)旨在为从事人工智能研究的人员、学生提供一个开放的竞技与学习环境,促进人工智能技术的实践应用和创新。该平台支持多种竞赛形式,涵盖机器学习、深度学习、自然语言处理等领域的课题,选手可以在线提交模型和代码,并由系统自动评估成绩并生成实时反馈。平台同时具备数据管理与归档功能,支持活跃和历史数据的高效存储,以应对大规模用户和数据量的挑战。通过分层存储架构(如 MongoDB 和 MySQL 组合),平台既实现了性能优化,又确保了数据的安全和长期可访问性,为竞赛活动提供了可靠的技术支撑。

旗下的云资源管理系统作为父系统的子系统,负责在父子系统间进行 IO 调度工作,并为参赛者提供动态分配和管理计算资源,通过自动扩展、资源监控、安全控制和成本核算等功能,确保高效、稳定的资源支持,助力参赛者在高性能环境中完成模型训练和测试。

老架构演变历程#

随着平台每场比赛的参赛人员不断增加,平台处理打榜的性能不断走下降趋势,为快速应对性能瓶颈问题,优先采取了垂直扩展硬件性能和水平扩展 KVM 集群来分担单机的工作压力。并在后期不断探索更好的架构模式,以长期替换垂直、水平扩展这两个临时解决方案。

垂直扩展硬件#

在老架构中,整体系统被评估为属于一个中等负载、并发生命周期较长、非频繁创建和销毁对象的应用。所以给 JVM 设置的参数是:

  • -Xms 初始堆大小:512MB
  • -Xmx 最大堆大小:4G
    • 避免打榜期间触发 Heap Space OOM。
  • -Xmn 新生代大小:2G
    • 防止打榜期间无法创建新线程 Unable to Create New Native Thread。
  • -XX:-UseLargePages 禁用大页内存
    • 避免参赛者打榜期间内存争夺过于激烈。

在硬件性能扩展时,垂直扩展是一个重要方向。通过提升单个节点的计算能力、存储能力和网络能力,可以更高效地满足系统对于性能和可靠性的要求。垂直扩展初期,平台优先考虑升级硬件配置。包括增加物理服务器的 CPU 核心数量、提升单台服务器的内存容量和频率,以及选用更高性能的 NVMe SSD 存储设备。这些升级显著提高了服务器的单机处理能力,使其可以处理更复杂的模型训练任务、存储更大规模的数据,以及快速响应来自用户的请求。在网络层面,通过优化服务器的网络接口卡(NIC)性能和网络带宽,提升单机的数据传输速率,减少任务之间的数据传输延迟。例如,为服务器配置万兆或更高规格的网卡,同时优化网络拓扑结构,保证数据流转的效率。这对于竞赛任务中的实时数据上传与结果返回具有重要意义。

在硬件升级的同时,需考虑硬件利用率问题。硬件性能的提升需要与系统的工作负载相匹配,避免过度配置造成资源浪费。例如,对于具有高并发请求特性的任务,使用性能强大的多线程 CPU 更为合适;而对于需要处理海量数据的任务,高内存和高速存储设备的搭配至关重要。因此,硬件的选择与扩展需要与平台的实际业务特点和负载类型相结合。同时,硬件垂直扩展需要评估投入产出比。单节点硬件性能的极限并非无限可扩展,当性能瓶颈逐渐显现时,投入成本可能呈指数增长,而性能提升却趋于平缓。因此,需要确定一个合理的扩展边界,避免单纯追求硬件性能而忽视了成本效益。同时,垂直扩展需要结合操作系统和软件栈的优化,例如调整系统内核参数、使用高效的调度算法等,以充分发挥硬件性能的潜力。

垂直扩展作为性能提升的手段之一,并非孤立存在。在实际应用中,需要与水平扩展相结合,在平台规模化发展的同时,通过分布式架构和负载均衡技术将压力分散到多个节点上。这样可以在保持性能的同时,提升系统的容错性和可靠性。垂直扩展既是对硬件性能的全面提升,也是对平台架构设计的一次深度优化。通过合理的扩展策略,平台能够在硬件资源的支持下,更高效地满足竞赛任务的需求,同时为未来的发展奠定坚实的基础。

水平扩展集群#

水平扩展是通过增加服务器数量来扩大系统的计算和存储能力。在竞赛平台中,水平扩展的方案主要包括:部署更多的物理或虚拟服务器,将任务分配到多个节点;通过负载均衡器实现任务分发,避免单点瓶颈;以及利用分布式存储和分布式计算框架,提升整体处理能力和数据处理效率。这种方式可以快速增加系统的总容量,适应日益增长的竞赛需求和用户规模。

水平扩展带来的临时优势在于,其能显著提升系统的并发能力和容错性。在高并发的比赛场景下,新增节点可以快速分担压力,保障服务的稳定性。此外,水平扩展可以通过弹性伸缩,根据任务负载的变化动态调整资源投入,从而提高资源利用率,降低运行成本。同时,分布式设计还能提升系统的可用性,即使个别节点出现故障,也不会影响整体服务的正常运行。

遗留问题#

尽管水平和垂直扩展都能在一定程度上缓解系统压力,但它们对资源管理问题的根本解决能力是有限的:

  1. 比赛资源的内存占用:随着比赛任务和用户量的积累,历史数据和模型的数量不断增长,即便硬件性能提升或节点增加,也难以避免存储和内存资源的占用问题。这些资源的长期积累会逐渐侵蚀系统的处理能力。
  2. 程序执行的开销:模型训练、数据预处理等任务的计算复杂度较高,尤其是在并发用户数较多的情况下,系统处理效率会受到显著影响。仅依赖中心集群处理所有任务,容易出现线程疲劳、资源竞争等问题,从而影响整体性能。
  3. IO与CPU任务的竞争:中心集群需要同时处理大量 IO 操作和 CPU 密集型任务,这会导致线程池饱和,任务延迟增加,甚至引发系统瓶颈。而这些问题无法通过简单的硬件扩展或节点增加完全解决,因为它们源自于资源分配与任务调度的基本矛盾。

为此,竞赛平台需要采用 KVM 本地程序设计,将部分计算和 IO 任务下放到虚拟机中。通过这种资源分离的方式,中心集群的负载可以显著降低。虚拟机独立运行程序,同时以低延迟的方式向中心系统回传结果,能够更高效地完成任务分工。这种设计不仅优化了资源利用,还为系统的长期扩展提供了灵活性。

探索新架构#

现状分析#

这些问题的根源在于中心集群架构单一、资源分配不均以及任务调度能力不足。新的架构模式以分层分布式设计为核心,通过边缘集群的独立运行和短连接机制的引入,能够有效缓解中心集群的负载压力。此外,通过任务下放和资源优化,系统可以更高效地处理并发任务,同时降低单点故障风险。这些设计既解决了存储与计算资源的竞争问题,也为平台的可扩展性奠定了基础。

持续增长的内存占用#

随着竞赛任务和用户规模的不断扩大,系统中历史数据和模型的存储需求持续增长。这导致内存资源被大量占用,影响其他实时任务的执行效率。传统架构中,中心集群需要处理所有任务,包括实时任务与历史数据的存储和维护,这种资源竞争逐渐成为性能瓶颈。为了优化资源利用,可以考虑在边缘节点实现历史数据的分层存储,将历史模型或低频访问数据迁移至边缘集群,减轻中心集群的内存压力。同时,通过边缘节点提供分布式缓存和预处理功能,可进一步优化系统性能,缩短用户访问延迟。

程序执行的开销#

模型训练和数据预处理属于高计算复杂度任务,在并发用户增加时,系统容易出现线程资源耗尽的问题。这主要是因为中心集群需要同时协调多个任务的执行,但单一的线程池资源和调度能力有限,容易导致性能下降。解决这一问题需要将计算密集型任务下放至边缘节点,借助其多线程乱序读的灵活性,分散中心集群的调度负担。同时,通过动态调整线程分配策略,结合任务优先级管理,边缘节点可以实现更高的并发性能和资源利用效率。

IO 与 CPU 任务的竞争#

中心集群需要同时处理大量的 IO 密集型任务和 CPU 密集型任务,而两者对资源的需求具有竞争性。这种竞争可能导致线程池饱和、任务执行延迟增加,甚至系统崩溃。例如,中心集群在同时响应大规模用户请求和执行高频模型更新时,容易因 IO 延迟而拖慢整体任务进度。为此,可以通过短连接机制优化中心与边缘集群之间的通信效率,降低 IO 开销。此外,边缘节点可以独立承担部分任务的执行,使中心集群专注于高优先级计算任务和关键数据整合,避免资源争夺导致的性能下降。

提出草案#

新架构旨在缓解中心集群因日益增长的 IO 任务压力所带来的性能瓶颈问题。通过对任务的分层分布式处理,实现中心集群和边缘节点之间的职责分离,提升系统的整体性能和稳定性。为解决这些问题设计了以下的草案:

  1. IO 任务的边缘化处理 将大部分 IO 密集型任务下放至各虚拟机(KVM)中。这些虚拟机将以独立节点的形式运行,负责完成分配的 IO 任务,同时通过独立通信机制处理任务结果。这种设计将减少中心集群的直接 IO 负载,使其更专注于协调和数据整合等核心任务。
  2. 边缘集群的分散化管理 边缘节点以分布式集群形式存在,独立处理任务的接收、执行、结果存储和上报。任务分散化能够提升系统的可扩展性,降低单点故障的风险,并优化资源利用效率。
  3. 多线程乱序读方案的引入 为进一步提升边缘集群的 IO 任务处理效率,采用多线程乱序读方案。每个虚拟机可根据任务的优先级、大小和时序动态调整线程分配策略,从而实现任务的高灵活性与高并发性。
  4. 短连接的通信机制 中心集群与边缘集群之间采用短连接通信协议,避免长连接带来的额外内存占用和线程阻塞问题。通过短连接实现任务下发与结果回传,减少不必要的网络 IO 开销,同时降低异步等待时间,提升通信效率。

预期效果:

  • 中心集群负载优化:显著降低中心集群的 IO 任务处理压力,释放更多资源用于核心计算和协调任务。
  • 边缘节点的高效利用:通过分散化管理和多线程优化,边缘节点能够高效完成任务并快速响应需求变化。
  • 通信性能提升:短连接设计减少了网络阻塞和超时等待问题,实现了更高效的数据交互。
  • 系统整体可扩展性增强:边缘节点的分布式设计为系统后续的扩展和任务种类的增加提供了更高的灵活性和适应性。

如何实现#

为了有效实现 IO 任务的边缘化和结果回调机制,可以通过以下几个步骤逐步构建一个完整的业务实现流程,依托Quarkus等轻量级框架构建边缘服务,与中心集群形成高效的任务调度和处理体系。

  1. 边缘节点服务的部署与功能实现 边缘集群的每个节点将部署一个基于 Quarkus 的轻量级服务。这些服务主要负责以下任务:
    1. 任务订阅与监听: 中心集群通过发布-订阅模式与边缘节点交互。边缘节点在启动时向中心集群注册,表明其可以接受指定类型的 IO 任务。注册信息包括节点 ID、支持的任务类型、当前负载状态等。
    2. IO 任务处理逻辑: 边缘服务接收到中心集群发布的 IO 任务事件后,根据任务内容执行对应的操作。例如,处理文件上传、日志分析、模型数据的读写等。Quarkus 的事件驱动模型能够帮助高效地处理这些异步任务,避免线程阻塞。
    3. 结果封装与回调接口: 任务完成后,边缘服务将结果封装成标准化格式,例如包含任务 ID、执行状态(成功/失败)、处理数据的摘要等。封装后的结果通过短连接接口异步回调至中心集群。
  2. 中心集群的任务调度与回调管理 中心集群的核心任务是协调多个边缘节点的工作,主要包括以下功能:
    1. 任务分发: 中心集群根据业务需求和边缘节点的负载情况,将 IO 任务分发到适合的边缘节点。任务分发采用调度算法,综合考虑节点的任务队列长度、资源可用性和任务优先级等因素,从而实现负载均衡。
    2. 任务队列管理: 为避免任务分发后因边缘节点繁忙而出现任务延迟或丢失,中心集群会为每个任务维护一个状态队列。任务在完成之前会一直处于监控状态,未能按时回调的任务可以被重新调度到其他空闲节点。
    3. 结果接收与处理: 边缘节点通过回调接口提交处理结果时,中心集群接收并更新任务状态。对于成功的任务,中心集群将结果归档或传递给后续的业务处理模块。对于失败的任务,中心集群根据预定义策略决定是否重试或记录日志供后续分析。
  3. 发布-订阅模式的实现细节
    1. 事件发布机制: 中心集群通过消息队列或事件流系统(如Kafka、RabbitMQ)将 IO 任务发布到边缘集群。任务信息中包含事件 ID、任务内容、目标节点等。边缘节点订阅相应的任务类型,并从消息队列中拉取任务。
    2. 边缘节点动态注册: 边缘节点启动时会向中心集群发送注册请求,表明其可用状态。中心集群维护一个动态注册表,实时更新每个节点的健康状态和负载信息,用于任务分发时的决策依据。
  4. 异步回调的实现机制 为了避免中心集群因边缘任务的阻塞等待造成资源浪费,系统采用异步回调机制:
    1. 短连接回调设计: 边缘节点完成任务后,通过 HTTP 短连接调用中心集群的结果接收接口。接口设计遵循幂等性原则,确保即使因网络中断等原因导致多次回调,也不会影响中心集群的任务处理逻辑。
    2. 结果验证与归档: 中心集群接收到回调结果后,对数据完整性和任务状态进行验证。如果验证通过,将结果存入数据库或分布式存储中,并标记任务为已完成。验证失败的回调结果将触发异常处理机制,例如记录日志或通知管理员。
  5. IO 任务的去中心化与协同优化 通过以上机制,系统实现了 IO 任务的去中心化处理。边缘集群负责处理大量的低优先级 IO 任务,释放中心集群的资源,使其能够专注于更高优先级的计算任务。中心与边缘之间的协作通过异步任务分发和结果回调的方式完成,避免资源浪费,同时提升了系统的整体响应速度和处理效率。

这种架构既减少了中心集群的负担,也充分利用了边缘节点的计算能力,实现了IO任务的高效调度和处理。

总结#

新架构的实施显著解决了老架构在性能上的长期不足,同时增强了中心集群与边缘集群之间的任务关联性。通过 IO 任务的边缘化处理以及中心集群的统一调度,不仅优化了系统的资源利用效率,还提高了整体的任务执行能力与灵活性。在后续的架构更新中,我们将持续推进灰度发布与差量更新的策略,以验证新架构的稳定性,及时发现并解决潜在问题,从而进一步巩固系统的可靠性和扩展性。

高并发IO系统的架构演变
https://biu.kim/posts/open/isolated_system_architecture/
Author
Moritz Arena
Published at
2024-03-07