ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

iii 增量采用指南:不重写、不切换,把现有系统一片一片迁入 iii

iii 增量采用指南:不重写、不切换,把现有系统一片一片迁入 iii iii 增量采用指南不重写、不切换把现有系统一片一片迁入 iii【免费下载链接】iiiEffortlessly compose, extend, and observe every service in real-time for the first time ever.项目地址: https://gitcode.com/GitHub_Trending/mo/iii导读本指南面向已经有一套线上系统、希望引入 iii 而又不愿承担一次性重写big-bang rewrite风险的团队。你将学习三条可独立执行、可随时回滚的迁移路径把现有 HTTP 服务包装成 iii 函数、把耗时调用卸载到 iii 队列、把持久化状态逐片迁入 iii 的状态原语。完成全部三步后你的系统运行在 iii 之上却从未经历过一次全量切换full cutover。为什么选择增量采用iii 的默认架构是引擎 若干 worker引擎从config.yaml启动worker 通过 WebSocket 接入向系统贡献可被function_id调用的函数。这意味着你并不需要先拆掉旧系统再重建新系统而是可以在旧系统旁边逐步增加 iii 形状的接入点让新旧两侧并行存在直到某一片彻底迁完为止。从源码结构看这一设计贯穿了仓库的多个层面引擎侧 engine/src/engine/mod.rs 维护函数、触发器、worker 的注册与路由config.yaml 支持热更新加载新 worker。文档 docs/quickstart.mdx 中的iii worker add命令正是增量添加的入口——每执行一次就在运行中的系统上多挂载一个能力而不是重建整个系统。迁移前的准备条件原文档列出了三项前提逐一展开如下一台运行中的 iii 引擎先按 安装指南 安装 iii然后在一个空目录运行iii让它在首次启动时生成config.yaml非交互环境如容器、CI 中会自动创建交互环境会询问确认。随后用iii worker add name为每一步需要的 worker 添加到系统中。关于引擎如何读取默认配置、config.yaml的结构与workers:列表的含义见 默认配置新生成的config.yaml以空workers:列表启动引擎仅自带内部服务SDK worker 接入的 WebSocket 监听器、配置 worker、可观测性其余能力全部由你显式 opt-in。一个可以通过 HTTP 访问的既有服务这是你要迁移的对象也是第一步包装的载体。服务所用语言对应的 SDKiii 提供 TypeScript / Python / Rust 三种 SDK分别位于仓库 sdk/packages/node、sdk/packages/python、sdk/packages/rust。SDK 的用法以函数注册为例可参考 编写函数。三步路线总览原文档给出的迁移路线由三个相互衔接、各自可独立回滚的子教程组成包装现有 API为现有 HTTP 服务增加一个 iii 函数形态的入口让它可以从系统中任何位置以function_id寻址。此时流量并不迁移只是新增一个接入点。把工作卸载到队列将耗时的调用放到队列 worker 背后让包装函数立即返回重试由队列负责。迁移持久化每次只迁移一小片状态到 state worker其余系统保持不变直到你准备好迁移下一片。下面分别结合仓库中的实际命令、配置与源码展开这三步的落地细节。第 1 步包装现有 HTTP 服务为 iii 函数目标让其他 worker 能通过function_id调用你的现有服务而流量仍在旧系统上。在 iii 中一个 worker 通过向 SDK 注册函数来贡献能力。函数 ID 形如service::name例如math::add这是调用方触发时使用的function_id。注册示例TypeScriptimport { registerWorker } from iii-sdk; const url process.env.III_URL; if (!url) throw new Error(III_URL must be set); const worker registerWorker(url); worker.registerFunction(math::add, async (payload: { a: number; b: number }) { return { c: payload.a payload.b }; });Python 与 Rust 对应写法见 编写函数其中 Python 使用worker.register_function(math::add, add_handler)Rust 使用worker.register_function(math::add, RegisterFunction::new(...))。注册时还可以附带请求/响应 JSON Schema 元数据它们会出现在 iii 控制台与iii trigger --help中作为函数契约文档注意当前版本 schema 仅作元数据不做运行时校验。包装现有服务的关键差异在于handler 内部不是计算逻辑而是通过 HTTP 调用你的旧服务再把响应原样返回。这样旧系统保持原样运行只是多了一个 iii 形状的入口。若要让外部 HTTP 请求直接命中该函数可以绑定http触发器worker.registerTrigger({ type: http, function_id: math::add, config: { api_path: /math/add, http_method: POST }, });绑定的细节含在触发器类型发布前乐观注册的行为见 使用 iii / 触发器 与 编写触发器。这一步不迁移流量现有调用方继续访问旧服务iii 侧只是新增了一个可寻址入口。第 2 步把耗时工作卸载到 iii 队列目标调用方立即返回重试与并发由队列接管。iii 的queueworker 提供命名队列named queue与发布/订阅两种形态。先添加队列 workeriii worker add queue队列在queueworker 的配置queue_configs下定义例如- name: queue config: queue_configs: email-jobs: max_retries: 3 concurrency: 10 type: standard每个queue_configs条目支持的字段与默认值如下完整说明见 队列字段默认值说明max_retries3消息进入死信队列DLQ前的投递尝试次数concurrency10并行处理的作业数必须 ≥ 1schema 会拒绝0因此不能用它暂停队列fifo队列强制为1typestandardstandard并发或fifo消息组内有序message_group_field无fifo必填决定排序组的 payload 字段backoff_ms1000基础重试延迟毫秒指数退避poll_interval_ms100worker 轮询间隔毫秒调用方通过TriggerAction.Enqueue把函数调用投入队列而不是同步等待结果import { TriggerAction, type EnqueueResult } from iii-sdk; const { messageReceiptId } await worker.triggerunknown, EnqueueResult({ function_id: email::send, payload: { to: ab.com, subject: hi }, action: TriggerAction.Enqueue({ queue: email-jobs }), }); // messageReceiptId 标识这条已入队的作业from iii import TriggerAction receipt worker.trigger({ function_id: email::send, payload: {to: ab.com, subject: hi}, action: TriggerAction.Enqueue(queueemail-jobs), }) # receipt[messageReceiptId] 标识这条已入队的作业use iii_sdk::TriggerAction; use iii_sdk::protocol::TriggerRequest; use serde_json::json; let receipt worker .trigger(TriggerRequest { function_id: email::send.to_string(), payload: json!({ to: ab.com, subject: hi }), action: Some(TriggerAction::Enqueue { queue: email-jobs.to_string() }), timeout_ms: None, }) .await?;引擎侧对TriggerAction::Enqueue的处理位于 engine/src/engine/mod.rs它生成message_receipt_idUUID捕获调用方的 namespace而非默认default并保留 traceparent/baggage 以便可观测性延续。消费端通过durable:subscriber触发器绑定到主题引擎对每条消息运行一次函数正常返回即确认ack抛异常即否定nack并进入重试最终重试耗尽进入死信队列。这也是调用方立即返回、重试由队列负责的机制来源。第 3 步把持久化逐片迁入 iii 状态原语目标一次只迁移一小片状态其余系统保持不动。iii 的stateworker 为每个函数提供持久化键值存储。先添加它iii worker add state之后函数可以通过state::get/state::set携带scope与key读写状态。以 快速上手 中的累计求和为例running_total worker.trigger( { function_id: state::get, payload: {scope: math, key: running_total}, } ) new_total (running_total or 0) result[c] worker.trigger( { function_id: state::set, payload: {scope: math, key: running_total, value: new_total}, } )多次调用后running_total跨调用持续累积且对通过其他函数如math::add_two_numbers进入的调用同样生效——这正是状态从旧系统迁出、由 iii 接管的最小范例。迁移持久化时策略是按切片slice推进选定一小片状态比如一个业务实体在代码中把它的读写从旧存储切换到state::*调用其余数据仍留在旧系统。每片迁移完成、验证通过后再动下一片直到全部迁完。结论每个切片独立可逆按顺序走完三个子教程系统会以一片一片的方式落到 iii 上。关键在于每个切片都是独立可回滚的包装入口可以随时摘除、队列可以随时改为同步调用、状态可以随时写回旧存储。因此在任意边界上暂停或回滚都不会影响系统其余部分。这种可逆性还得到引擎动态加载机制的支撑引擎监听config.yaml的变更并实时拉起新 worker见 默认配置也就是说添加能力与移除能力都是运行期操作无需停机。对已经迁移完成的 worker还可以通过 worker 注册表 以iii worker add name的方式从注册表安装与自研 worker 的安装体验保持一致registry 条目支持二进制、OCI 镜像与 bundle 三种制品形态。延伸阅读快速上手端到端跑通引擎、函数、状态与 HTTP编写函数注册、function_id 与请求/响应 Schema队列命名队列、pub/sub 与死信队列使用 iii / 触发器绑定、门控与乐观注册创建 workeriii worker init脚手架与函数清单worker 注册表发布与安装引擎默认配置config.yaml与热加载安装指南【免费下载链接】iiiEffortlessly compose, extend, and observe every service in real-time for the first time ever.项目地址: https://gitcode.com/GitHub_Trending/mo/iii创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表