news 2026/9/11 19:46:29

Huly Virtual Network 实战指南:基于 ZeroMQ 的分布式容器网络架构与开发部署

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Huly Virtual Network 实战指南:基于 ZeroMQ 的分布式容器网络架构与开发部署

Huly Virtual Network 实战指南:基于 ZeroMQ 的分布式容器网络架构与开发部署

【免费下载链接】platformHuly — All-in-One Project Management Platform (alternative to Linear, Jira, Slack, Notion, Motion)项目地址: https://gitcode.com/GitHub_Trending/platform80/platform

本文围绕 Huly 平台底层虚拟网络组件 Huly Virtual Network 展开,系统讲解其 hub-and-spoke 架构(网络服务器、Agent、容器、客户端四个核心角色)、容器开发与生命周期管理、HA 无状态容器故障转移、多租户隔离以及生产部署方案。读者学完后能够独立搭建一个完整的分布式容器网络应用,掌握容器接口实现、事件广播、自动释放(auto-disposal)与高可用配置等关键能力。文中所有示例均可在仓库foundations/net目录下的 docs 与 examples 中对照验证。

一、认识 Huly Virtual Network:解决什么问题

Huly Virtual Network 是 Huly 平台中负责"虚拟化服务实例"的分布式运行时组件。它的设计目标不是传统意义上的容器虚拟化,而是把一段业务逻辑(Container)作为可寻址、可路由、可自动伸缩的资源单元,让客户端通过网络透明地获取和使用这些服务实例。

其核心设计思想是hub-and-spoke(中心辐射式)架构

  • 网络服务器(Network Server):中心协调者,维护 Agent 与容器注册表,负责路由、生命周期与事件广播;
  • Agent:工作节点进程,承载并托管容器,向网络注册自身能力;
  • 容器(Container):实现具体业务逻辑的服务实例,处理客户端请求;
  • 客户端(Client):按 kind(种类)与条件向网络请求容器,发送请求并接收事件。

从仓库源码结构看,这一架构被拆分为四个独立包:core(网络核心类型、NetworkImplTickManagerImplAgentImpl与容器接口)、server(NetworkServer网络服务端)、client(createNetworkClientNetworkAgentServerserveAgent)以及 backrpc(底层 RPC 与消息通道)。

重要的设计约束

在深入之前必须先明确一条贯穿全文的关键限制网络服务器(中心协调者)只能以单实例运行,不支持 HA 与集群。而 Agent 与容器则完全支持高可用——通过无状态注册机制实现自动故障转移。这条约束在 QUICKSTART、HA_STATELESS_CONTAINERS 与 PRODUCTION_DEPLOYMENT 中被反复强调,生产环境必须据此设计架构。

二、快速开始:十分钟搭建第一个网络应用

环境要求

  • Node.js:22.0.0 或更高;
  • PNPM:10.15 或更高(经 Rush 自动安装);
  • ZeroMQ:原生依赖(自动安装);
  • 操作系统:Linux、macOS 或 Windows 均可。

三种安装方式

方式一:克隆源码构建(推荐开发)

git clone https://github.com/hcengineering/huly.net.git cd huly.net # 安装依赖 node common/scripts/install-run-rush.js install # 构建所有包 node common/scripts/install-run-rush.js build # 运行测试验证 node common/scripts/install-run-rush.js test

方式二:Docker 镜像(推荐生产)

docker pull hardcoreeng/network-pod:latest docker run -d \ --name huly-network \ -p 3737:3737 \ hardcoreeng/network-pod:latest

方式三:NPM 包(官方文档标注 Coming Soon)

npm install @hcengineering/network-core \ @hcengineering/network-client \ @hcengineering/network-server

分步实现你的第一个容器应用

Step 1:定义一个容器(my-container.ts

容器只需实现Container接口,即可获得完整的网络寻址与生命周期能力:

import type { Container, ContainerUuid, ClientUuid } from '@hcengineering/network-core' export class HelloWorldContainer implements Container { constructor(readonly uuid: ContainerUuid) { console.log(`Container ${uuid} created`) } async request(operation: string, data?: any): Promise<any> { switch (operation) { case 'greet': return { message: `Hello, ${data?.name || 'World'}!` } case 'status': return { status: 'running', uuid: this.uuid } default: return { error: 'Unknown operation' } } } async ping(): Promise<void> { // 健康检查 } async terminate(): Promise<void> { console.log(`Container ${this.uuid} terminated`) } connect(clientId: ClientUuid, broadcast: (data: any) => Promise<void>): void {} disconnect(clientId: ClientUuid): void {} }
Step 2:启动网络服务器(server.ts
import { NetworkImpl, TickManagerImpl } from '@hcengineering/network-core' import { NetworkServer } from '@hcengineering/network-server' const tickManager = new TickManagerImpl(1000) tickManager.start() const network = new NetworkImpl(tickManager) const server = new NetworkServer(network, tickManager, '*', 3737) console.log('🚀 Network server started on port 3737') // 优雅停机 process.on('SIGINT', async () => { console.log('\nShutting down...') await server.close() tickManager.stop() process.exit(0) })
Step 3:创建 Agent(agent.ts

Agent 通过serveAgent向网络注册容器工厂:

import { createNetworkClient } from '@hcengineering/network-client' import { HelloWorldContainer } from './my-container' import type { GetOptions, ContainerUuid } from '@hcengineering/network-core' const client = createNetworkClient('localhost:3737') await client.waitConnection(5000) await client.serveAgent('localhost:3738', { 'hello-world': async (options: GetOptions) => { const uuid = options.uuid ?? (`hello-${Date.now()}` as ContainerUuid) const container = new HelloWorldContainer(uuid) return { uuid, container, endpoint: `hello://localhost/${uuid}` as any } } }) console.log('🤖 Agent server started on port 3738') process.on('SIGINT', async () => { await client.close() process.exit(0) })
Step 4:编写客户端(client.ts
import { createNetworkClient } from '@hcengineering/network-client' async function main() { const client = createNetworkClient('localhost:3737') await client.waitConnection(5000) console.log('✅ Connected to network') // 获取容器 const containerRef = await client.get('hello-world' as any, {}) console.log(`📦 Got container: ${containerRef.uuid}`) // 发送请求 const greeting = await containerRef.request('greet', { name: 'Alice' }) console.log('Response:', greeting) const status = await containerRef.request('status') console.log('Status:', status) // 清理 await containerRef.close() await client.close() console.log('👋 Disconnected') } main().catch(console.error)
Step 5:运行

分别打开三个终端执行:

npx ts-node server.ts # 终端 1 npx ts-node agent.ts # 终端 2 npx ts-node client.ts # 终端 3

预期输出:

✅ Connected to network 📦 Got container: hello-1234567890 Response: { message: 'Hello, Alice!' } Status: { status: 'running', uuid: 'hello-1234567890' } 👋 Disconnected

若想单文件体验完整流程,可参考 QUICKSTART 中的 All-in-One 示例(在同一个进程中依次启动 TickManager、Network、Server,再用serveAgent注册 demo 容器并直接get调用)。仓库 examples 目录下还提供了更完整的可运行示例,例如 01-basic-container-request-response.ts、02-event-broadcasting.ts 等。

三、核心概念:网络、Agent、容器与客户端

架构总览

Core Concepts 使用 Mermaid 描述了完整拓扑:客户端向中心 Network 发起容器请求,Network 维护容器注册表(Container Registry)并通过路由器(Router)把请求分发到对应 Agent,Agent 再路由到其托管的容器实例。其五大关键原则为:

  1. 集中协调:网络服务器统一协调所有 Agent 与容器;
  2. 分布式执行:容器运行在可跨机器分布的 Agent 上;
  3. 动态发现:客户端通过网络动态发现并连接容器;
  4. 自动生命周期:网络基于客户端引用自动管理容器生命周期;
  5. 容错:失败 Agent 与孤儿容器会被自动清理。

Network:中心协调者

Network 的职责包括维护 Agent/能力注册表、跟踪活动容器及其位置、路由客户端请求、管理生命周期(创建、引用计数、清理)、提供服务发现与负载均衡,并向客户端广播系统变更事件。其核心接口如下:

interface Network { // Agent 管理 register(record: AgentRecord, agent: NetworkAgentApi): Promise<ContainerUuid[]> unregister(agentId: AgentUuid): Promise<void> ping(agentId: AgentUuid): Promise<void> // 容器管理 get(client: ClientUuid, kind: ContainerKind, options: GetOptions): Promise<[ContainerUuid, ContainerEndpointRef]> release(client: ClientUuid, uuid: ContainerUuid): Promise<void> list(kind?: ContainerKind): Promise<ContainerRecord[]> // 通信 request(target: ContainerUuid, operation: string, data?: any): Promise<any> // 发现 agents(): AgentRecord[] kinds(): ContainerKind[] }

网络服务器监听 TCP 端口(默认 3737),基于 ZeroMQ 实现高性能消息传递,并通过 ping/pong 维持连接健康。启动方式见上文 Step 2。

Agent:工作节点

Agent 是托管容器的进程,负责:向网络注册并宣告能力(支持哪些容器 kind)、按需创建容器或预置无状态容器、处理容器生命周期(启动、停止、健康检查)、在客户端与容器间路由请求。

Agent 必须在超时窗口内持续向网络发送 ping。默认配置可在源码 packages/core/src/api/timeouts.ts 中找到:

export const timeouts = { aliveTimeout: 3, // 秒 - 判定 Agent/客户端死亡的超时 unusedContainerTimeout: 5, // 秒 - 无引用容器的终止等待时间 pingInterval: 1 // 秒 - Agent ping 间隔 }

也就是说:Agent 每 1 秒 ping 一次;若aliveTimeout(3 秒)内未收到 ping,网络将把该 Agent 标记为死亡,移除其全部容器、广播移除事件,并允许备用 Agent(针对无状态容器)接管。

Container:业务逻辑的载体

容器实现具体业务逻辑、维护内部状态、向连接中的客户端广播事件,并根据需求被自动创建与销毁。所有容器必须实现统一的 Container 接口:

interface Container { request(operation: string, data?: any, clientId?: ClientUuid): Promise<any> ping(): Promise<void> terminate(): Promise<void> connect(clientId: ClientUuid, broadcast: (data: any) => Promise<void>): void disconnect(clientId: ClientUuid): void onTerminated?(): void }
容器生命周期

request触发创建 → 工厂实例化 → 网络注册 → Active 处理请求 → 客户端持有引用进入 Referenced 状态 → 引用释放后进入 Idle 倒计时 → 超时后调用terminate()→ 从注册表移除。生命周期事件与超时值(containerTimeout/unusedContainerTimeout)由网络统一管理。

两类容器
  • 有状态容器(动态创建):按需由工厂创建,工厂可从GetOptions中提取参数(options.uuidoptions.extraoptions.labels)来定制实例;
  • 无状态容器(预置):容器实例在注册前已存在,多个 Agent 可持有同一 UUID 的实例参与竞争,网络接受第一个注册者、拒绝其余注册者,从而实现自动故障转移(详见第五节)。

Client:应用侧视角

客户端通过createNetworkClient('host:port')连接网络,按 kind 与条件获取容器、发送请求、接收事件并管理引用(acquire/release)。

const client = createNetworkClient('localhost:3737', 3600) // 第二参数为存活超时(秒,可选) await client.waitConnection(5000) // 最多等待 5 秒

获取容器的四种常见方式:

// 任意该 kind 的容器 const ref = await client.get('user-session' as ContainerKind, {}) // 指定 UUID const ref = await client.get('user-session' as ContainerKind, { uuid: 'session-123' as ContainerUuid }) // 带标签选择 const ref = await client.get('workspace' as ContainerKind, { labels: ['premium', 'us-west'] }) // 携带附加数据 const ref = await client.get('query-engine' as ContainerKind, { extra: { database: 'analytics', userId: 'user-456' } })

四种通信模式

  1. 请求/响应(同步)const result = await ref.request('processData', { value: 42 })
  2. 即发即忘(异步):调用request但不等待响应语义,适合日志、埋点;
  3. 事件广播(发布/订阅)const connection = await ref.connect()后设置connection.on = async (event) => {...},容器端通过broadcast回调向所有已连接客户端推送事件;
  4. 双向流式通信:在connect()建立的持久连接上,既能持续接收on回调,也能通过connection.request(...)继续发送请求。

端点引用(Endpoint References)

容器通过端点引用寻址,ContainerEndpointRef是带品牌标记的字符串类型。三种端点形态:

类型格式说明
Direct(直连)tcp://host:port/uuid直接连接容器
Routed(经 Agent 路由)agent://host:port:agentId/uuid经由 Agent 转发
No-Connect(免连接)noconnect://host:port/uuid仅请求,不建持久连接

可通过parseEndpointRef(endpoint)解析出kindhostportuuidagentId等字段。

容器 Kind 与标签

ContainerKind同样是带品牌标记的字符串类型,用于分类容器(如'user-session''workspace''query-engine''transactor')。Agent 在注册时声明支持的 kind 集合。标签(labels)提供细粒度选择能力,典型用途包括:多租户(以租户 ID 为标签)、地域路由(region 标签)、分级选择(free/premium/enterprise)与环境隔离(dev/staging/production)。

四、容器开发实战

Container Development Guide 提供了从零构建生产级容器的完整方法论,以下为核心要点。

请求处理器模式

推荐在request内使用 switch 或命令模式分发操作,并统一捕获异常返回结构化错误:

async request(operation: string, data?: any, clientId?: ClientUuid): Promise<any> { try { switch (operation) { case 'createUser': return await this.createUser(data) case 'getUser': return await this.getUser(data.userId) default: return { success: false, error: `Unknown operation: ${operation}`, supportedOperations: ['createUser', 'getUser'] } } } catch (error: any) { return { success: false, error: error.message } } }

对于长耗时任务,建议配合AbortController管理任务生命周期,使cancelJob可中断、terminate()可批量取消所有进行中的任务。

事件广播与定向推送

容器在connect中保存(clientId → broadcast)映射,即可实现三类广播:

  • 全员广播:遍历映射逐一调用 broadcast;
  • 定向推送:如通知容器,为每个订阅者保存自定义过滤器(filter),广播前按类型、优先级等条件匹配,实现"仅推送感兴趣的客户端";
  • 连接/断开通知:在connect/disconnect中向其他在线客户端广播上下线事件。

状态管理

  • 内存态:适合会话类容器,可用Map存储并维护lastActivity实现会话超时判断(如 30 分钟无活动判定为 inactive);
  • 持久态:容器持数据库连接,写操作先更新缓存再异步落库,读操作缓存优先、未命中回源数据库;terminate()中必须 flush 未完成写入并关闭连接。

错误处理分层

将异常分类为ValidationErrorNotFoundErrorPermissionError与通用内部错误,向客户端返回统一结构的{ success: false, error: 'validation' | 'not_found' | 'permission_denied' | 'internal_error', message, fields? };开发环境可透出原始错误消息,生产环境则收敛为通用提示。

测试容器

单元测试直接实例化容器并调用request断言结果与异常:

it('should add numbers', async () => { const result = await container.request('add', { a: 2, b: 3 }) expect(result).toEqual({ result: 5 }) }) it('should handle division by zero', async () => { await expect(container.request('divide', { a: 10, b: 0 })).rejects.toThrow('Division by zero') })

集成测试则启动真实 TickManager、Network,通过serveAgent注册工厂后再经客户端跨网络调用,验证请求-响应全链路(参见 CONTAINER_DEVELOPMENT 的 Integration Tests 小节)。

最佳实践清单

  1. 校验一切入参(非空字符串、邮箱格式等);
  2. 使用 TypeScript 强类型定义请求/响应结构(data as CreateUserRequest);
  3. 结构化日志:记录容器 UUID、操作名、clientId、耗时与错误;
  4. terminate()严格按序执行:停止接收新请求 → 等待进行中的操作 → 通知客户端 → 关闭连接 → 清理状态;
  5. 用 JSDoc 文档化容器的操作与事件契约;
  6. 常见模式:单例容器用无状态容器 + HA 实现;依赖注入通过工厂static async create(uuid)组装;资源密集场景用容器池(ContainerPool)复用实例。

五、客户端自动释放(Auto-Disposal)

Auto-Disposal Guide 讲解NetworkClientWithAgents对 JavaScript 显式资源管理提案(Symbol.dispose/Symbol.asyncDispose)的实现。用法是await using client = createNetworkClient(...),其自动清理触发时机包括:代码块结束、抛出异常、函数提前 return。

适用场景(✅ 使用await using:短生命周期脚本与示例、测试用例、纯客户端应用、临时请求-响应模式。

禁用场景(❌ 不要使用):需要长期保持连接的服务、通过serveAgent()托管 Agent/容器的应用、应无限期运行的生产服务器、持续处理作业的后台 Worker。

// ✅ 短脚本:函数返回即自动 close async function fetchData() { await using client = createNetworkClient('localhost:3737') await client.waitConnection(5000) const container = await client.get('my-service' as ContainerKind, {}) return container.request('getData') } // ❌ 反例:长服务用 await using,函数返回后连接被释放,服务立刻停止! async function startService() { await using client = createNetworkClient('localhost:3737') await client.serveAgent('localhost:3738', factories) // 函数返回即被释放——服务停止! }

长服务应持有强引用,在SIGTERM/SIGINT信号处理器中手动调用client.close()。旧代码迁移也很简单:把try { ... } finally { await client.close() }直接替换为await using client = ...即可。

六、高可用:无状态容器的自动故障转移

网络服务器本身单实例、是单点故障(SPOF),但Agent 与容器可通过无状态注册实现完整 HA,这是 HA_STATELESS_CONTAINERS 与 QUICKSTART_HA 的核心内容。

工作原理

多个 Agent 可预置同一 UUID的容器实例并竞争注册:

  1. 网络采用first-wins 策略:第一个注册该 UUID 的 Agent 成为主节点,其余注册被拒绝;
  2. 被拒绝的 Agent 终止其副本(或保持待命);
  3. 主容器终止/失败时,网络广播移除事件;
  4. 备用 Agent 收到事件后延迟约 100ms 重新注册(节流防惊群),第一个重新注册成功者接管。

推荐 API:serveAgent的第三个参数

生产代码应优先使用serveAgent的无状态容器工厂参数(不要直接调用agent.addStatelessContainer):

import { createNetworkClient, containerOnAgentEndpointRef } from '@hcengineering/network-client' const sharedUUID = 'my-service-001' as ContainerUuid const client = createNetworkClient('localhost:3737') await client.waitConnection() // Agent 1(主) await client.serveAgent('localhost:3801', {}, (agentEndpoint) => [ { uuid: sharedUUID, kind: 'my-service' as ContainerKind, endpoint: containerOnAgentEndpointRef(agentEndpoint, sharedUUID), container: new MyService(sharedUUID) } ]) // Agent 2(备)——同一 UUID await client.serveAgent('localhost:3802', {}, (agentEndpoint) => [ { uuid: sharedUUID, kind: 'my-service' as ContainerKind, endpoint: containerOnAgentEndpointRef(agentEndpoint, sharedUUID), container: new MyService(sharedUUID) } ])

监控故障转移

通过client.onUpdate监听容器事件:

client.onUpdate(async (event) => { for (const containerEvent of event.containers) { if (containerEvent.container.uuid === SHARED_SERVICE_UUID) { switch (containerEvent.event) { case NetworkEventKind.added: console.log('已注册:', containerEvent.container.agentId); break case NetworkEventKind.removed: console.log('容器移除——故障转移进行中'); break case NetworkEventKind.updated: console.log('容器更新'); break } } } })

典型应用场景

  • Leader 选举:所有节点注册同一cluster-${clusterId}-leaderUUID,先到者成为 leader,无需外部协调服务;
  • 单例服务:如数据库迁移,全集群仅一个实例执行migrate
  • 主备数据库:备用副本在接管时通过onActivation()提升为 master。

已知限制(务必知晓)

  1. 无 split-brain 防护:网络分区时可能同时出现两个"活动"实例;
  2. 最终一致:故障转移期间存在短暂无实例窗口(约 100ms + 网络延迟);
  3. 无状态转移:实例间不自动同步状态;
  4. 依赖单一网络实例:所有 Agent 必须连接同一个 Huly Network。

最佳实践:UUID 命名要有意义且跨部署一致、容器实现完善的ping()、备用方优雅处理注册被拒、始终订阅事件以跟踪故障转移、在非生产环境定期演练故障转移、按 SLA 设置超时。

七、多租户架构

Multi-Tenant Architectures 阐述如何基于 kind、labels 与引用管理实现天然的多租户隔离。

三种隔离模式

模式做法优点缺点
租户每容器每租户独立容器实例完全隔离、易于计量、可逐租户扩容容器数量多、资源开销高
共享容器 + 租户过滤数据按 tenantId 过滤容器少、资源利用率高、易管理隔离依赖代码纪律,有泄露风险
混合模式公共操作共享、敏感数据专属兼顾成本与安全架构复杂

租户标识的三种方式

  1. 标签法labels: ['tenant-id:acme-corp', 'tier:enterprise']——容器级隔离的首选;
  2. extra 参数extra: { tenantId: 'acme-corp', tier: 'enterprise', region: 'us-west' }
  3. 请求时携带:每次request都带上tenantId并在容器内校验。

推荐组合方案(纵深防御):容器级用 label 隔离 + 请求级校验 tenantId 与容器归属一致。

数据隔离实现

  • 数据库级:每个租户独立库/模式(tenant_${tenantId});
  • 行级安全:共享库时强制追加WHERE tenant_id = ?
  • 内存级Map<tenantId, Map<key, value>>按租户分桶缓存。

资源管理与安全

  • 配额TenantQuota(maxDocuments、maxUsers、maxStorageBytes、maxRequestsPerSecond)在操作前检查、操作后更新用量,超额返回quota_exceeded
  • 限流:按 tier 配置 token 桶速率(如 enterprise 1000 req/s、免费 100 req/s),超出返回rate_limit_exceeded
  • 防数据泄露:校验租户访问权限、核对 tenantId 与容器一致、响应返回前按 tenantId 过滤(sanitize);
  • 审计日志:记录每次请求的时间戳、租户、客户端、操作、状态与耗时;
  • 计费计量:在容器内累计 requests / computeTime / storageBytes,周期性上报计费系统(如每 1000 次请求上报一次)。

完整的 SaaS 多租户示例见 examples/03-multi-tenant.ts。

八、生产部署指南

Production Deployment Guide 覆盖从预部署检查到持续运维的完整链路。

部署架构要点

  • 网络服务器:仅 1 个活动实例,其余为备用(active-passive,快速接管);必须用进程监控(systemd / PM2 / Kubernetes restart 策略)保证快速重启;
  • Agent:每个容器 kind 建议 3+ 副本并跨可用区分布,按负载自动伸缩;
  • 监控:集中式日志、指标采集与告警。

Docker Compose 部署

docker-compose.yml定义网络服务器与多个 Agent 服务(完整配置见文档)。关键片段:

services: network-server: image: hardcoreeng/network-pod:latest restart: unless-stopped ports: - '3737:3737' environment: - NODE_ENV=production - NETWORK_PORT=3737 - LOG_LEVEL=info healthcheck: test: ['CMD', 'curl', '-f', 'http://localhost:3737/health'] interval: 30s timeout: 10s retries: 3

Agent 使用基于node:22-alpine的 Dockerfile 构建,带HEALTHCHECK。常用运维命令:

docker-compose up -d docker-compose logs -f docker-compose up -d --scale agent-1=3 # 水平扩容 docker-compose down

Kubernetes 部署

网络服务器 Deployment(replicas: 2仅用于快速接管,同一时刻只有一个实例处于活动状态),配 liveness/readiness 探针与资源配额;Agent 使用 Deployment + HPA 自动伸缩(minReplicas: 4, maxReplicas: 20,CPU 70% / 内存 80% 阈值):

kubectl create namespace huly-network kubectl apply -f k8s/network-deployment.yaml -n huly-network kubectl apply -f k8s/agent-deployment.yaml -n huly-network kubectl logs -f deployment/huly-agents -n huly-network kubectl scale deployment huly-agents --replicas=10 -n huly-network

配置参数

环境变量(网络服务器):

NODE_ENV=production NETWORK_PORT=3737 NETWORK_BIND_ADDRESS=0.0.0.0 ALIVE_TIMEOUT=3 # 秒 PING_INTERVAL=1 # 秒 CONTAINER_TIMEOUT=60 # 秒 TICK_RATE=1000 LOG_LEVEL=info

配置文件(config/production.json:network(port、bindAddress、aliveTimeout、pingInterval、containerTimeout)、agent(maxContainers、memoryLimit、healthCheckInterval)、logging(level、format、destination)、monitoring(enabled、metricsPort、tracingEnabled)。

注意:上文源码 timeouts.ts 中的默认值为aliveTimeout: 3pingInterval: 1unusedContainerTimeout: 5(秒),生产配置应在此基础上按 SLA 调整。

监控、日志与健康检查

  • Prometheus 指标:用prom-client暴露/metrics,推荐指标:huly_requests_total(按 operation/status 计数)、huly_request_duration_seconds(直方图)、huly_active_containers(按 kind 的活跃容器数);
  • 结构化日志:winston JSON 格式,Console + error.log + combined.log 多传输端;
  • 健康检查healthcheck.jscreateNetworkClient连接并执行client.list(),成功退出码 0,失败退出码 1。

安全加固

  1. 生产启用 TLS(证书/私钥注入);
  2. 防火墙只开放必要端口(如ufw allow 3737/tcpufw allow 3738:3800/tcp、其余deny);
  3. 实现客户端认证(继承NetworkServer校验 token);
  4. 容器以最小权限运行、K8s 使用 securityContext、镜像漏洞扫描、限流与入参校验。

性能调优与备份

  • 调大TickManagerImpl的 tick 率(如 10000 ticks/sec)以降低延迟;调整aliveTimeout/containerTimeout适配生产;
  • Agent 限制并发容器数(如 maxContainers=100)、必要时预暖容器;
  • 容器内用连接池(如createPool({ max: 10 }))复用数据库连接;
  • 状态备份:周期性调用container.exportState()并落盘;恢复时container.importState(state)重建实例。

故障排查速查

  • 网络服务器无法启动lsof -i :3737查端口占用、查看/var/log/huly/error.log、核对config/production.json
  • Agent 连不上telnet network-server 3737docker logs huly-agent-1nslookup network-server
  • 内存占用高kubectl top pods -n huly-network并适当kubectl scale
  • 滚动更新kubectl set image deployment/huly-network network=hardcoreeng/network-pod:v2.0.0
  • 优雅停机:在SIGTERM中执行server.close()→ 等待在途操作 →tickManager.stop()→ 退出。

九、文档导航与源码对照

本文内容完整继承自 foundations/net/docs 文档集,可按需深入阅读各专题:

  • 入门:快速开始、核心概念;
  • 开发:容器开发指南、自动释放指南;
  • 进阶:HA 无状态容器、HA 快速上手、多租户架构;
  • 生产:生产部署指南。

对应的源码与可运行示例位于:

  • 核心类型与网络实现:packages/core(容器接口 containers.ts、网络实现 network.ts、超时默认值 api/timeouts.ts);
  • 客户端与 Agent:packages/client(client.ts);
  • 网络服务端:packages/server;
  • 完整示例:examples,包含基础请求-响应、事件广播、多租户、生产级完整配置、错误处理重试、自定义超时与 HA 无状态容器示例。

推荐的阅读顺序:初学者按 快速开始 → 核心概念 → 容器开发;应用开发者按 容器开发 → 多租户 → 自动释放;DevOps 按 生产部署 → HA;系统架构师按 核心概念 → HA → 生产部署 → 集成模式。在动手实现前,请始终牢记那条贯穿全篇的铁律——网络服务器单实例运行,并据此设计进程监控与故障恢复方案。

【免费下载链接】platformHuly — All-in-One Project Management Platform (alternative to Linear, Jira, Slack, Notion, Motion)项目地址: https://gitcode.com/GitHub_Trending/platform80/platform

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 19:44:23

灯光模拟HarmonyOS应用实战-92-科二做到一半切分类为何会立刻换一套题:用PracticeTransitionReceipt处理放弃与重建

灯光模拟HarmonyOS应用实战-92-科二做到一半切分类为何会立刻换一套题&#xff1a;用PracticeTransitionReceipt处理放弃与重建 科二灯光基础页顶部有“图标认知”“上车检查”“夜间场景”三个分类。用户做到了第十二题&#xff0c;想看一眼另一个分类&#xff0c;点下标签后会…

作者头像 李华
网站建设 2026/9/11 19:42:08

树莓派Pico W + MicroPython + MQTT + EMQX 环境监测实战

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

作者头像 李华
网站建设 2026/9/11 19:41:52

thinkPHP互助理财源码解密与改造实战:从XXTEA到自动匹配

简介&#xff1a;基于thinkPHP开发的共赢天下互助平台理财源码&#xff0c;面向互助众筹、理财拆分类项目的开发者与运营者&#xff0c;适配PC与WAP端&#xff0c;手机端可打包为APP。系统集成激活码、排单、自动匹配、奖金分配、经理人及分拆等模块&#xff0c;功能完整&#…

作者头像 李华
网站建设 2026/9/11 19:41:42

SpringBoot音乐网站架构设计与性能优化实践

1. 项目背景与核心需求音乐网站作为数字娱乐领域的基础设施&#xff0c;其技术架构直接影响用户体验和运营效率。基于SpringBoot的开发模式&#xff0c;能够快速构建高可用的音乐服务平台。这类项目通常需要解决以下几个核心问题&#xff1a;海量音频文件的高效存储与快速检索用…

作者头像 李华
网站建设 2026/9/11 19:40:56

品牌推广与企业推广:AI搜索时代,谁才是真正的“优先投资项”?

品牌推广与企业推广&#xff1a;AI搜索时代&#xff0c;谁才是真正的“优先投资项”&#xff1f;一场被混淆了二十年的认知错位2026年&#xff0c;一个关于企业传播的根本性命题正在被重新审视——当AI搜索成为用户获取信息的第一入口&#xff0c;企业究竟应该优先推广“品牌”…

作者头像 李华
网站建设 2026/9/11 19:40:27

HDF框架与HCS配置详解:OpenHarmony驱动开发实战指南

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

作者头像 李华