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(网络核心类型、NetworkImpl、TickManagerImpl、AgentImpl与容器接口)、server(NetworkServer网络服务端)、client(createNetworkClient、NetworkAgentServer、serveAgent)以及 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 再路由到其托管的容器实例。其五大关键原则为:
- 集中协调:网络服务器统一协调所有 Agent 与容器;
- 分布式执行:容器运行在可跨机器分布的 Agent 上;
- 动态发现:客户端通过网络动态发现并连接容器;
- 自动生命周期:网络基于客户端引用自动管理容器生命周期;
- 容错:失败 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.uuid、options.extra、options.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' } })四种通信模式
- 请求/响应(同步):
const result = await ref.request('processData', { value: 42 }); - 即发即忘(异步):调用
request但不等待响应语义,适合日志、埋点; - 事件广播(发布/订阅):
const connection = await ref.connect()后设置connection.on = async (event) => {...},容器端通过broadcast回调向所有已连接客户端推送事件; - 双向流式通信:在
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)解析出kind、host、port、uuid、agentId等字段。
容器 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 未完成写入并关闭连接。
错误处理分层
将异常分类为ValidationError、NotFoundError、PermissionError与通用内部错误,向客户端返回统一结构的{ 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 小节)。
最佳实践清单
- 校验一切入参(非空字符串、邮箱格式等);
- 使用 TypeScript 强类型定义请求/响应结构(
data as CreateUserRequest); - 结构化日志:记录容器 UUID、操作名、clientId、耗时与错误;
terminate()严格按序执行:停止接收新请求 → 等待进行中的操作 → 通知客户端 → 关闭连接 → 清理状态;- 用 JSDoc 文档化容器的操作与事件契约;
- 常见模式:单例容器用无状态容器 + 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的容器实例并竞争注册:
- 网络采用first-wins 策略:第一个注册该 UUID 的 Agent 成为主节点,其余注册被拒绝;
- 被拒绝的 Agent 终止其副本(或保持待命);
- 主容器终止/失败时,网络广播移除事件;
- 备用 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。
已知限制(务必知晓)
- 无 split-brain 防护:网络分区时可能同时出现两个"活动"实例;
- 最终一致:故障转移期间存在短暂无实例窗口(约 100ms + 网络延迟);
- 无状态转移:实例间不自动同步状态;
- 依赖单一网络实例:所有 Agent 必须连接同一个 Huly Network。
最佳实践:UUID 命名要有意义且跨部署一致、容器实现完善的ping()、备用方优雅处理注册被拒、始终订阅事件以跟踪故障转移、在非生产环境定期演练故障转移、按 SLA 设置超时。
七、多租户架构
Multi-Tenant Architectures 阐述如何基于 kind、labels 与引用管理实现天然的多租户隔离。
三种隔离模式
| 模式 | 做法 | 优点 | 缺点 |
|---|---|---|---|
| 租户每容器 | 每租户独立容器实例 | 完全隔离、易于计量、可逐租户扩容 | 容器数量多、资源开销高 |
| 共享容器 + 租户过滤 | 数据按 tenantId 过滤 | 容器少、资源利用率高、易管理 | 隔离依赖代码纪律,有泄露风险 |
| 混合模式 | 公共操作共享、敏感数据专属 | 兼顾成本与安全 | 架构复杂 |
租户标识的三种方式
- 标签法:
labels: ['tenant-id:acme-corp', 'tier:enterprise']——容器级隔离的首选; - extra 参数:
extra: { tenantId: 'acme-corp', tier: 'enterprise', region: 'us-west' }; - 请求时携带:每次
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: 3Agent 使用基于node:22-alpine的 Dockerfile 构建,带HEALTHCHECK。常用运维命令:
docker-compose up -d docker-compose logs -f docker-compose up -d --scale agent-1=3 # 水平扩容 docker-compose downKubernetes 部署
网络服务器 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: 3、pingInterval: 1、unusedContainerTimeout: 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.js用createNetworkClient连接并执行client.list(),成功退出码 0,失败退出码 1。
安全加固
- 生产启用 TLS(证书/私钥注入);
- 防火墙只开放必要端口(如
ufw allow 3737/tcp、ufw allow 3738:3800/tcp、其余deny); - 实现客户端认证(继承
NetworkServer校验 token); - 容器以最小权限运行、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 3737、docker logs huly-agent-1、nslookup 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),仅供参考