新旧功能的柔性切换:灰度路由、影子比较与读写迁移
新实现已经上线,旧实现仍在服务。只改一个开关,就能让少量请求试用新实现;同一份输入还可以交给另一侧执行,比较结果,却不改变用户看到的响应。试用扩大后,主次可以反过来:新实现负责响应,旧实现继续提供比较样本,并在符合条件时兜底。 这类能力发生在应用内部。需要切换的可能是一套规则、一份配置的读取方式、一个查询接口、一段任务流程,或者整个数据模型。蓝绿、金丝雀和滚动发布可以帮助放量,但发布单元的流量比例没有回答:谁有权返回结果,谁可以写数据,哪种失败允许回退,以及回退的数据是否还可信。 以目录查询为例,旧存储 O 正在服务,新存储 N 逐步接入。迁移先让 N 观察真实查询,再让已完成数据准备的人群使用新读,之后才转移写入权威。停止回退和停止维护旧数据又是两次不同的决定。模板计算和任务处理也可以沿这条路径分析,只是比较合同和副作用边界各不相同。 从一次查询看清四种角色 设旧实现为 O,新实现为 N。请求被路由到 N,不代表最终一定由 N 返回:N 可能失败,系统按照策略使用 O 的结果。与此同时,O 也可能只是被调用来比较,完全没有接管响应的资格。 因此至少需要分别表达主执行、影子执行、...
业务扩展框架03:组合实验与远程绑定
运行一个最小业务组合实验 在博客源码仓库根目录运行: 1bash examples/business-extension/run.sh 示例仅依赖 JDK 8 或更新 JDK,不下载第三方依赖。脚本在临时目录编译,运行后清理编译产物。完整代码位于仓库的 examples/business-extension/ExtensionLab.java,实验说明位于同目录 README.md。 这是自建教学模型,不是 TMF、Lattice 或美团 BPF 的源码。它验证 SPI 发现、注解注册、业务配置激活和本地扩展调用。库存、资格与销售时间仅记录 mock 事件,没有连接真实系统。 在 Java 8 下执行,三个业务输出如下: 12345retail v1 payable=10000 [validate.input, price.list, inventory.audit, inventory.stock(mock)]presale v1 payable=9000 [validate.input, validate.presale-window(mock), price.presale...
业务扩展框架02:注解模型与表驱动
注解把组件看成什么 业务框架读取一个类上的注解时,通常是在构建组件描述信息:这个实现的稳定标识是什么、实现哪个扩展点、归属哪种业务或产品、遵守什么调用契约。Java 对象负责执行代码,描述信息负责让框架管理和选择这个对象。 “被注解的组件”可能对应不同对象: 注解所在位置 可能建模的对象 不能仅凭注解得出的结论 领域接口或抽象类 能力定义、服务契约、流程节点类型 已经存在可执行实例 扩展接口的方法 一个变化点及其输入输出、归约语义 有多少业务实现会被激活 具体实现类 某个能力实现及其归属 本次请求一定执行它 配置加载器、代理工厂 框架本身的可替换基础设施 它属于某个商业产品 服务引用字段 远程服务引用的声明 远端实例已经发现且可用 因此同样叫 @Extension,在不同框架里可能标记扩展点定义,也可能标记扩展实现。理解注解必须同时看 @Target、处理器和注册过程;仅凭名字无法确定语义。 图 1:教学对照:注解所在位置与处理器共同决定被登记的对象;这些分支不代表同一个框架的统一 API。 flowchart TB accTitle: 注...
业务扩展框架01:TMF与美团平台化实践解决什么问题
多业务共用平台以后,复用为什么会变难 一个订单平台同时支持普通零售、预售和团购。三者都有商品、价格、订单与库存,但预售需要校验销售时间和预售额度,团购需要校验成团条件,普通零售通常直接处理现货。把共同步骤提取出来并不难,难的是下一次改预售规则时,怎样确定团购完全不受影响。 最直接的写法是在每个步骤判断业务类型。业务增多后,条件会散落到价格、库存、退款、消息消费等位置。新增业务的代价不只是多写几个分支,还包括找到所有分支、理解组合顺序、协调多个团队发布,以及证明旧业务没有改变。 将分支改成若干 Strategy 类,只解决了代码摆放。若每个策略自行判断是否适用、彼此没有清晰归属,两个策略可能同时生效,运行时仍然需要回答:这次请求应执行谁,为什么,冲突时怎么办。 TMF 一类业务扩展框架要把这些关系显式化:平台定义稳定的业务契约和变化点,业务提供定制实现,配置表达安装关系与冲突决策,运行时按明确的业务上下文执行。它需要的前提是已经存在值得复用的业务模型;框架不会从一堆任意 Java 方法中自动发现一个交易平台。 本系列分为三篇: 本篇:TMF 与美团公开实践的目标、领域模型和架构边...
Codex 架构全景:本地运行、云端长任务与多层 Loop
Codex 的架构需要同时回答两个问题:一次编码请求怎样完成,以及请求结束以后,什么状态还能保留、谁会再次启动工作。前一个问题涉及模型、工具和 Harness;后一个问题涉及会话、目标、执行环境、调度和身份。 “Codex 在本地运行”通常表示工作区和工具在本机,模型推理仍可以发生在 OpenAI 的服务器。“Desktop 连 Remote”通常表示客户端通过 SSH 控制远端 App Server;“Cloud 长期运行”则包含托管执行环境及其生命周期。这些模式可以共享执行框架,却承担着不同的运行责任。 本文以 2026 年 10 月 15 日读取的官方产品文档和 Codex rust-v0.162.1 源码为基线。源码固定在 092d3acd6bec3e3a14bdc7e7a2810ab628ab759d,提交日期为 2026 年 10 月 9 日;本地 codex --version 为 codex-cli 0.162.1。文中的拓扑是根据公开接口整理的解释模型,涉及托管 Cloud 的部分只描述公开契约。云端内部队列、数据库拓扑、VM checkpoint 算法和模型权...
Flink 生产部署拓扑与组件职责
Flink 作业能从 Kafka 读到数据,并不意味着它已经具备生产恢复能力。任务运行在什么进程、状态存在哪里、谁负责申请资源,以及故障后从哪个位置继续处理,需要在部署时分别确定。 本文以 Apache Flink 2.3 文档为基线,讨论有状态流作业的生产拓扑。图中的连接区分任务调度、记录传输与状态持久化;对象存储、Kafka 和 Kubernetes 都是外部系统,不属于 TaskManager 内部组件。批处理的调度与 shuffle 策略另有配置,不能把下面的持续流水线直接套用到所有有界作业。 集群内外的职责 JobManager 负责协调执行,TaskManager 执行 source、转换和 sink。业务记录通常在 TaskManager 及外部系统之间流动,不需要经过 JobManager 转发。客户端负责提交;作业以 detached 方式启动后,客户端退出并不等于作业结束。 图 1:Flink 控制连接、业务数据与快照存储的边界 flowchart TB C["客户端"] -.->|"提交"| JM["...
Kafka 生产部署拓扑与组件职责
Kafka 的部署单元包括控制器、保存分区副本的 Broker,以及运行生产者、消费者和数据管道的应用进程。三类进程承担不同负载,扩容和故障恢复也有不同边界。只画几个 Broker,容易漏掉元数据多数派、客户端网络地址和内部主题这些影响可用性的条件。 本文以 Apache Kafka 4.3 文档中的 KRaft 部署为参照。Kafka 4.0 起不再支持 ZooKeeper 模式;旧集群迁移需要经过兼容的 3.x 版本。图中的三控制器、三 Broker 是解释故障域的示例,不是所有业务的容量配置。 控制面与数据面 控制器维护 Broker 注册、主题和分区元数据,决定分区领导者等集群状态。Broker 保存业务日志副本并响应生产和消费请求。业务消息无需经过控制器转发,控制器的副本数也不决定业务主题的副本数。 图 1:KRaft 控制面与业务数据面的部署边界 flowchart TB subgraph CP[控制面:独立控制器进程] C1[Controller 1] --- C2[Controller 2] C2 --- C3[Controller 3] ...
Kubernetes 生产部署拓扑与组件职责
Kubernetes 的对象模型只有放进真实的生产拓扑里,组件职责和故障边界才会变得清楚。控制面负责接受期望状态、保存状态并作出调度与调谐决策;节点侧负责把已经绑定到本节点的 Pod 变成容器、网络和存储挂载。两侧通过 API 对象协作,而不是彼此直接调用全部内部组件。 本文集中画出生产环境里最容易混淆的十四条关系:控制面与工作节点、API 请求、控制器、调度器、节点执行、服务流量、存储与网络插件、探针、滚动发布、节点故障、etcd 仲裁、备份恢复和多可用区部署。图中的路径采用 Kubernetes 官方文档当前公开的稳定机制;具体版本的 feature gate、默认值和版本偏斜范围仍应以目标版本文档为准。 控制面与工作节点 图 1:Kubernetes 控制面与工作节点的生产拓扑 flowchart TB U[kubectl / CI / Controller] --> LB[API Server 负载均衡入口] LB --> A1[kube-apiserver A] LB --> A2[kube-apiserver B] L...
深入 Elasticsearch(19):生产部署拓扑与节点角色划分
三节点实验集群能验证发现、选举和分片复制,但不能直接推导出生产拓扑。生产设计必须同时回答四个问题:哪些节点参与控制面,哪些节点承担数据面,故障域如何隔离,以及任一节点或可用区退出后,剩余容量能否继续承载业务。 本文面向自建 Elasticsearch 8.x/9.x 集群,给出从小型混合角色集群到分层数据节点集群的参考拓扑。具体节点数、分片数和硬件规格仍应以目标版本和真实负载压测为准;Elastic Cloud Serverless 的资源模型不适用这里的自建配置。 先选拓扑,再写配置 生产集群没有一套固定节点清单。轻负载可以让节点混合承担 master、data 和 ingest;规模扩大后,再把控制面和高消耗的数据处理职责拆开。角色拆分的目标是隔离资源竞争和故障影响,不是让节点名字更多。 图 1:从实验集群到分层生产集群的演进路径 flowchart LR A[单节点开发环境<br/>全部默认角色] --> B[三节点小型生产集群<br/>master + data + ingest] B --> C[控制面分离<br/&g...
Jev 为什么像 BERT 又像 LLM:决策模型的创新与旧谱系
“虽然等了很久,但客服已经补发,先不用退款。”判断这句话的情绪,和判断用户是否要求退款,是两个任务。传统情感分类器的任务在训练时已经确定;自然语言任务接口则允许每次请求指定判断标准。 Jev 引人关注,正因为它提供了这样的接口,同时把答案限制在给定范围内:不生成一段回答,而是针对 Choice、Score、Noul 这类类型化问题返回概率结果。“像 BERT 又像 LLM”首先描述的是这种能力组合。 这种组合已有多年的技术积累。理解 Jev 的新意,需要区分自然语言怎样定义任务,以及模型怎样输出答案。 BERT 与常见 LLM 的区别 BERT 和 LLM 不是严格互斥的两个集合。BERT 本身就是语言模型,也可以做得很大。日常语境里的“BERT 类模型”通常指 encoder-only、双向注意力、以表示学习和判别任务为主的模型;“LLM”则常被用来指 decoder-only、因果注意力、逐 token 生成的大模型。 真正有区分力的是三个维度: 维度 BERT 类 encoder 常见 decoder-only LLM 注意力 token 可同时看左右文 当...





