cherryDiscovery

package
v1.5.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 27, 2026 License: MIT Imports: 14 Imported by: 3

README

Discovery 发现服务

集群节点自动发现与成员管理,支持多种后端实现。

架构

IDiscovery (业务接口)
├── ComponentDefault (基类)     — 成员存储 + listener 通知
│   ├── ComponentMaster (nats)  — NATS 主从模式
│   └── Component (etcd)        — etcd 分布式模式 (独立仓库)
模式 Mode 值 适用场景
default 读取 profile 配置 单进程开发/测试
nats NATS 主从发现 多节点生产环境
etcd etcd lease + watch 多节点生产环境,依赖 etcd

Install

import cherryDiscovery "github.com/cherry-game/cherry/net/discovery"

Quick Start

default 模式(开发测试)

在 profile 中配置节点信息,无需额外部署:

{
    "cluster": {
        "discovery": {
            "mode": "default"
        }
    },
    "node": {
        "game": [
            {
                "node_id": "game-1",
                "rpc_address": "127.0.0.1:10001",
                "__settings__": {
                    "region": "us-west"
                }
            }
        ],
        "gate": [
            {
                "node_id": "gate-1",
                "rpc_address": "127.0.0.1:20001"
            }
        ]
    }
}
nats 模式(生产环境)

启动 master 节点:

master 负责接收注册、心跳检测、广播成员变更。

{
    "cluster": {
        "discovery": {
            "mode": "nats"
        },
        "nats": {
            "prefix": "node",
            "master_node_id": "master-1"
        }
    }
}

启动 worker 节点:

worker 向 master 注册并定期发送心跳。

{
    "cluster": {
        "discovery": {
            "mode": "nats"
        },
        "nats": {
            "prefix": "node",
            "master_node_id": "master-1"
        }
    }
}

master_node_id 必须与运行 master 的节点 node_id 一致。

NATS 协议流程

1. 先启动 master 节点
2. Worker 启动 → NATS Request  → master 收到 register
3. Master 回复完整成员列表 + NATS Publish add 广播新成员
4. Worker 定期心跳 (1s) → master 心跳超时 (3s) → 移除 + RemoveMember 广播
5. Worker 退出 → NATS Publish remove → 所有节点移除该成员

NATS subject 格式:cherry.<prefix>.discovery.<masterID>.<type>

Type 方向 说明
register Worker→Master 注册请求,携带自身 Member 数据
add Master→Worker 新成员广播
update 双向 Settings 变更广播
remove 双向 成员移除广播
heartbeat Worker→Master 心跳,Master 更新 LastAt 或回复 registerRequired 触发重新注册

业务层 API (IDiscovery)

discovery := app.Discovery()

// 成员查询
all := discovery.Map()                           // 所有成员
games := discovery.ListByType("game")            // 按类型过滤
games := discovery.ListByType("game", "self")    // 排除指定节点
member, ok := discovery.Random("gate")           // 随机选取
member, ok := discovery.GetMember("node-id")     // 按 ID 查找

// Settings 同步(更新当前节点,自动同步到其它节点)
discovery.UpdateSetting("region", "us-east")
discovery.UpdateSettings(map[string]string{"region": "us-east", "zone": "a"})

// 成员变更监听
discovery.OnAddMember(func(member IMember) {
    // 新节点加入
})
discovery.OnUpdateMember(func(member IMember) {
    // 节点 settings 变更
})
discovery.OnRemoveMember(func(member IMember) {
    // 节点离开
})

实现自定义后端

方式一:直接实现 IDiscovery
type MyDiscovery struct {
    cfacade.Component
}

func (m *MyDiscovery) Mode() string { return "my-mode" }
func (m *MyDiscovery) Init() { /* ... */ }
// ... 实现 IDiscovery 全部方法
方式二:组合 ComponentDefault

复用 memberMap 存储和 listener 通知逻辑,只需关注传输层:

type MyDiscovery struct {
    cherryDiscovery.ComponentDefault
    thisMember *cproto.Member
}

func (m *MyDiscovery) Mode() string { return "my-mode" }

func (m *MyDiscovery) Init() {
    m.thisMember = cherryDiscovery.NewMemberWithApp(m.App())
    m.AddMember(m.thisMember)
    // 初始化传输层...
}

func (m *MyDiscovery) UpdateSetting(key, value string) {
    m.thisMember.UpdateSetting(key, value)
    // 通过传输层广播变更...
}

注册:

func init() {
    cherryDiscovery.Register(&MyDiscovery{})
}

配置参考

cluster.discovery
参数 类型 默认值 说明
mode string - 发现服务模式:default / nats / etcd
cluster.nats (nats 模式)
参数 类型 默认值 说明
prefix string "node" NATS subject 前缀
master_node_id string - master 节点 ID(必须与运行的 master 节点 node_id 一致)
cluster.etcd (etcd 模式,独立仓库)

components/etcd

Documentation

Overview

Package cherryDiscovery provides cluster node discovery for the Cherry framework.

It supports multiple discovery backends via the IDiscovery interface:

  • "default" mode: reads node topology from the profile config file (dev/test use)
  • "nats" mode: master-based discovery over NATS messaging
  • "etcd" mode: distributed discovery via etcd (maintained in a separate repository)

Custom backends can be registered via Register() and selected via the "cluster.discovery.mode" property in the profile configuration file.

Index

Constants

View Source
const (
	ConfigKeyNode       = "node"
	ConfigKeyNodeID     = "node_id"
	ConfigKeyRPCAddress = "rpc_address"
	ConfigKeySettings   = "__settings__"
)

Config keys used to parse node information from the profile file.

Variables

This section is empty.

Functions

func GetDiscovery added in v1.5.0

func GetDiscovery(mode string) (cfacade.IDiscoveryComponent, error)

GetDiscovery looks up a registered discovery component by mode name.

func GetMode added in v1.5.0

func GetMode() (string, error)

GetMode reads the discovery mode from the profile configuration. The config path is "cluster.discovery.mode".

func New added in v1.3.0

New creates a discovery component based on the profile configuration. It reads the mode from "cluster.discovery.mode" and instantiates the corresponding registered component. Panics via log.Fatal on missing config or unknown mode.

func NewMemberWithApp added in v1.5.0

func NewMemberWithApp(app cfacade.IApplication) *cproto.Member

NewMemberWithApp creates a *cproto.Member populated from the application's node identity. HeartbeatTimeout is read from the "cluster_heartbeat_timeout" setting (default 3s).

func Register added in v1.3.0

func Register(component cfacade.IDiscoveryComponent)

Register adds a discovery component implementation to the registry. Panics via log.Fatal if component is nil or its Mode() returns empty.

Types

type ComponentDefault added in v1.5.0

type ComponentDefault struct {
	cfacade.Component
	// contains filtered or unexported fields
}

ComponentDefault is a file-based discovery implementation for development/testing. It reads node information directly from the profile configuration file (profile.json->node).

Fields:

  • memberMap: stores all known cluster members keyed by nodeID (sync.Map for concurrent access)
  • onAddListener: callbacks invoked when a new member is added via AddMember()
  • onUpdateListener: callbacks invoked when an existing member is updated via UpdateMember()
  • onRemoveListener: callbacks invoked when a member is removed via RemoveMember()

This implementation is designed as a composable base: other backends (nats, etcd) embed ComponentDefault to reuse the member storage and listener notification logic.

func (*ComponentDefault) AddMember added in v1.5.0

func (n *ComponentDefault) AddMember(member cfacade.IMember)

AddMember inserts a member into the local member table. If the member already exists, logs a debug message but still notifies add listeners. Otherwise stores the new member and notifies all onAddListener callbacks.

func (*ComponentDefault) GetMember added in v1.5.0

func (n *ComponentDefault) GetMember(nodeID string) (cfacade.IMember, bool)

GetMember looks up a member by nodeID. Returns nil, false if not found or nodeID is empty.

func (*ComponentDefault) GetType added in v1.5.0

func (n *ComponentDefault) GetType(nodeID string) (nodeType string, err error)

GetType returns the node type for the given nodeID.

func (*ComponentDefault) Init added in v1.5.0

func (n *ComponentDefault) Init()

Init loads node configuration from the profile file. sync.Map is usable in its zero value, no explicit initialization needed.

func (*ComponentDefault) ListByType added in v1.5.0

func (n *ComponentDefault) ListByType(nodeType string, filterNodeID ...string) []cfacade.IMember

ListByType returns members of the given nodeType, excluding any nodes listed in filterNodeID.

func (*ComponentDefault) Map added in v1.5.0

func (n *ComponentDefault) Map() map[string]cfacade.IMember

Map returns a snapshot of all known members as a plain map.

func (*ComponentDefault) Mode added in v1.5.0

func (n *ComponentDefault) Mode() string

func (*ComponentDefault) Name added in v1.5.0

func (*ComponentDefault) Name() string

func (*ComponentDefault) OnAddMember added in v1.5.0

func (n *ComponentDefault) OnAddMember(listener cfacade.MemberListener)

OnAddMember registers a listener that is called after a member is added via AddMember(). Nil listeners are silently ignored.

func (*ComponentDefault) OnRemoveMember added in v1.5.0

func (n *ComponentDefault) OnRemoveMember(listener cfacade.MemberListener)

OnRemoveMember registers a listener that is called after a member is removed via RemoveMember(). Nil listeners are silently ignored.

func (*ComponentDefault) OnUpdateMember added in v1.5.0

func (n *ComponentDefault) OnUpdateMember(listener cfacade.MemberListener)

OnUpdateMember registers a listener that is called when an existing member is updated via UpdateMember(). Nil listeners are silently ignored.

func (*ComponentDefault) Random added in v1.5.0

func (n *ComponentDefault) Random(nodeType string) (cfacade.IMember, bool)

Random returns a random member of the given nodeType. Returns nil, false if no members of that type exist.

func (*ComponentDefault) RemoveMember added in v1.5.0

func (n *ComponentDefault) RemoveMember(nodeID string)

RemoveMember deletes a member from the local member table by nodeID. If the member existed, notifies all onRemoveListener callbacks.

func (*ComponentDefault) UpdateMember added in v1.5.0

func (n *ComponentDefault) UpdateMember(member *cproto.Member)

UpdateMember updates an existing member in the local member table. If the member doesn't exist, it is stored but no update listeners are notified. If the member exists, the stored value is replaced and onUpdateListener callbacks fire.

func (*ComponentDefault) UpdateSetting added in v1.5.0

func (n *ComponentDefault) UpdateSetting(key, value string)

UpdateSetting updates a single setting on the local node's member entry and notifies OnUpdateMember listeners. If the local node is not in the member map (e.g. before Init completes), the call is silently ignored.

Backends with a transport layer (nats, etcd) override this method to also broadcast the change to other nodes.

func (*ComponentDefault) UpdateSettings added in v1.5.0

func (n *ComponentDefault) UpdateSettings(settings map[string]string)

UpdateSettings updates multiple settings on the local node's member entry and notifies OnUpdateMember listeners once. If the local node is not in the member map, the call is silently ignored.

Backends with a transport layer (nats, etcd) override this method to also broadcast the change to other nodes.

type ComponentMaster added in v1.5.0

type ComponentMaster struct {
	ComponentDefault
	// contains filtered or unexported fields
}

ComponentMaster implements NATS-based master/worker discovery.

Protocol overview:

  1. Start a single master node first.
  2. Worker nodes send a register message (cherry.<prefix>.discovery.<masterID>.register) to the master.
  3. The master replies with the full member list and broadcasts the new member via add subject.
  4. Workers periodically send heartbeat messages; the master removes members that time out.
  5. Workers broadcast remove messages on shutdown.

natsSubjects holds the NATS subject strings built from prefix and masterID. thisMember is the local node's member info, synced with the master on setting changes. ctx/cancel control the lifecycle of background goroutines (ticker, heartbeat check).

func NewMaster added in v1.5.0

func NewMaster() ComponentMaster

func (*ComponentMaster) Init added in v1.5.0

func (m *ComponentMaster) Init()

Init sets up the master component: loads local member info, builds NATS subjects, and starts the appropriate subscriptions and background loops based on role.

func (*ComponentMaster) Mode added in v1.5.0

func (m *ComponentMaster) Mode() string

func (*ComponentMaster) NodeID2Bytes added in v1.5.0

func (m *ComponentMaster) NodeID2Bytes(nodeID string) ([]byte, error)

func (*ComponentMaster) Stop added in v1.5.0

func (m *ComponentMaster) Stop()

Stop performs a graceful shutdown: workers send a remove message, then the lifecycle context is cancelled to stop all background loops.

func (*ComponentMaster) UpdateSetting added in v1.5.0

func (m *ComponentMaster) UpdateSetting(key, value string)

UpdateSetting updates a single setting on this member and broadcasts the change.

func (*ComponentMaster) UpdateSettings added in v1.5.0

func (m *ComponentMaster) UpdateSettings(setting map[string]string)

UpdateSettings updates multiple settings on this member and broadcasts the change.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL