我正在用Python编写客户端 - 服务器应用程序。我们的想法是拥有一台主服务器和数千个将与之连接的客户端。服务器将随机发送小文件到要处理的客户端,客户端必须每分钟完成工作并将其状态更新到服务器。我的问题是,目前我只有一个小而老的家庭服务器,所以我认为它无法处理这么多连接。也许你可以帮我解决这个问题:
编辑:我更新了问题,以便更好地解释这个问题,但主要是为那些有同样问题的人提供足够的清晰度。在@TimMcNamara答案中实际上有一个很好的解决方案。
答案 0 :(得分:14)
哪些设计决策可能会影响您实施网络解决方案的方式?你立即开始列出一些:
这看起来很棒。我们想要一些容易编程的东西,而且规格相当高。但是,这个列表失败了。我们在这里做的只是看服务器。这可能是我们在Web应用程序中可以控制的全部内容,但是我们可以完全控制的分布式系统如传感器网络呢?
假设我们有10,000台设备想要用最新的传感器读数更新您,他们每分钟都会读取一次。现在,我们可以使用一个高端服务器来保存与所有设备的并发连接。
然而,即使您拥有一台极高端的服务器,您仍然可能会遇到性能问题。如果设备都使用相同的时钟,并且所有设备都在一分钟的时间内尝试发送数据,那么服务器将在每分钟1-2秒内完成大量的CPU工作,其余部分则没有。非常低效。
由于我们可以控制传感器,我们可以让他们自己进行负载平衡。一种方法是为每个设备提供一个ID,然后使用模数运算符仅在每分钟的正确时间发送数据:
import time
def main(device_id):
data = None
second_to_send = device_id % 60
while 1:
time_now = time.localtime().tm_sec
if time_now == 0:
data = read_sensors()
if time_now == second_to_send and data:
send(data)
time.sleep(1)
这种负载平衡的一个后果是我们不再需要这样的高功率服务器。我们认为我们需要与每个人保持联系的内存和CPU不是必需的。
我在这里要说的是,您应该确保您的特定解决方案专注于整个问题。通过您提供的简要描述,我们似乎不需要一直保持大量的连接。但是,我们确实需要100%连接。我们有什么选择?
非阻塞I / O的影响意味着当没有立即返回时,向文件描述符请求数据的函数。对于网络,这可能是坏的,因为尝试从套接字读取的函数将不向调用者返回任何数据。因此,有时产生一个线程然后调用read
可能会简单得多。这样在线程内部阻塞不会影响程序的其余部分。
线程问题包括内存效率低下,线程创建所涉及的延迟以及与上下文切换相关的计算复杂性。
要利用非阻塞I / O,您可以在while 1:
循环中对每个相关文件描述符进行自我轮询。这将是很好的,除了CPU将以100%运行的事实。
为避免这种情况,已创建基于事件的库。当没有工作要做时,它们将以0%运行CPU,仅在要读取数据时才激活。在Python世界中,Twisted,Tornado或gevent是重要的参与者。但是,有many options。特别是diesel看起来很有吸引力。
以下是龙卷风网页的相关摘录:
因为它是非阻塞的并使用epoll或kqueue,它可以处理数千个同时站立的连接,这意味着它是实时Web服务的理想选择。
每个选项都采用略有不同的方法。 Twisted和Tornado在他们的方法上非常相似,依赖于非阻塞操作。 Tornado专注于Web应用程序,而Twisted社区则对更广泛的网络感兴趣。随后有更多用于非HTTP通信的工具。
gevent是不同的。该库修改了套接字调用,因此每个连接都在一个非常轻量级的类似线程的上下文中运行,尽管实际上这对于程序员来说是隐藏的。只要有阻塞调用,例如数据库查询或其他I / O,gevent就会很快切换上下文。
每个选项的结果是您可以在单个OS线程中为许多客户端提供服务。
您的操作系统对允许的连接数施加限制。如果达到您正在谈论的数字,您可能会达到这些限制。特别是,Linux在/etc/security/limits.conf
中为每个用户维护限制。您可以通过在shell中调用ulimit
来访问用户的限制:
$ ulimit -a core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 63357 max locked memory (kbytes, -l) 64 max memory size (kbytes, -m) unlimited open files (-n) 1024 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 8192 cpu time (seconds, -t) unlimited max user processes (-u) 63357 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited
我在这里鼓励了最相关的一行,open files
。打开外部连接被视为打开文件。一旦达到1024限制,没有应用程序将能够打开另一个文件,也不会有任何其他客户端能够连接到您的服务器。我们假设您有一个用户httpd
作为您的网络服务器。这应该让您了解可以为提高该限制所做的修改:
httpd soft nofile 20480
httpd hard nofile 20480
对于极高的音量,您可能会达到系统范围的限制。您可以通过cat /proc/sys/fs/file-max
:
$ cat /proc/sys/fs/file-max
801108
要修改此限制,请使用sudo sysctl -w fs.file-max=n
,其中n是您希望允许的打开文件数。修改/etc/sysctl.conf
以使其重新启动。
答案 1 :(得分:1)
一般来说,即使是非常适度的家庭服务器,也可以同时拥有数万个套接字。
请确保不为每个连接创建新的线程或进程。