Backstage 后端系统构建指南:从最小后端到多后端拆分与启动容错配置

发布时间:2026/9/10 2:56:15

Backstage 后端系统构建指南:从最小后端到多后端拆分与启动容错配置 Backstage 后端系统构建指南从最小后端到多后端拆分与启动容错配置【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage本文以 Backstage 官方文档《Building Backends》为核心系统讲解如何使用新后端系统New Backend System创建、装配与定制自己的 Backstage 后端包括createBackend的轻量初始化、插件/模块/服务的装配方式、通过配置与服务工厂完成定制、将单体后端拆分为多套独立部署以及用backend.startup配置控制插件启动失败时的容错行为。读完本文你将掌握一套可复制、可运行的后端搭建与运维方案并能结合仓库源码理解其底层实现。整体概览一个最小后端由什么构成Backstage 的后端本质上是一个轻量级的 Node.js 包只需要一个带package.json的目录和一个src/index.ts入口文件不考虑周围的工具链与文档的话仅此而已。这个包通常放在 Backstage monorepo 的packages/backend目录下但位置完全由你决定。任何通过backstage/create-app创建的项目都会自带这样一个后端包因此绝大多数情况下你不需要从零手写它。当你用backstage/create-app创建新项目时得到的后端src/index.ts大致长这样import { createBackend } from backstage/backend-defaults; // 以下示例中省略此行 const backend createBackend(); backend.add(import(backstage/plugin-app-backend)); backend.add(import(backstage/plugin-catalog-backend)); backend.add(import(backstage/plugin-scaffolder-backend)); backend.add( import(backstage/plugin-catalog-backend-module-scaffolder-entity-model), ); backend.start();初始模板里还会有更多插件和模块但整体结构是一致的。这段代码做的事情可以拆成三步调用createBackend创建后端实例。它负责把喂给后端的各种特性features装配在一起并为插件提供所有核心服务的默认实现。通过backend.add(...)安装特性。特性分三类**插件plugins**是独立的功能单元**模块modules**用于增强某个已有插件或模块**服务services**则用于更深层的定制可以覆盖默认行为。需要注意每个模块只能瞄准一个插件而且该插件必须存在于同一个后端中。调用backend.start()启动后端。此时后端才开始真正做初始化工作——创建实例本身不会执行任何实际操作所有工作都被推迟到start()调用时进行。关于createBackend的底层实现可以到 packages/backend-defaults/src/CreateBackend.ts 中查看它内部调用createSpecializedBackend并传入一长串defaultServiceFactoriesauditor、auth、cache、database、discovery、logger、scheduler 等约 27 个服务工厂。也就是说createBackend是开箱即用batteries included的高层入口而createSpecializedBackend是更底层、不预装任何服务的原始入口。更详细的说明可参考后端实例架构文档。如果你已经有一个尚未迁移到新后端系统的旧后端可参考迁移指南其中讲解了如何把旧式的makeCreateEnvplugins/*.ts结构逐步收敛为上述极简形态以及如何用legacyPlugin桥接旧式插件。仓库实例一个真实后端的装配清单理论之外本仓库自带的示例后端 packages/backend/src/index.ts 就是一份极佳的装配清单参考。它在createBackend()之后通过backend.add(...)安装了 Auth、App、Catalog、Events、Kubernetes、Permissions、Proxy、Scaffolder、Search、TechDocs、Signals、Notifications、MCP Actions、User Settings 等大量后端插件及其模块。值得特别注意的是其中使用的一个进阶特性——特性加载器Feature Loaderimport { coreServices, createBackendFeatureLoader, } from backstage/backend-plugin-api; const searchLoader createBackendFeatureLoader({ deps: { config: coreServices.rootConfig, }, *loader({ config }) { yield import(backstage/plugin-search-backend); yield import(backstage/plugin-search-backend-module-catalog); yield import(backstage/plugin-search-backend-module-explore); yield import(backstage/plugin-search-backend-module-techdocs); if (config.has(search.elasticsearch)) { yield import(backstage/plugin-search-backend-module-elasticsearch); } }, }); backend.add(searchLoader);它用生成器函数按需批量加载一组特性并且可以在deps中声明对 root 作用域服务的依赖——这里就通过coreServices.rootConfig读取配置当检测到search.elasticsearch配置时才额外加载 Elasticsearch 搜索模块。这展示了配置驱动装配的思路后端可以依据静态配置动态决定要安装哪些功能。配套的 packages/backend/package.json 则给出了后端包的典型定义role: backend、main: dist/index.cjs.js、构建/启动脚本backstage-cli package build、backstage-cli package start以及大量backstage/plugin-*-backend与backstage/plugin-*-backend-module-*依赖。这说明一个后端包的依赖天然分为插件本体与插件模块两类二者都在index.ts中通过backend.add装配。定制方式一静态配置Configuration除安装现成插件与模块外后端定制有几种途径。最易上手的是静态配置详细写法可参考配置编写文档。后端本身的许多行为、以及大量插件/模块的行为都可以通过配置调整具体可配置项需要查阅各插件/模块自己的文档同时建议查阅核心服务文档其中也覆盖了核心服务的配置方法。典型配置文件如仓库根目录的 app-config.yaml后端在启动时会读取并下发到各插件。定制方式二覆盖核心服务Services服务是另一个重要的定制切入点它允许对后端做更深、更广的定制。服务与前端系统中的 Utility APIs 类似都是通过依赖注入把通用能力提供给插件和模块更深入的解释见服务架构文档。所有后端都必须安装一组核心服务负责日志、数据库访问、HTTP 服务等基础能力。好消息是当你使用backstage/backend-defaults提供的createBackend时这组服务已全部默认安装。这些服务全部可以被你自己的实现替换。最省事的替换方式是沿用现有实现、只加选项——许多核心服务支持这种用法并非全部因为有些服务没有有意义的选项。例如想要定制核心配置服务以启用远程配置加载可以这样写import { rootConfigServiceFactory } from backstage/backend-app-api; const backend createBackend(); backend.add( rootConfigServiceFactory({ remote: { reloadIntervalSeconds: 60 }, }), );这样配置目标中就可以传入 URL后端会每 60 秒轮询一次该 URL 获取配置变更。这里有一个例外框架内置的PluginMetadataService插件元数据服务由框架直接提供无法被覆盖。它是插件作用域服务向服务实例提供当前正在为哪个插件创建实例的信息是插件级定制的基石——例如默认日志服务正是通过它给每条日志打上插件 ID 标签。定制方式三完全自定义服务工厂Custom Service Implementations覆盖服务时你并不局限于现有实现完全可以提供自己的服务工厂service factory从而用完全自定义的实现全局覆盖某个服务或在现有实现基础上叠加额外逻辑。覆盖服务的写法与上文相同放进services选项但这次需要用createServiceFactory创建工厂。例如用自定义实现替换默认的LoggerServiceconst backend createBackend(); backend.add( createServiceFactory({ service: coreServices.logger, deps: { rootLogger: coreServices.rootLogger, plugin: coreServices.pluginMetadata, config: coreServices.rootConfig, }, factory({ rootLogger, plugin, config }) { const labels readCustomLogLabelsForPlugin(config, plugin); // 自定义逻辑 return rootLogger.child(labels); }, }), );这个例子背后涉及两个容易混淆的服务LoggerServicecoreServices.logger插件作用域服务负责为每个插件创建带插件专属上下文的日志实例默认实现会给日志附加一个包含插件 ID 的plugin标签。RootLoggerServicecoreServices.rootLoggerroot 作用域服务是真正的日志实现本体。上面的自定义实现就是从配置中读出额外的标签并叠加到rootLogger的子 logger 上。这恰好引出**服务作用域service scope**的概念服务只有两种作用域——plugin默认和root。插件作用域服务会为每个依赖它的插件各创建一个实例实现插件间的一定隔离root 作用域服务则在所有插件与服务间共享单个实例且无论是否有插件依赖它都会被初始化适合承载与具体插件无关的后端级关注点。root 作用域服务只能依赖其他 root 作用域服务而插件作用域服务可以依赖两者。从源码结构看这类成对服务rootLogger/logger、rootConfig/config等的划分正是为了既让 root 服务也能访问日志/配置又鼓励插件优先使用插件作用域版本。完整的服务接口、引用与工厂规范可阅读服务架构文档。拆分为多个后端Split Into Multiple Backends更高阶的部署形态是把后端插件拆分到多个后端部署中。拆分的好处独立扩缩容、性能与安全隔离等在部署扩展文档与威胁模型中有详细说明这里聚焦怎么拆。创建独立后端需要额外新建一个后端包它会与现有后端分别构建、分别部署。目前yarn new还没有提供后端模板最快的做法是复制现有后端包再修改。命名取决于你的拆分方式这里以简单后缀为例目录结构可能变成packages/ backend-a/ src/ index.ts package.json - name: backend-a backend-b/ src/ index.ts package.json - name: backend-b然后裁剪各自的src/index.ts只保留想归属该后端的插件与模块。例如要把 Scaffolder 插件拆出去backend-a可能是const backend createBackend(); backend.add(import(backstage/plugin-app-backend)); backend.add(import(backstage/plugin-catalog-backend)); backend.add( import(backstage/plugin-catalog-backend-module-scaffolder-entity-model), ); backend.start();而backend-b则是const backend createBackend(); backend.add(import(backstage/plugin-scaffolder-backend)); backend.start();注意backend-b的package.json也要同步清理依赖移除不再需要的插件包。把后端拆成两套独立部署后剩下的关键问题是让它们能互相通信——这也是最繁琐的部分因为 Backstage 目前没有现成的开箱即用方案。你需要为两个后端手动配置自定义的DiscoveryService实现让它们能返回彼此正确的 URL在前端提供自定义的DiscoveryApi实现除非你通过一个负责路由的反向代理把两个后端统一暴露出来。多后端部署架构示例下面是一个更复杂的示例三套后端部署每套承载各自的插件与模块前端与各后端实例之间有一个反向代理负责把流量路由到正确的实例。作为加固选项该代理也可以配置为带认证的反向代理拒绝未认证用户访问后端实例。在这个示例中Catalog 与 Search 插件被拆到一套后端部署代理把/api/catalog/和/api/search/的流量全部路由到该实例。通过这种分离这两个插件可以独立扩缩容与部署并且在性能与安全上相互隔离同理TechDocs 与 Scaffolder 也被单独拆出其余流量则路由到承载 App、Auth、Proxy 插件的实例。图中还可以看到每个插件拥有自己逻辑上的数据库但通常共享同一个数据库管理系统DBMS实例——这当然不是硬性要求你可以按需进一步拆分或合并数据库。启动配置控制插件启动失败时的行为backend.startup配置块用于控制后端在插件或插件模块启动失败时的行为。默认情况下任何插件或模块的启动失败都是致命错误会导致后端中止启动。该配置允许你把特定插件/模块设为可选或翻转全局默认值让所有插件/模块默认可选、只有显式要求的才必须成功。插件启动失败处理默认情况下插件启动失败会让后端中止。你可以按插件用onPluginBootFailure: continue改变这一行为backend: startup: plugins: catalog: onPluginBootFailure: continue配置后如果catalog插件在启动时崩溃后端会记录错误并继续启动其余插件。这在排查与数据相关的问题时非常有用——可以让一个会崩溃的插件保持安装状态同时让后端其余部分继续对外服务。插件模块启动失败处理对单个插件模块可以用onPluginModuleBootFailure做同样的控制backend: startup: plugins: catalog: modules: github: # moduleId即 createBackendModule({ moduleId: ... }) 中声明的 ID onPluginModuleBootFailure: continue这允许github目录模块失败而不拖垮catalog插件或后端其余部分。注意modules下的键是createBackendModule中声明的moduleId而不是插件名或实体提供者entity provider名。设置全局默认值与其逐个把插件设为continue不如翻转全局默认值让所有插件失败时都继续只要求特定插件必须成功backend: startup: default: onPluginBootFailure: continue plugins: auth: onPluginBootFailure: abort这个示例中除auth被显式设为abort必须成功启动外其余插件全部可选。default机制对模块同样生效通过onPluginModuleBootFailurebackend: startup: default: onPluginModuleBootFailure: continue plugins: catalog: modules: github: onPluginModuleBootFailure: abort完整配置参考backend: startup: # 未按插件/模块单独指定时应用的全局默认值 default: # 默认值为 abort。设为 continue 可使所有插件默认可选。 onPluginBootFailure: abort # 或 continue # 默认值为 abort。设为 continue 可使所有插件模块默认可选。 onPluginModuleBootFailure: abort # 或 continue # 按插件、按模块的覆盖配置 plugins: pluginId: # 覆盖该插件默认的启动失败行为。 onPluginBootFailure: abort # 或 continue modules: moduleId: # 覆盖该插件模块默认的启动失败行为。 onPluginModuleBootFailure: abort # 或 continue这一配置的底层解析逻辑可以在 packages/backend-app-api/src/wiring/createAllowBootFailurePredicate.ts 中看到它启动时一次性读取backend.startup.default.onPluginBootFailure、backend.startup.default.onPluginModuleBootFailure的默认值再读取backend.startup.plugins下按插件、按模块的覆盖项最后返回一个(pluginId, moduleId?) boolean的谓词函数——返回true表示允许该插件/模块启动失败即配置为continue否则按abort处理。这也印证了配置键的取值仅支持abort与continue两种且模块级配置一定嵌套在对应插件之下。值得一提的是Backend.start()返回一个BackendStartupResult包含所有插件与模块详细的成功/失败状态和耗时信息启动失败时会抛出BackendStartupError其中携带完整的启动结果便于诊断究竟是哪个插件或模块失败。这对构建额外的监控或调试工具很有价值详见后端实例架构文档。小结与延伸阅读搭建一个 Backstage 后端可以概括为三步createBackend()创建实例 →backend.add(...)装配插件/模块/服务工厂 →backend.start()启动。在此基础上你可以通过静态配置、给现有服务工厂传选项、或编写完全自定义的服务工厂三种粒度进行定制当单体后端不再满足部署需求时可以按插件拆分出多套独立后端并用自定义DiscoveryService/反向代理打通互访最后用backend.startup配置为启动阶段引入容错能力。继续深入可以参考仓库内以下资料后端实例Backend架构文档createBackend/createSpecializedBackend的关系、BackendStartupResult与BackendStartupError服务Services架构文档服务引用、服务工厂、作用域、Multiton、默认工厂等完整机制核心服务索引Auth、Cache、Database、Discovery、Logger、Scheduler 等全部核心服务的文档入口后端迁移指南旧后端到新后端系统的完整迁移步骤示例后端装配清单 与 示例后端包定义真实项目的组装与依赖结构createBackend 实现defaultServiceFactories完整列表启动失败谓词实现backend.startup配置的解析与判定逻辑【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/10 2:56:15

微环光频梳仿真实践:基于MATLAB的LLE方程求解与参数分析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/10 2:51:15

压力传感器最小二乘温度补偿:零位与灵敏度拟合实战

简介:面向压力传感器开发、测试与工业现场应用人员,这份资源提供基于最小二乘法的温度补偿算法实现,用来消除环境温度变化引起的传感器输出漂移,确保不同温度下测量数据的一致性。压缩包内仅含一个MATLAB脚本文件(m格式…

2026/9/10 7:06:40

AI生成代码时代,能力断层如何弥补?Code to Learn训练闭环实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/10 7:06:40

RK3576开发板RTC完整配置指南:从内核到Android时区避坑

前阵子调一块RK3576开发板,功能问题都处理完了,结果客户那边反馈说设备重启后时间总是回到出厂值,日志时间戳全乱了。查了一圈,发现是RTC这块没配置干净。RK3576这颗芯片在AIoT和边缘计算项目里用得越来越多,配Linux或…

2026/9/10 7:06:40

AI文本太假怎么办?humanizer人性化改写实操指南

早上打开后台,看到一位读者的留言:“能不能出一篇关于 humanizer 的内容?我写文章基本都是 AI 帮我起草,但总觉得发出去的效果不对,说不出来哪里假。”这条留言让我挺有感触。做内容这行几年,我自己也被“A…

2026/9/10 7:01:40

T507平台适配长江存储EC150的工程级兼容性实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/9 13:11:35

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/8 7:15:15

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/9 16:31:09

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/10 0:00:55

目录对比去重实战:用哈希算法精准清理重复文件

我电脑里现在还有一块换了三次机的“数据墓地”硬盘,里面存着2016年以前所有旧笔记本的完整备份。平时不觉得有什么,直到前阵子想把它整理归档,发现同一个安装包、同一批照片、同一份论文草稿,在几个不同的备份目录里反复出现。更…

2026/9/10 0:00:55

Leaflet离线地图完整Demo合集:内网部署与坐标纠偏实战

简介:这是一份面向Web GIS开发者的LeafLet离线地图示例合集,帮助开发者快速掌握离线地图从搭建到交互的完整流程。压缩包共723个文件,大小14.06MB,以319个js脚本、175个html页面和29个css样式文件为主体,配合png/svg图…

2026/9/10 0:00:55

MATLAB读取Rinex 3.02观测文件:多系统GNSS数据解析实战

简介:基于MATLAB开发的Rinex3.02版观测文件(o文件)读取代码包,面向卫星定位导航方向的学习者与研究人员,用于解决新版观测文件的数据解析、历元提取与时间转换问题。压缩包共4个文件,包含两个m脚本、一个19…

2026/9/7 16:23:03

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/7 22:46:00

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/9 10:21:54

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码