这个例子是tcp socket编程事件序列安全吗?

时间:2016-04-09 17:19:11

标签: ruby sockets asynchronous go

我计划提供两项服务。

  1. 用Ruby编写的HTTP REST服务
  2. 用Go
  3. 编写的JSON RPC服务

    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代码

    下面是一段简单的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。

    但是我想先与社区进行双重检查,以防我错过了一些明显的事情。

0 个答案:

没有答案