部署模式
server 可以运行成一个 standalone registry,也可以运行成一个发现 peer、参与选主、并把本地 clients 镜像到当前主节点的 cluster 成员。
CLI 默认会以 auto 模式在 47372 这个端口启动。
Standalone
当一个 server 同时持有本地 registry 和 bridge surface 时,使用 standalone 模式。
npx @modeldriveprotocol/server --port 47372 --server-id hub适合这些情况:
- 你只需要一个本地 MDP server
- clients 可以直接注册到 bridge-facing server
- 你希望本地部署尽量简单
Auto
Auto 模式会先探测已有的 MDP peer。找到当前主节点后就把本地 clients 向上镜像;找不到时,会进入 cluster 控制面并允许自己参与选主。
npx @modeldriveprotocol/server --cluster-mode auto --server-id edge-01默认发现流程会:
- 探测
127.0.0.1 - 从
47372开始 - 最多检查连续
100个端口 - 通过
GET /mdp/meta判断某个端口是不是 MDP 服务 - 在真正建立 proxy 链路之前,先确认远端元数据里声明了兼容的 protocol 版本
peer 建链之后,cluster manager 会通过下面这些机制维持一致性:
- 主节点通过 cluster control websocket 发送 heartbeat
- 从节点通过 lease 避免过早提升
- lease 超时后,通过带 term 的随机化 election 选出新主节点
- 主节点优雅关闭时主动发送 resign,让从节点可以立刻重新选主
- 主节点会持续检查自己是否还握有 quorum;如果已经变成孤岛,就会主动退位
- 可选的静态 membership,让 quorum 不只是依赖 discovery 过程中学到的 sticky peers,还可以依赖显式声明的 server id 集合
- cluster identity 校验,避免两个互不相关的 server 组因为运行在同一台机器上或恰好使用了重叠的 server id 而串群
需要时可以手动调参:
npx @modeldriveprotocol/server \
--cluster-mode auto \
--cluster-id local-dev \
--cluster-members node-a,node-b,node-c \
--discover-host 127.0.0.1 \
--discover-start-port 47372 \
--discover-attempts 100 \
--server-id edge-01设置了 --cluster-members 之后,cluster 会用这组显式 server id 来做 quorum 计算和 peer 准入。网络里即使存在别的未知 peer,它们也不会自动进入控制面,更不会被计入选主多数派。 设置了 --cluster-id 之后,discovery 和控制面还会额外校验逻辑 cluster identity。默认值会根据 --discover-host 和 --discover-start-port 推导出来。 同一个 cluster 里的每个 --server-id 都必须唯一。如果另一个 endpoint 在同一个 cluster.id 下宣告了相同的 serverId,当前节点会把它当成硬错误,而不是继续猜哪个 peer 才是正确的。
Proxy-Required
Proxy-required 是 auto 的严格版本,但这个约束只发生在启动阶段。server 启动时必须至少找到一个已有 cluster peer,否则直接启动失败。
npx @modeldriveprotocol/server \
--cluster-mode proxy-required \
--discover-host 127.0.0.1 \
--discover-start-port 47372 \
--discover-attempts 100 \
--server-id edge-02适合这些情况:
- 这个 server 绝不能意外成为根 bridge
- 你的部署明确要求先有一个 cluster
- 启动时应该快速失败,而不是悄悄切换拓扑
显式指定上游
如果你已经知道其中一个 peer 的 URL,就直接跳过扫描,把它作为 cluster join 的 seed。
npx @modeldriveprotocol/server \
--port 47170 \
--cluster-mode proxy-required \
--upstream-url ws://127.0.0.1:47372 \
--server-id edge-01这对脚本、测试和固定的本地开发环境是最可预测的方式。完成初次加入后,这个 server 仍会继续参与 term / lease / election。
Cluster Manifest
如果你希望 cluster identity、成员集合和 discovery 默认值可以跨重启保留下来,而不是每次都写一长串 CLI 参数,可以把它们放进一个 JSON manifest,然后通过 --cluster-config 加载。
示例 manifest:
{
"clusterId": "local-dev",
"clusterMembers": ["node-a", "node-b", "node-c"],
"discoverHost": "127.0.0.1",
"discoverStartPort": 47372,
"discoverAttempts": 100,
"upstreamUrl": "ws://127.0.0.1:47372"
}启动方式:
npx @modeldriveprotocol/server \
--cluster-config ./mdp-cluster.json \
--server-id node-amanifest 只提供默认值。显式 CLI 参数仍然优先生效,所以多个节点可以复用同一份 manifest,只覆盖各自的 --server-id、--port,或者在需要时覆盖成不同的 --cluster-id。
探针接口
发现流程使用的元数据探针是:
GET /mdp/meta
返回示例:
{
"protocol": "mdp",
"protocolVersion": "2.0.0",
"supportedProtocolRanges": ["^2.0.0"],
"serverId": "127.0.0.1:47372",
"endpoints": {
"ws": "ws://127.0.0.1:47372",
"httpLoop": "http://127.0.0.1:47372/mdp/http-loop",
"auth": "http://127.0.0.1:47372/mdp/auth",
"meta": "http://127.0.0.1:47372/mdp/meta",
"cluster": "ws://127.0.0.1:47372/mdp/cluster"
},
"features": {
"upstreamProxy": true,
"clusterControl": true
},
"cluster": {
"id": "127.0.0.1:47372",
"membershipMode": "dynamic",
"membershipFingerprint": "dynamic",
"role": "leader",
"term": 3,
"leaderId": "127.0.0.1:47372",
"leaderUrl": "ws://127.0.0.1:47372",
"leaseDurationMs": 4000,
"knownMemberCount": 3,
"reachableMemberCount": 3,
"quorumSize": 2,
"hasQuorum": true
}
}这个接口服务于部署控制平面逻辑,不是一个 MDP wire message。一个 server 决定是否向另一个 server 建立 proxy 关系时,应把 protocolVersion 视为精确 semver,把 supportedProtocolRanges 视为 semver range 列表。cluster 这一块则是当前控制面的实时视图,从节点会用它来确认谁是当前主节点。cluster.id 是最先要检查的隔离字段,如果它和期望的逻辑 cluster 不一致,这个 peer 就应该被忽略或拒绝。cluster.membershipMode 和 cluster.membershipFingerprint 是下一层兼容性检查:如果一组静态节点对成员集合的理解不一致,它们会直接拒绝互联,而不是在不同 quorum 规则下继续运行。新增的 quorum 字段主要用于诊断:knownMemberCount 是 sticky 的内存成员集合大小,reachableMemberCount 是当前节点本地看到的可达成员视图,hasQuorum 表示这个节点现在是否还能看到多数派。
如果要看精确的 CLI 参数和启动语法,继续阅读 CLI 参数。
还要注意两个明确边界:
- cluster 能重新选出新的主节点继续做路由,但不会复制活跃中的 client session。主节点 failover 之后,clients 仍然需要重新连接到新的主节点。
- membership 在单个进程生命周期内是 sticky 的。某个 peer 一旦进入当前进程的内存成员集合,quorum 不会因为 discovery 暂时看不到它就自动缩小。
- 如果你希望跨重启和拓扑抖动都维持稳定的 quorum 定义,优先使用
--cluster-members,把成员集合显式配置出来,而不是完全交给 discovery 推断。 - 如果你使用了
--cluster-members,同一个逻辑 cluster 里的每个节点都应该使用完全一致的成员集合。静态 membership fingerprint 不一致的节点会互相拒绝。 - 如果你会在同一台机器或同一网段上跑多个独立的 MDP cluster,显式设置
--cluster-id,避免它们意外互联。 - 之后如果 quorum 又恢复了,cluster 可以重新收敛并选出新的主节点,但这个恢复仍然只覆盖路由状态,不会恢复旧主节点上的活跃 client session。