rpcx 替代 net/rpc 或 http 接口可行,但需显式指定 servicepath(如 "arithservice")、配对 discovery+selector(禁用 peer2peer)、选用 protobuf/messagepack 序列化、复用 discovery 实例、手动暴露 /metrics 端点,并确保方法签名第三个参数为指针且返回 error。

直接用 rpcx 替代 net/rpc 或裸写 HTTP 接口是可行的,但必须绕开它默认的 peer2peer 模式和隐式服务发现逻辑——否则本地调试能跑通,一上集群就失联。
rpcx 服务端注册必须显式指定 ServicePath 和 ServiceMethod
很多人照抄示例代码写 s.RegisterName("Arith", new(Arith), ""),结果客户端怎么都连不上。问题出在空字符串 "" 这个 service path 上:rpcx 默认会把空路径转成包名+结构体名(比如 main.Arith),而客户端如果没用完全一致的路径去调用,就会报 service not found。
- 务必显式传入明确的路径,例如
s.RegisterName("ArithService", new(Arith), "") - 如果结构体在子包里,路径要带包名,比如
"calculator.Arith",且客户端调用时也得用这个全路径 - 避免依赖默认推导,
RegisterName第三个参数不为空时,它才真正生效;为空则走反射推导,容易跨包错乱
客户端连接必须配对 Discovery + Selector,不能只靠 NewPeer2PeerDiscovery
NewPeer2PeerDiscovery("tcp@localhost:8972", "") 看似简单,但它只适用于单点直连,且不支持重试、健康检查或服务列表变更。一旦服务端重启或 IP 变更,客户端就卡死在旧连接上,错误常表现为 connection refused 或长时间无响应。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 生产环境必须搭配真实服务发现后端(如 etcd、consul),哪怕本地开发也建议用
etcd起一个单节点模拟 -
XClient初始化时,client.Failtry是最稳妥的容错模式,配合client.RandomSelect或client.RoundRobin,别用client.Failfast——它不重试,网络抖动就直接失败 - Discovery 实例必须复用,不要每次请求都新建;它内部有缓存和服务列表监听,频繁创建会导致 goroutine 泄漏
序列化协议选型直接影响跨语言兼容性和性能边界
默认用 JSON 编解码看着方便,但实际压测中你会发现 CPU 占用比 Protobuf 高 3–5 倍,尤其在字段多、嵌套深的结构体上。更麻烦的是,JSON 不支持 int64 精确传输(JavaScript 会丢精度),而 rpcx 的 Args 和 Reply 若含大整数,客户端可能收到错误值。
- Go 内部服务间通信首选
Protobuf:需定义.proto文件 +protoc生成,但序列化快、体积小、类型安全 - 调试阶段可用
MessagePack:比 JSON 紧凑,又无需 proto 工具链,导入github.com/smallnest/rpcx/codec/msgpack并注册即可 - 绝对不要用默认的
gob:它是 Go 专属、不跨语言、且版本兼容性差,升级 Go 版本后旧 client 可能无法反序列化
Metrics 插件启用后必须暴露 /metrics 端点并配置 Prometheus 抓取
光调用 serverplugin.NewPrometheusMetricsPlugin() 不够,rpcx 不会自动启动 HTTP server 暴露指标。你得手动加一段监听逻辑,否则 Prometheus 抓不到数据,Grafana 仪表盘全是空的。
- 在
s.Serve(...)启动主服务后,另起 goroutine 启一个独立的 HTTP server,比如监听:8080 - 把
promhttp.Handler()注册到该 server 的/metrics路由下(需要引入github.com/prometheus/client_golang/prometheus/promhttp) - Prometheus 配置文件里要加 job,target 指向这个新端口,不是 rpcx 的主服务端口(
:8972)
最容易被忽略的是服务端方法签名约束:第三个参数必须是指针,且返回值只能是 error。写成 func(*Arith) Add(ctx context.Context, args *Args, reply Reply) error 看似一样,但 reply 不是指针,rpcx 就不会写入结果,客户端拿到的永远是零值。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










