smallnest / rpcx

Best microservices framework in Go, like alibaba Dubbo, but with more features, Scale easily. Try it. Test it. If you feel it's better, use it! 𝐉𝐚𝐯𝐚有𝐝𝐮𝐛𝐛𝐨, 𝐆𝐨𝐥𝐚𝐧𝐠有𝐫𝐩𝐜𝐱! build for cloud!
https://rpcx.io
Other
8.08k stars 1.16k forks source link

[Feature Require]: 支持以 Socket/Websocket 为基础的双向连接 #794

Closed axetroy closed 10 months ago

axetroy commented 1 year ago

背景

在 RPC 调用中,需要知道目标服务器地址,例如 ws@192.168.0.1/tcp@192.168.0.1

这里有个问题,例如 A/B 两台服务器想要互相调用 RPC 服务器,就必须处于网络互通的情况。

但实际有可能会有以下情况

# 网络互通
A <---> B
# A 能访问 B,但 B 不能访问 A
A --> B
# B 能访问 A,但 A 不能访问 B
A <-- B

但在实际的项目中,有时候我们不需要知道对方的地址,也希望能通信。

例如我正在做的一个项目,架构是 Master(1):Agent(N) 的关系

1 个 master 对应 N 个 agent,并且互相通信,不可能把 N 个 agent 的地址写进程序或者存储。

最好的方法是,谁连接 master,即可用 socket/Websocket 进行双向通信,无需知道对方的地址。

模拟接口

通过 tcp socket 连接

  // 客户端
  socket, err := net.Dial("192.168.0.1")

  d, err := client.NewSocketDiscovery(socket, "")

  if err != nil {
    return err
  }

  d.NewXClient("xxxx", ...)

通过 websocket 连接

  // 客户端
  ws, err := net.Dial("ws://192.168.0.1")

  d, err := client.NewWebSocketDiscovery(ws, "")

  if err != nil {
    return err
  }

  d.NewXClient("xxxx", ...)
  // 客户端给予 *websocket.Con 启动一个虚假的 RPC 服务,而不用真实的监听端口
  s := server.NewWebSocketServer(conn)

  s.RegisterName('Agent', ...)

  // s.Server("tcp") ❌

socket 是标准库中的实现,websocket 使用 golang.org/x/net/websocket

服务端真实的一个 tcp/websocket 服务,用于服务器 RPC 调用,而客户端,使用虚拟的接口,提供给服务端调用 RPC

samuelyao314 commented 1 year ago

我看文档里有类似的机制

samuelyao314 commented 1 year ago

https://doc.rpcx.io/part6/bidirectional.html

axetroy commented 1 year ago

我看文档里有类似的机制

双向通讯的文档我看了,并不太符合我描述的,与其这样,不如单纯的用 socket 通讯进行封装。

也看过其他 RPC 类库,没有这方面的实现。

补充一下描述:

需要一种机制,能使得 A/B 两台服务进行通讯,但又不需要这两台服务器都监听端口。

这里有几种手段,A 启动 TCP/Websocket 服务,B 连接

但同时又要两者提供 RPC 服务,A通过 TCP/Websocket 提供,B通过连接A的 socket 提供。

hexxv commented 1 year ago

这个需求 听起来像是 peer2peer, 哈哈哈,不过高级点,,不想把对方地址写成配置。如果可以接受peer2peer, 我认为通过 服务发现选择器的 定制化开发 来满足你的需求。

选择器:

// Selector defines selector that selects one service from candidates.
type Selector interface {
    Select(ctx context.Context, servicePath, serviceMethod string, args interface{}) string // SelectFunc
    UpdateServer(servers map[string]string)
}
smallnest commented 10 months ago

这个需求建议使用单独的库和通讯去做