我计划提供两项服务。
Ruby服务将打开与Go JSON RPC服务的TCP套接字连接。它会为它收到的每个传入HTTP请求执行此操作。它会通过套接字向Go服务发送一些数据,然后该服务将相应的数据发送回套接字。
Go服务go看起来像这样(简化):
srv := new(service.App) // this would expose a Process method
rpc.Register(srv)
listener, err := net.Listen("tcp", ":8080")
if err != nil {
// handle error
}
for {
conn, err := listener.Accept()
if err != nil {
// handle error
}
go jsonrpc.ServeConn(conn)
}
请注意,我们使用goroutine为传入连接提供服务,因此我们可以同时处理请求。
下面是一段简单的Ruby代码片段,演示了(理论上)我将数据发送到Go服务的方式:
require "socket"
require "json"
socket = TCPSocket.new "localhost", "8080"
b = {
:method => "App.Process",
:params => [{ :Config => JSON.generate({ :foo => :bar }) }],
:id => "0"
}
socket.write(JSON.dump(b))
response = JSON.load socket.readline
我担心的是:这是一个安全的事件序列吗?
我不会问这是否是“线程安全”,因为我并不担心在go例程中操纵共享内存。我更担心我的Ruby HTTP服务是否会收回它预期的数据?
如果我有两个并行请求进入我的HTTP服务(或者Ruby应用程序托管在负载均衡器后面,因此HTTP服务的不同实例处理多个请求),那么我可以让实例A将消息Foo发送给Go服务;实例B发送消息Bar。
Go服务中的业务逻辑将根据其输入返回不同的响应,因此我想确保Ruby实例A收回对Foo的正确响应,并且B获取Bar的正确响应。
我认为套接字连接更像是一个队列,如果实例A首先向Go服务发出请求,然后然后 B发出请求,但是无论出于何种原因B都更快响应,那么Go service会将B的响应写入套接字,而Ruby应用程序的实例A最终会读取错误的套接字数据(这显然只是一个可能的场景,因为我可以得到 lucky 并让实例B在实例A之前读取套接字数据。
我不确定是否有简单解决此问题的方法。除非我不使用TCP套接字或RPC,而是依赖Go服务中的标准HTTP。但是我想要TCP的性能和更少的开销。
我担心设计可能因为必须实现外部队列作为将响应与Ruby服务同步的方式而变得更加复杂。
这可能是因为我的Ruby服务的本质是基本上是同步的(HTTP响应/请求),我别无选择,只能切换到Go服务的HTTP。
但是我想先与社区进行双重检查,以防我错过了一些明显的事情。