跳转到内容

架构

标签「架构」下的 2 篇文章

软考高级架构师考试后的一个感受

昨天,也就是 2026 年 5 月 23 日,去参加了软考高级系统架构设计师考试。

考完之后最明显的感受是:这类考试真的在越来越快地贴近新的技术趋势。以前提到架构,更多想到的是分层、缓存、消息队列、高并发、数据库、微服务这些传统工程问题;但这次做题时,AI、模型、多模态这些内容已经很自然地出现在题目里了。

这种感觉还挺直接的。

不是那种“AI 作为热点,被强行塞进试卷”的感觉,而是它开始变成架构师应该了解的背景知识之一。

上午选择题做下来,感觉整体还可以。

时间上比较充裕,没有那种一路卡住、最后疯狂赶题的感觉。很多题还是围绕软件工程、架构设计、数据库、网络、安全、项目管理这些基础内容展开,只要平时有积累,大多数题都能比较顺地往下做。

比较有意思的是,题型很快就来到了 AI 和模型相关内容。

印象里有一道和 Transformer 相关的题,也有一道涉及多模态的题。看到这些题的时候,会明显感觉到考试范围已经不只是传统软件架构知识了。

这其实也合理。

现在很多系统已经不只是“业务系统 + 数据库 + 缓存 + 接口”这么简单。越来越多项目会接入大模型能力,可能涉及文本生成、向量检索、多模态理解、智能测试、智能客服、知识库问答等场景。

架构师如果完全不了解这些内容,后面做系统设计时确实会越来越吃力。

案例题对我来说还是有一些难。

选择题更多是知识点识别和判断,案例题则更像是把知识放进一个具体场景里,让你分析系统问题、补全架构设计、选择方案、说明理由。

这个部分很考验表达能力,也考验对架构方法的熟练程度。

有时候不是完全不知道,而是知道一些点,但要在有限时间里组织成比较完整、规范、有条理的答案,并不容易。

这也提醒我,备考不能只停留在“看过概念”。案例题需要练的是:

  • 能不能看懂业务场景。
  • 能不能识别系统中的关键矛盾。
  • 能不能把架构方案和问题对应起来。
  • 能不能用比较规范的语言写出答案。

这和实际做架构也很像。真实工作里,知道某个技术名词没有太大意义,关键还是能不能把它放到合适的系统问题里。

这次考试让我比较在意的一点,是 AI 相关内容的出现频率。

选择题里出现了 Transformer、多模态,论文题里也直接出现了“向量数据库”和“多模态大模型在移动智能测试框架中的应用”。

这说明考试已经不只是把 AI 当成一个新名词,而是在尝试把它放进架构设计语境里。

比如向量数据库不是单独存在的知识点,它背后对应的是:

  • 文本向量化。
  • 相似度检索。
  • RAG 检索增强生成。
  • 知识库问答。
  • 语义搜索。
  • 大模型应用的数据底座。

多模态大模型也不是简单知道“能处理图片和文本”就够了。它进入移动智能测试框架时,可能会涉及:

  • UI 截图理解。
  • 测试步骤生成。
  • 异常页面识别。
  • 测试用例自动补全。
  • 文本、图像、操作行为的联合分析。

这些东西已经开始和软件工程、测试框架、系统架构结合起来了。

论文题:四个方向都挺有代表性

Section titled “论文题:四个方向都挺有代表性”

这次论文题是四选一,题目大概是:

  1. 六边形架构设计。
  2. 向量数据库。
  3. 论高并发系统设计。
  4. 论多模态大模型在移动智能测试框架中的应用。

这四个题其实很有代表性。

六边形架构偏架构思想,重点是领域逻辑和外部依赖的隔离。

高并发系统设计是传统架构高频题,缓存、限流、削峰、异步、分库分表、读写分离、降级熔断这些内容都能展开。

向量数据库和多模态大模型则明显代表新趋势,考察的是架构师能不能把 AI 相关能力纳入系统设计。

如果从稳妥角度看,高并发系统设计可能是很多人比较熟悉的方向。它素材多、案例多,也比较容易结合实际项目经验展开。

但从趋势角度看,向量数据库和多模态大模型这两个题很值得重视。

它们释放了一个信号:以后软考高级架构师可能会越来越多地考察 AI 时代下的软件架构能力。

这次考完,最大的感受不是某一道题难不难,而是知识体系真的需要更新。

传统架构能力还是基础。数据库、缓存、消息队列、微服务、高并发、安全、可用性、可扩展性,这些东西不会过时。

但只靠这些已经不够了。

现在还要补上大模型相关的工程知识:

  • Transformer 的基本概念。
  • 向量数据库和语义检索。
  • RAG 应用架构。
  • 多模态模型的输入输出方式。
  • AI 能力如何接入现有业务系统。
  • 模型服务的成本、延迟、稳定性和安全边界。

这些内容不一定都要学到算法研究层面,但作为架构师,至少要知道它们能做什么、不能做什么、适合放在系统里的哪个位置、会带来哪些工程风险。

这次软考高级架构师考试给我的一个提醒是:

架构师的知识边界正在被 AI 拉宽。

选择题里出现 Transformer 和多模态,论文题里出现向量数据库和多模态大模型,这些都说明 AI 已经逐渐进入软件架构的主干知识里。

对我来说,选择题感觉还可以,案例题仍然需要继续练。更重要的是,后面复习和学习时,不能只看传统架构内容,也要把 AI 工程化、大模型应用架构、向量检索和多模态场景补起来。

考试只是一个节点。

真正值得记录的,是它让我看到技术趋势已经走到试卷上了。

大规模无状态爬虫系统设计

这篇文章记录的是一套大规模无状态爬虫系统的设计。

先说明一下参与边界:这套系统不是我一个人独立设计完成的。我主要负责爬虫端的核心设计和实现,另一位同事是项目主要负责人,他有十余年的架构设计经验,整体系统设计、调度中心以及很多关键取舍都由他主导。我在这个系统里更多是站在爬虫端视角,参与了一套大规模无状态爬虫体系的落地。

也正因为那时自己还是初入职场,所以这套设计对我的意义不只是“写了一个爬虫”,而是第一次比较完整地看到:爬虫在工程系统里不应该只是脚本,它可以是一个被调度、被扩容、被监控、可替换的采集节点。

本文只讨论在授权和合规范围内的数据采集系统设计,不涉及绕过站点安全机制或采集敏感数据。

在做这个项目之前,Scrapy 是很自然会被想到的方案。

它有成熟的爬虫生命周期、调度器、下载器、中间件、管道、去重、状态管理等能力。对于中小规模、结构清晰、业务变化不频繁的采集任务来说,Scrapy 确实是一套完整方案。

但这套系统面对的问题不太一样。

我们更关注的是大规模任务下的采集吞吐、任务调度、账号分配、异常处理和快速扩容。Scrapy 自带的体系虽然完整,但学习成本较高,入手较慢,架构也相对复杂。尤其当系统需要把任务状态、账号状态、异常流转、代理分配、补偿处理这些能力统一放到一个调度中心管理时,爬虫本身再保留太多状态,反而会让边界变得不清楚。

所以最后的方向是:不沿用 Scrapy 的架构模式,而是结合现有高并发框架,设计一套更轻、更快、更容易水平扩展的无状态爬虫系统。

爬虫核心只负责一件事:拿到任务后尽快完成数据抓取,包括必要的增量更新,然后把结果交给后续链路。

按当时的架构草图抽象后,整体链路大概是这样:

大规模无状态爬虫系统架构图
任务、账号、代理由调度中心统一下发;爬虫节点保持无状态,采集结果进入 Kafka、Flink、ES 数据链路。

在这个体系里,Java 服务承担调度中心的角色。它负责任务协调、账号分配、账号状态管理、异常状态流转、代理下发等能力。

爬虫端则被刻意设计得很薄。

爬虫启动后向调度中心领取任务。调度中心在下发任务时,会同时给出这次采集所需的账号和代理。爬虫拿到这些一次性上下文后开始采集,采集完成后把数据写入 Kafka,并向调度中心汇报任务结果和心跳状态。

这里的“一次性”不是指账号用一次就丢弃,而是指一次采集任务内绑定一次任务、账号和代理。任务结束后,账号会根据结果重新回到有效账号池,或者进入异常账号池,等待专门的登录模块重新处理。

我觉得这套系统里最关键的设计,就是把爬虫做成无状态。

传统爬虫经常会在自己内部维护很多信息:当前任务跑到哪一步、账号是否可用、代理是否失效、失败后要不要重试、异常应该怎么处理、下次从哪里继续等。

这些能力当然有价值,但如果所有爬虫节点都各自维护状态,系统规模一大,就会出现几个问题:

  • 单个爬虫节点变重,扩容和迁移成本变高。
  • 账号、代理、任务状态分散在各处,难以统一判断。
  • 某个节点异常退出后,恢复逻辑复杂。
  • 错误处理混在采集逻辑里,爬虫代码越来越难维护。

无状态的思路是反过来的:爬虫只负责执行当前任务,不负责长期持有状态。

它不决定一个账号后续应该怎么处理,也不决定一个异常任务最终怎么补偿。它只把采集过程中的结果、错误和心跳上报给调度中心,由调度中心再调度给对应的处理模块。

这样做以后,爬虫端会变得非常轻。

如果某个爬虫节点挂了,系统只需要感知它心跳消失,再把未完成任务重新调度出去。爬虫本身不需要承担复杂恢复逻辑。对于我当时负责的爬虫端来说,这个设计最大的好处就是:代码目标非常明确,采集就是采集,错误就是上报。

这套系统里,爬虫单次采集任务大约 15 秒左右就可以完成。

它能快起来,原因不只是“并发写得高”,更重要的是系统边界清楚。

调度中心已经提前准备好了任务、账号和代理,爬虫不需要在执行过程中再做大量决策。拿到任务后,爬虫可以直接进入采集流程。它只处理当前任务所需的请求、解析、增量判断和结果投递。

采集结果进入 Kafka 后,后面的清洗、聚合、存储交给 Flink 和 ES 链路。爬虫不在本地做过多处理,也不会把数据链路和采集链路耦合在一起。

从工程上看,这其实是在减少爬虫节点的职责。

节点职责越少,单次任务越短,失败成本也越低。即使某个任务失败,也可以快速上报并进入调度中心的异常处理流程,而不是让爬虫自己在本地反复纠缠。

爬虫选择 Docker 部署,是因为这个系统天然需要横向扩容。

如果爬虫直接跑在固定机器上,扩容会比较麻烦。新机器环境要配置,依赖要安装,版本要对齐,启动方式也容易不一致。Docker 把运行环境打包后,爬虫就可以在任意一台机器上快速启动。

这带来了两个非常直接的好处。

第一,可以一键扩容。

当采集任务变多,或者需要在短时间内提高吞吐时,只需要增加爬虫容器数量。因为爬虫是无状态的,新启动的容器不需要同步复杂上下文,只要能连上调度中心,就可以开始领取任务。

第二,可以按数据采集情况动态调整数量。

任务高峰期增加爬虫节点,任务低谷期减少节点。爬虫节点本身不保存长期状态,所以扩容和缩容都比较自然。

这也是无状态设计和容器化部署非常契合的地方:一个节点随时可以来,也随时可以走,系统的长期状态不依赖它。

从图上看,可能会有一个疑问:代理池去哪了?

实际设计里,代理也由调度中心负责。

爬虫在领取任务时,调度中心会把任务、账号、代理一起下发。对于爬虫来说,它不需要自己去代理池里挑选代理,也不需要判断某个代理是否还应该继续使用。它只需要使用调度中心给出的代理完成当前任务,并把结果反馈回去。

这样设计的好处是统一。

任务、账号、代理在一次采集里是绑定关系。如果采集失败,调度中心可以结合错误类型判断问题出在哪里:可能是任务本身异常,可能是账号失效,也可能是代理不可用。爬虫端只提供事实,不做最终裁判。

这让异常处理有了更清晰的入口。

账号管理是这个系统里非常重要的一部分。

有效账号池保存当前可用账号。调度中心给爬虫下发任务时,会从有效账号池里分配账号。任务完成后,如果账号表现正常,就重新回到有效账号池,等待后续继续使用。

如果采集过程中发现账号异常,爬虫不会自己尝试修复账号,而是把异常上报给调度中心。调度中心再把账号放入异常账号池,由账号登录模块或专门处理模块去恢复。

恢复成功后,账号重新进入有效账号池;恢复失败,则继续留在异常状态,等待后续处理或下线。

这套流转看起来绕了一步,但它让职责非常清楚:

  • 爬虫负责发现和上报异常。
  • 调度中心负责状态流转和资源分配。
  • 账号登录模块负责账号恢复。
  • 有效账号池只保留可用于任务分配的账号。

当系统规模变大时,这种职责拆分会比“爬虫自己判断一切”更稳。

爬虫采集到的数据不会直接写入最终存储,而是先进入 Kafka。

Kafka 在这里承担缓冲和解耦作用。爬虫只需要稳定地把采集结果投递出去,不需要关心后续清洗、转换和索引写入的具体细节。

Flink 负责消费 Kafka 中的数据,做实时清洗、转换、去重或补充处理。处理后的数据再写入 ES,供后续检索和查询使用。

这条链路的好处是采集和处理分离。

爬虫节点只追求采集效率,数据处理链路则可以按自己的节奏扩展。如果后续清洗逻辑变复杂,也不会直接拖慢爬虫侧的执行。

这套设计对我最大的影响,是让我第一次真正理解“少做一点”有时候是更好的工程设计。

刚开始做爬虫时,很容易觉得爬虫应该什么都管:任务、状态、账号、代理、重试、异常、存储,最好都封装在一个完整框架里。但在大规模系统里,爬虫越重,越容易变成难以扩展的节点。

这套系统反而让我看到另一种思路:

爬虫不需要成为系统中心。它可以只是一个高性能、可替换、可扩容的执行单元。真正的状态和调度逻辑,应该放到更适合统一管理的位置。

对当时初入职场的我来说,这个认知很重要。

我开始意识到,架构设计不是把所有能力都堆进一个模块里,而是决定每个模块应该知道什么、不应该知道什么。一个模块越清楚自己不负责什么,边界往往越稳定。

回头看,这套无状态爬虫体系最让我印象深刻的地方,就是它把复杂性从爬虫端拿走了。

爬虫只领取任务、执行采集、上报结果;调度中心统一管理任务、账号、代理和异常;数据进入 Kafka、Flink、ES 组成的后续链路。每一层都有自己的职责,每一层也都可以独立扩展。

这比单纯写一个“能跑的爬虫”要更接近真正的工程系统。