云原生后端【免费下载链接】fissionFast and Simple Serverless Functions for Kubernetes项目地址https://gitcode.com/gh_mirrors/fi/fission点击查看免费下载导读本指南以 Fission 仓库中的架构文档 RFC-0004: Reconciler Consolidation Dependency-Driven Watches 为主体讲解 Fission 控制平面如何将 executor执行器进程内九个 controller-runtime reconciler 合并为少数几个「以 Function 为中心、通过.Watches()感知依赖对象」的控制器并顺带退役冗余 informer 工厂、引入可选 finalizer 实现跨命名空间可靠回收。读完本文你将理解 Fission 控制平面当前的控制器拓扑、跨命名空间工作负载Deployment/Service/HPA 与 Function CR 不在同一命名空间带来的约束以及如何通过.Watches() 标签映射实现自愈、如何用 finalizer 保证删除清理并掌握最终落地形态与实测资源收益。1. 背景一次 1:1 迁移留下的结构性重复Fission 的控制平面已于 2026-06-01 全面迁移到 controller-runtime reconciler详见 RFC-0003 CRD 现代化。但那次迁移是一次「忠实 1:1 移植」原先每个 informer 事件处理器都变成了一个独立的 reconciler全部通过 pkg/controller/builder.go 里的共享注册助手接入 Manager。而该助手目前只会调用.For(obj).WithPredicates(...).Complete(r)——也就是说迁移后的代码里没有.Owns()、没有.Watches()、没有 OwnerReferences/SetControllerReference、没有 finalizer非生成代码中。这套移植能跑但它留下了 controller-runtime 模型本来就要消除的结构性重复。1.1 当前拓扑9 个进程、约 19 个 reconciler每个 Helm pod 运行fission-bundle并携带一个子系统标志见 cmd/fission-bundle/main.go当前控制平面拓扑如下进程Reconciler.For根对象是否主选举routerhttpTriggerReconcilerHTTPTrigger、functionReconcilerFunction否executor9 个详见下节可选kubewatcherKubernetesWatchTrigger可选timerTimeTrigger可选buildermgrEnvironment、Package可选mqtriggerMessageQueueTrigger可选mqt_kedaMessageQueueTrigger → KEDA ScaledObject/TriggerAuth/Deployment可选canaryconfigCanaryConfig可选loggerPodDaemonSet否重复最严重的是executor 进程它注册了九个 reconciler分为四类三个functionReconcilerpoolmgr、newdeploy、container 各一个全部以fv1.Function为根见 pkg/executor/executortype/poolmgr/reconciler.go、pkg/executor/executortype/newdeploy/reconciler.go、pkg/executor/executortype/container/reconciler.go。两个environmentReconcilerpoolmgr 的 pool 同步 newdeploy 的运行时镜像传播都以fv1.Environment为根见 pkg/executor/envreconciler/reconciler.go。两个 cms reconcilerConfigMap、Secret唯一职责是调用RefreshFuncPods回收挂载了变更对象的函数 Pod见 pkg/executor/cms/reconciler.go。两个 poolmgr 生命周期 reconciler以ReplicaSet和Pod为根温池内部机制。1.2 为什么 controller-runtime 也没能帮上忙controller-runtime 在一个 Manager 内每个 GVK 只共享一个 informer所以三个 Function reconciler 并不会让 Function 缓存翻三倍。真正被放大的是 informer 下游的一切每个 Function 事件被扇出到三个 workqueue被三个谓词分别评估被三个 reconcile 协程池处理各自维护一份lastReconciled/lastSeen的sync.Map而其中两个后端对不属于自己 executor type 的 Function 会提前返回依据Spec.InvokeStrategy.ExecutionStrategy.ExecutorType见 pkg/apis/core/v1/types.go也就是说三分之二的处理是纯开销。两个 Environment reconciler 的重复方式相同。此外 executor 还有第二套冗余缓存层newdeploy 和 container 仍然各自构建独立的 client-goSharedInformerFactory来维护 Deployment/Service lister见 pkg/utils/informer.go 的GetInformerFactoryByExecutor——它们与 Manager 缓存里已经持有的相同对象并存运行。1.3 这为什么重要计算开销冗余的事件扇出、谓词评估、reconcile 协程随 Function/Environment 变更规模线性增长却毫无收益。内存开销独立的 Deployment/Service informer 工厂等于在同一进程里又装了一套完整的 informer 基础设施。正确性缺口没有对受管 Deployment/Service/HPA 的.Watches()漂移比如有人删掉了某个函数的 Deployment会一直静默直到下一次 spec 变更或周期性 reaper 碰巧运行——executor 不会自愈。清理脆弱性删除回收依赖 NotFound 路径 内存中的lastReconciled缓存 标签 reaper如果 executor 错过了删除事件就无法保证跨命名空间工作负载被回收。2. 目标与非目标RFC-0004 的目标在不产生行为回归的前提下把 executor 的 reconciler 从九个减到三个用.Watches()让 executor 响应真实的依赖图而不是靠分散的 reconciler为 executor 管理的 Deployment/Service/HPA 增加自愈能力移除冗余的独立 Deployment/Service informer 工厂通过 finalizer 提供可靠的、可选的跨命名空间回收并保留一个强删逃生通道。非目标明确不做的事不合并跨进程timer、kubewatcher、canaryconfig 等单 reconciler 的 pod 保持独立进程——合并会改变 Helm 拓扑、leader 选举租约、RBAC 和故障域明确不在本次范围。不用.Owns()做垃圾回收见下文命名空间约束owner-reference GC 无法跨命名空间对 Fission 的工作负载放置是错误工具。不做任何 CRD schema、CLI 或 Helm 值变更这是纯粹的控制平面内部结构调整。3. 决定性约束工作负载可以和 CR 不在同一命名空间NamespaceResolver.GetFunctionNSpkg/utils/namespace.go会把default命名空间里的 Function CR 映射到配置的FunctionNamespace例如fission-function来放置其 Deployment/Service/HPA。因此一个 Function 的受管工作负载完全可能位于与 Function 对象不同的命名空间。Kubernetes 的 owner reference——以及 controller-runtime 的.Owns()和内建 GC——不能跨命名空间命名空间对象只能被同命名空间的对象拥有。这从根上排除了用.Owns()处理 Function→Deployment 的通用方案。正确的工具是.Watches() 标签→属主映射用于漂移/自愈与命名空间无关finalizer用于保证回收与命名空间无关。这个约束是整个 RFC 设计的分水岭后续 A–E 五节设计都由它驱动。4. 设计五个动作4.1 A. 把三个 Function reconciler 合并为一个依赖驱动用单个 executor 级 reconciler 取代三个按类型划分的functionReconcilerbuilder.ControllerManagedBy(mgr). For(fv1.Function{}). // one workqueue, one predicate Watches(fv1.Environment{}, envToFunctions). // re-roll funcs on runtime-image change Watches(corev1.ConfigMap{}, cmToFunctions, contentChanged). // recycle pods on referenced CM change Watches(corev1.Secret{}, secretToFunctions, contentChanged). Watches(appsv1.Deployment{}, deployToFunction, byFnLabel). // self-heal drift/deletion Watches(corev1.Service{}, svcToFunction, byFnLabel). Watches(autoscalingv2.HorizontalPodAutoscaler{}, hpaToFunction, byFnLabel). Complete(r)要点reconcile 主体读取f.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType默认poolmgr并分发给现有的executortype.ExecutorType后端接口定义见 pkg/executor/executortype/executortype.go。各类型的 create/update/delete 逻辑原地不动只是路由上移一层。executor 类型切换变得更简单也更正确一个 reconciler 同时持有旧类型来自lastReconciled和新类型可以在单次 reconcile 内拆除旧后端的对象并构建新的。而今天三个 reconciler 必须各自独立检测「这个 Function 不再归我管」再自行清理。controller-runtime 按NamespacedName串行化 reconcile所以单一lastReconciledsync.Map与它所替代的三个一样安全。这要求 pkg/controller/builder.go 里的助手增加一个接受.Watches()源的变体当前Register*系列只支持.For() 谓词。4.2 B. 把 Environment 与 cms reconciler 折入 Function reconciler新的.Watches()边吸收了九个 reconciler 中的四个Watches(fv1.Environment{}, envToFunctions)取代两个environmentReconciler。envToFunctions列出使用该变更 Environment 的函数并对其入队reconcile 路径随后完成原来 newdeploy env reconciler 做的事运行时镜像变更时重新滚动 Deployment。poolmgr pool 的周期性重新同步则保留为 Function/pool 路径上的RequeueAfter。Watches(corev1.ConfigMap{}, ...)与Watches(corev1.Secret{}, ...)配合现有的contentChanged谓词取代两个 cms reconciler。映射列出挂载该对象的函数并入队reconcile 路径调用现有的refreshPods/RefreshFuncPods。4.3 C. 对受管对象使用.Watches()实现自愈deployToFunction/svcToFunction/hpaToFunction使用现有的部署标签getDeployLabels见 pkg/executor/executortype/newdeploy/newdeploymgr.go 和 pkg/executor/executortype/container/containermgr.go把受管对象映射回其属主 Function。这在.Owns()无法生效的跨命名空间场景下可用并为 executor 补上了缺失的漂移修正删除某个函数的 Deployment 会重新入队该 Function后者会重建它。有了它周期性对象 reaper 降级为兜底手段而不是主要的修复路径。实现注意newdeploy 与 container 的getDeployLabels签名不同newdeploy 还接收 env 元数据。共享映射必须键在两者共有的稳定函数标识标签function name/uid上而不是完整标签集。4.4 D. 退役独立的 Deployment/Service informer 工厂一旦 Deployment/Service 由 Manager 监视B/C 已完成并为它们给executorCacheOptions加上标签限定范围的ByObject过滤器镜像现有 poolmgr Pod 过滤器Manager 缓存就成为这些读取的唯一来源。然后删除GetInformerFactoryByExecutor、ndmInformerFactory/cnmInformerFactory映射、deplLister*/svcLister*字段和startFactoriesrunnable把读取统一改走mgr.GetClient()。这是本 RFC 中最清晰的一条内存优化项。4.5 E. 用 finalizer 实现可靠的跨命名空间回收可选、分阶段因为 owner-ref GC 够不到FunctionNamespace在 Function 上如需要还有 Environment添加 Fission finalizerfission.io/function-cleanup首次 reconcile 时添加删除时DeletionTimestamp 已设置reconcile 拆除跨命名空间的 Deployment/Service/HPA然后移除 finalizer首版通过环境变量开关控制默认关闭以便行为得到验证后再设为默认为 executor 宕机的场景提供文档化的逃生通道保证删除永远不会卡死kubectl patch function name -n ns --typemerge -p {metadata:{finalizers:[]}}。这取代了脆弱的「NotFound lastReconciled缓存 reaper」清理链变成不依赖 executor 实时观察到删除事件的保证性回收。5. 诚实地说省了什么、没省什么没有缩小 Function/Environment 的 informer/缓存内存——controller-runtime 本来就按 Manager、按 GVK 共享一个 informer。确实移除三个 Function workqueue 中的两个 对应协程池、两个 Environment 中的一个、两个 cms reconciler、两份重复状态映射以及第 D 项独立 Deployment/Service informer 工厂。净效果executor reconciler9 → 3统一functionReconciler poolmgrreplicaSetReconciler poolmgrreadyPodReconcilerFunction 事件处理3× → 1×独立 informer 工厂2 → 0。6. 备选方案与取舍.Owns() owner reference 做 GC否决。owner reference 不能跨命名空间而 Fission 惯常把工作负载放在与 CR 不同的FunctionNamespace。.Owns()会在最典型的场景下静默失效。保留三个 reconciler、只共享谓词/状态收益有限仍保留三重扇出、重复状态映射和冗余工厂而且依然没有自愈。把小单进程timer/kubewatcher/canaryconfig合并进一个进程基线内存收益更大更少的 Go runtime Manager 缓存但会改变 Helm 拓扑、租约、RBAC 和故障隔离。延后到可能的未来 RFC本次明确不做。7. 向后兼容无 CRD schema、CLI 或 Helm 值变更。统一 reconciler 保留各后端既有的 create/update/delete 语义AdoptExistingResources继续与 reconciler 的初始同步单飞single-flight。finalizer可选默认关闭启用它是操作员的刻意动作强删路径有文档。集群下限不变Kubernetes 1.32见 docs/rfc/README.md.Watches()、标签映射入队、finalizer 均为长期 GA 能力。8. 分阶段实施每个阶段一个可审查的 PR均引用本 RFC扩展 pkg/controller/builder.go增加支持.Watches()的注册变体无行为变化。把两个 Environment reconciler 合并为一个风险最低、相互隔离。把三个 Function reconciler 合并为一个按类型分发的 reconciler保留各后端的 create/update/delete 切换逻辑。把 ConfigMap/Secret 回收折入统一 Function reconciler 的.Watches()删除 cms reconciler。为 Deployment/Service/HPA 增加.Watches()漂移修正。退役独立SharedInformerFactoryDeployment/Service 读取走 Manager 缓存 增加标签限定ByObject过滤器。finalizer可选、环境变量门控 强删文档。9. 验证 / 测试计划单元测试为每个映射函数envToFunctions、cmToFunctions、secretToFunctions、deployToFunction…编写表驱动测试跑在 fake clientset 上——断言正确的 Function key 被入队且错误命名空间/错误标签的对象什么都不入队。Reconcile 分发断言每种ExecutorType的 Function 都路由到正确后端且 executor 类型切换会拆除旧后端对象并构建新的集成套件已经覆盖切换场景。自愈集成测试——创建函数带外删除其 Deployment断言无需 spec 变更即被重建。Finalizer集成测试——开 flag 后删除 Function断言其跨命名空间 Deployment/Service/HPA 在对象消失前已被清掉断言强删 patch 能解除卡死的删除。回归现有 executor 集成套件test/integration/suites/common、test/integration/suites/serial必须保持绿色serial 套件的AdoptExistingResources测试守护 adopt/reconcile 单飞。资源增量仅供参考在第 6 阶段前后抓取 executor 的 CI pprof goroutine/heap 画像确认工厂移除与协程数下降。10. 悬而未决的问题finalizer 是否也覆盖 Environment其 builder Deployment/Service 在buildermgr中还是首版只做 Functionpoolmgr pool 的周期性重新同步应该放在统一 Function reconciler 的RequeueAfter上还是继续留在它现在所在的 Environment 路径上面对三种 executor 类型不同的标签集一个统一的 Deployment/Service 标签限定ByObject过滤器是否足够11. 实际落地As shipped与设计的偏差正式实施相对计划有几处偏离PR #3457–#34612026-06-03 全部合并第 4 阶段把 cms 折入.Watches()被跳过。cms reconciler 直接调用RefreshFuncPods要把它折入 Function reconciler需要引入「被引用资源 RV 和变化检测」一次 level-triggered 重新设计才能去掉两个薄 reconciler——投入产出比不划算。所以 executor 最终定型为6 个 reconciler统一 Function、统一 Environment、cms ConfigMap、cms Secret、poolmgr ReplicaSet、poolmgr readyPod而不是设计草图里的约 3 个。finalizer 变成 chart 级默认开启开关而不是环境变量门控/可选顶层finalizerEnabled值默认true与disableOwnerReference并列见 charts/fission-all/values.yaml由 charts/fission-all/templates/executor/deployment.yaml 写入FINALIZER_ENABLED环境变量供其他控制器日后采纳而不是 executor 专用旋钮。漂移自愈范围只覆盖 Deployment ServiceHPA 不在 Manager 缓存中使用仅删除的 watch 谓词idle reaper 只会缩放、从不删除所以对 Update 做出反应会与它打架通过幂等的 get-or-create 路径重建。并发把三个按类型划分的 Function reconciler每个原本是独立的 1-worker 控制器合并为一个后破坏了跨类型隔离——一个阻塞在waitForDeploy的createFunction会队头阻塞不相关的函数。修复方式是给共享 reconciler 设MaxConcurrentReconciles10。11.1 落地后的代码实证当前仓库里统一的 Function reconciler 实现在 pkg/executor/funcreconciler/reconciler.go可以从源码确认上述「as shipped」细节ownedObjectToFunction通过getDeployLabels盖印的 function 标识标签fv1.FUNCTION_NAME/fv1.FUNCTION_NAMESPACE常量定义见 pkg/apis/core/v1/const.go把受管 Deployment/Service 映射回 Function缺失标签直接返回 nil不是我们的对象。deleteOnlyPredicate只放行 Delete 事件——Create/Update/Generic 全否与「reaper 缩放永不删除」的冲突规避一致。functionFinalizer fission.io/function-cleanup由 chart 级finalizerEnabled值经FINALIZER_ENABLED环境变量开关关闭时会主动排空已存在的 finalizer避免删除卡死。deletionTimestampPredicate与GenerationChangedPredicateOR 组合状态专用写入仍被过滤但删除DeletionTimestamp 置位、Generation 不变必须到达 reconciler否则被 finalizer 持有的 Function 无法回收释放。funcReconcileConcurrency 10对应并发修复controller-runtime 仍按 Function key 串行化所以每函数状态安全。RegisterReconciler直接构建控制器不走controller.Register因为需要.Watches()For(fv1.Function{})Watches(Deployment)Watches(Service)两个仅删除的 watch 完整落地。在 pkg/executor/start.go 中executorCacheOptions用executorManagedSelectorEXECUTOR_TYPE ∈ {newdeploy, container}把 Deployment/Service 的ByObject缓存限定在 executor 受管对象上保持原独立工厂的标签作用域issue #2775cms 的RegisterReconcilers、统一 Environment reconciler、leader 选举下的executorControllersrunnable 都一一对应落地。12. 实测性能数据已测量CI 在每条集成腿kind-ci profile抓取 executor 的 heap goroutine pprof。所有数据基于 k8s v1.34.3。12.1 累计RFC-0004 前 vs 后完整合并 漂移自愈Before 4395fbefpre-#3457最近一个能抓到 executor 的 pre-RFC main 提交After #3461run 26880909337。Executor goroutines按帧BeforeAfterΔcontroller-runtime controller machinery2718−9reconcile workersprocessNextWorkItem96−3workqueue goroutines347−27informer reflectors2420−4informer sharedProcessor / listeners12/2210/20−2/−2total233225−8Heapinuse4.67 MB → 6.08 MB——在 run 间抓取噪声范围内不是回归。合并释放的是协程/workqueue不是缓存内存controller-runtime 无论哪种方式都按 GVK 共享一个 informer所以 heap 基本持平更早的 Phase-3 样本曾反向摆动 6.4 → 4.4 MB。Router对照不受 RFC-0004 影响74 → 72 协程。注意事项这个「after」快照早于MaxConcurrentReconciles10修复所以 Function reconciler 当时仍只有一个 worker。合并后的最终形态会新增约 9 个闲置 reconcile-worker 协程parked 在queue.Get上开销很低这是为不饥饿付出的刻意代价——最终总数与 pre-RFC 基线大致持平但 workqueue/controller machinery 少得多。12.2 Phase 3 单独8 → 6 个 reconcilerFunction 合并Maine494f61cPhase 2 合并后8 个 reconcilervs #34586 个 reconcilerreconcile workers 8 → 6controller machinery 24 → 18每控制器事件源协程 8 → 6heap 持平client-go informer 帧逐字节相同informer 按 GVK 共享。两份对比中持久不变的信号是构成更少的控制器、workqueue、informer而不是原始总数——后者随集群活动在 run 间波动。结语与延伸阅读RFC-0004 是一次教科书式的「依赖驱动 reconciler」重构以 Function 为中心、用.Watches()表达真实依赖图、用标签映射突破 owner-reference 的跨命名空间限制、用 finalizer 换掉脆弱的删除回收链并用「不改变 CRD/CLI/Helm 值、不合并跨进程」的纪律把风险锁在控制平面内部。即使 cms 折入与 HPA 自愈两项最终按性价比与缓存范围取舍偏离了原设计核心收益——单 Function 工作队列、单份状态缓存、零独立 informer 工厂、可选可靠回收——都已稳定落地并被 CI pprof 数据佐证。完整设计原文docs/rfc/0004-reconciler-consolidation.md合并后的交互式拓扑图docs/rfc/0004-reconciler-map.html统一 Function reconciler 实现pkg/executor/funcreconciler/reconciler.goexecutor 启动与缓存作用域pkg/executor/start.gocmsConfigMap/Secret回收实现pkg/executor/cms/reconciler.go共享注册助手pkg/controller/builder.gofinalizer 开关Helm 值charts/fission-all/values.yaml赞分享云原生后端【免费下载链接】fissionFast and Simple Serverless Functions for Kubernetes项目地址https://gitcode.com/gh_mirrors/fi/fission点击查看免费下载相关推荐Nativefier构建任务依赖任务顺序与并行执行Nativefier构建任务依赖任务顺序与并行执行 你是否在使用Nativefier时遇到过构建失败或执行效率低下的问题本文将深入解析Nativefier的CLI桌面应用开发工具深入理解Granite-3B-Code-Instruct-2K架构Llama模型的2560隐藏层优化指南深入理解Granite 3B Code Instruct 2K架构Llama模型的2560隐藏层优化指南 Granite 3B Code Instruct 2OpenCloud 依赖解析modern-go/concurrent 并发 Map 与可取消 Goroutine 执行器实战OpenCloud 依赖解析modern go/concurrent 并发 Map 与可取消 Goroutine 执行器实战 导读 本文以 OpenCloud后端微服务存储认证鉴权上一篇终极指南如何快速上手CodiumAI PR-Agent智能代码审查工具下一篇如何快速实现Unity UI平滑遮罩打造专业级UI效果的终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
