我的服务器上运行了一个daemonized ruby脚本,如下所示:
@server = TCPServer.open(61101)
loop do
@thr = Thread.new(@server.accept) do |sock|
Thread.current[:myArrayOfHashes] = [] # hashes containing attributes of myObject
SystemTimer.timeout_after(5) do
Thread.current[:string] = sock.gets
sock.close
# parse the string and load the data into myArrayOfHashes
Myobject.transaction do # Update the myObjects Table
Thread.current[:myArrayOfHashes].each do |h|
Thread.current[:newMyObject] = Myobject.new
# load up the new object with data
Thread.current[:newMyObject].save
end
end
end
end
@thr.join
end
此服务器接收并管理我的rails应用程序的数据,该应用程序全部在Mac OS 10.6上运行。客户在15分钟内每15分钟拨打一次服务器,而我目前只有16个左右的客户在15分钟内每15分钟拨打一次,我想知道以下情况:
另外,是否有一篇文章可以指出我讨论实现这种服务器的最佳方法?我的意思是我可以在同一端口上监听多个服务器实例吗?这会有帮助吗?
我正在使用Bluepill来监控我的服务器守护进程。
答案 0 :(得分:2)
1和2
答案是否定的,两个彼此靠近连接的客户端不会使连接失败(但是多个客户端连接可能会失败,见下文)。
原因是操作系统在所有服务器套接字中都内置了一个默认的所谓侦听队列。因此,即使您没有在程序中快速调用accept
,操作系统仍将继续为您缓冲传入连接。只要侦听队列没有被填满,它就会缓冲这些连接。
那么这个队列的大小是多少呢?
在大多数情况下,通常使用的默认大小为5.在创建套接字后设置大小,并在此套接字上调用listen
(请参阅man page for listen here)。
对于Ruby TCPSocket
自动为您调用listen
,如果您查看TCPSocket
的C源代码,您会发现它确实将大小设置为5:
https://github.com/ruby/ruby/blob/trunk/ext/socket/ipsocket.c#L108
SOMAXCONN
在此定义为5:
https://github.com/ruby/ruby/blob/trunk/ext/socket/mkconstants.rb#L693
如果你没有足够快地调用accept并且队列被填满,会发生什么?
答案可在listen
的手册页中找到:
backlog参数定义sockfd的挂起连接队列可能增长的最大长度。如果在队列已满时到达连接请求,则客户端可能会收到带有ECONNREFUSED指示的错误,或者,如果基础协议支持重新传输,则可以忽略该请求,以便稍后在连接时重新尝试成功。
在您的代码中,如果超过5个客户端同时尝试连接,则有一个问题可能导致队列填满:您在循环结束时调用@thr.join
。
执行此操作时实际发生的情况是,在接受线程中的所有内容都已完成执行之前,您的服务器将不接受任何新的传入连接。
因此,如果数据库内容以及您在accept-thread内部执行的其他操作需要很长时间,那么侦听队列可能会在此期间填满。这取决于您的处理时间,以及可能在同一时间连接的客户端数量。
第3 强>
您没有说明您正在运行哪个平台,但在linux / osx上最简单的方法是在控制台中运行top
。有关更高级的内存监视选项,您可能需要查看这些选项:
ruby/ruby on rails memory leak detection
track application memory usage on heroku