2017-10-13 53 views
0

问题

我想运行负载测试,每秒请求数量很高。我在Go中写了一个套接字发送者和一个接收者。发送方向端口7357发送大量数据包,每个数据包包含当前时间(以纳秒为单位)。接收机在端口7357进行侦听并分析每条消息,计算延迟。如何在Go中为每个连接写入单独的数据包?

问题是,当阅读我在一个conn.Read()得到多个数据包。我知道这意味着我实际上每个数据包都发送多条消息:每个conn.Write()都不会发送套接字数据包,但会等待一段时间,然后在发送之前与下一个(或接下来的几个)进行合并。

问题

我怎样才能确保每个conn.Write()通过插座单独发送作为一个单独的数据包? 注意:我不想重新创建TCP,我只是想模拟从每个发送消息的外部实体的负载。

所采取的步骤

我已经搜索的文档,但似乎没有conn.Flush()或相似。我曾尝试使用缓冲写入器:

writer := bufio.NewWriter(conn) 
... 
bytes, err := writer.Write(message) 
err = writer.Flush() 

没有错误,但仍然在接收端得到混合数据包。我也尝试在每conn.Write()之后做0个字节的假conn.Read(),但它也没有工作。发送消息终止符如\r\n似乎没有任何区别。最后,Nagle算法在默认情况下是禁用的,但我已经调用tcp.SetNoDelay(true)进行了很好的测量。

在Node.js中,我设法在每个socket.write()setImmediate()等待所有I/O完成之前完成setImmediate()的技巧。我如何在Go中执行相同的操作,以便获得单独的数据包?

代码段

发送:

func main() { 
    conn, _ := net.Dial("tcp", ":7357") 
    defer conn.Close() 
    for { 
    timestamp := strconv.FormatInt(time.Now().UnixNano(), 10) 
    conn.Write([]byte(timestamp)) 
    conn.Read(buff) 
    } 
} 

接收:

func main() { 
    listen, _ := net.Listen("tcp4", ":7357") 
    defer listen.Close() 
    for { 
    conn, _ := listen.Accept() 
    go handler(conn) 
    } 
} 
func handler(conn net.Conn) { 
    defer conn.Close() 
    var buf = make([]byte, 1024) 
    for { 
    conn.Read(buf) 
    data := string(buf[:n]) 
    timestamp, _ := strconv.ParseInt(data, 10, 64) 
    elapsed := timestamp - time.Now().UnixNano() 
    log.Printf("Elapsed %v", elapsed) 
    } 
} 

错误处理的可读性被删除,但在实际的代码彻底检查。它第一次运行strconv.ParseInt()时崩溃,value out of range错误,因为它收到了很多时间戳合并。

+1

TCPConn中的SetWriteBuffer,IPConn ...在净包文档(https://golang.org/pkg/net)不起作用,我已经试过了。但这个参考似乎有一个解决方案https://groups.google.com/forum/#!topic/golang-nuts/0FQ8duKRB4U我还没有尝试过,但你可能想要退房。 – Ravi

+0

“*我只是想模拟来自大量发送消息的外部实体的负载。*”您能否详细说明这一点? “一条消息”究竟是什么意思?为什么多个外部实体使用单个TCP连接?这听起来像你想/需要一个消息协议,为什么不设计/实现一个? –

+0

几个客户端连接到一台服务器并使用TCP发送消息。每条消息都包含在一个TCP数据包中。服务器分别处理每条消息。这个测试的连接数量并不重要;客户可能会使用几个或只有一个。我想我可以打开几个连接并使用循环法通过每个连接发送一条消息,但我正在寻找一种更简单的方法。 – alexfernandez

回答

-1

您可以在每次迭代中从套接字读取预定义的字节数,这可能有帮助,但您需要创建自己的协议,该协议将由您的应用程序处理。如果没有原因不可能保证所有东西都能稳定运行,因为在接收器上你无法理解开始的地方和结束的地方。

+0

我应该指定我的目的是构建一个负载测试工具,我已经将它添加到了我的问题中。 – alexfernandez

2

曾经有一条规则规定,在任何人被允许编写使用TCP的代码之前,他们需要从内存中重复以下句子并解释它的含义:“TCP不是消息协议,它是一个可靠的字节流协议,不保存应用程序消息边界。“

除了用TCP提供的解决方案不可能可靠地实现,它不是减少延迟的解决方案。如果网络不堪重负,使用更多的数据包发送相同的数据只会使延迟变得更糟。

TCP是一个字节流协议。它提供的服务是一个字节流。期。

看来你想低延迟消息协议,工作在TCP。大。设计一个与实施它

获得低延迟的主要技巧是使用应用程序级别应答edgements。 TCP ACK标志将捎带回确认,提供低延迟。

不要禁用Nagling。这是一个只有当你无法设计一个适用于TCP的合适协议的黑客。由于相同的原因,您在非理想条件下会造成延迟,即使可能,您提出的解决方案也不是一个好主意。

但你必须设计和实现消息协议或使用现有的协议。您的代码期望TCP(不是消息协议)以某种方式将消息传递给它。这是不会发生的,期间。

如何确保每个conn.Write()作为单独的数据包单独通过套接字发送?注意:我不想重新创建TCP,我只是想模拟来自大量发送消息的外部实体的负载。

即使你可以,那也不会做你想要的东西。即使它们是以单独的数据包发送的,也不能保证另一方的read不会合并。如果你想发送和接收消息,你需要一个消息协议,TCP不是。

在Node.js中,我在每个socket.write()之后设法使用setImmediate():setImmediate()在继续之前等待所有I/O完成。我如何在Go中执行相同的操作,以便获得单独的数据包?

您可能已将其从“发生不工作”改为“碰巧在我尝试时工作”。但由于我解释的原因,你永远无法可靠地完成这项工作,并且你是一个傻瓜的差事。

如果要发送和接收消息,您需要精确定义“消息”的内容,并编写代码来发送和接收消息。没有可靠的捷径。 TCP是一个字节流协议,句号。

如果您关心延迟和吞吐量,请设计一个优化的消息协议,以便通过TCP优化这些协议。不要禁用Nagle,因为需要Nagle防止病态行为。只有当您无法更改协议时才应该禁用该功能,并且这些协议不能用于TCP层协议。禁用Nagle绑在背后,在网络状况不佳的情况下,通过增加发送数据所需的数据包数量,即使没有任何意义,也会导致显着更差的延迟和吞吐量。

您可能需要/需要应用程序级别的确认。这与TCP很好地协同工作,因为TCP ACK将搭载应用程序级别的确认。

+0

我应该指定我的目的是构建负载测试工具,我已将它添加到我的问题中。 Nagle默认是禁用的,尽管我仍然尝试过。我想用'setImmediate()'在Node.js中完成任务,我发现奇怪的是它不能在Go中完成。 – alexfernandez

+0

@alexfernandez如果您禁用了Nagle,那么您正在对残缺协议进行负载测试。 Nagle显着提高了TCP的吞吐量和延迟。只有当您的协议不适合使用TCP时才需要禁用它。让Nagle默认禁用并没有任何意义AFAICT。而node.js中的'setImmediate'不会将TCP转换为消息协议,因为它不是一个。请再读一遍我的第一段。 –

+0

对于负载测试,从消息数量中分离数据包数量并分别进行测试要好得多。我想我可以接受一个包含多个消息的测试。 – alexfernandez

相关问题