为成功做好准备:访问模式很重要
哪些设计决策会影响您实施网络解决方案的方式?您立即开始列出一些:
这看起来是一个很棒的清单。我们想要一些易于编程且规格相当高的东西。但是,这个列表失败了。我们在这里所做的只是查看服务器。这可能是我们在 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是大玩家。但是,有很多选择。特别是柴油看起来很有吸引力。
以下是 Tornado 网页的相关摘录:
因为它是非阻塞的,并且使用 epoll 或 kqueue,所以它可以同时处理数千个站立连接,这意味着它非常适合实时 Web 服务。
这些选项中的每一个都采用略有不同的方法。Twisted 和 Tornado 在方法上非常相似,都依赖于非阻塞操作。Tornado 专注于 Web 应用程序,而 Twisted 社区则对更广泛的网络感兴趣。随后有更多用于非 HTTP 通信的工具。
gevent 不同。该库修改了套接字调用,以便每个连接都在一个非常轻量级的类似线程的上下文中运行,尽管实际上这对您作为程序员是隐藏的。每当出现阻塞调用时,例如数据库查询或其他 I/O,gevent 都会非常快速地切换上下文。
这些选项中的每一个的结果是您能够在单个操作系统线程中为许多客户端提供服务。
调整服务器
您的操作系统对它允许的连接数施加了限制。如果您达到您正在谈论的数字,您可能会达到这些限制。特别是,Linux 为/etc/security/limits.conf
. 您可以通过调用ulimit
shell 来访问用户的限制:
$ ulimit -a
核心文件大小(块,-c)0
数据段大小 (kbytes, -d) 无限制
调度优先级 (-e) 0
文件大小(块,-f)无限制
待处理信号 (-i) 63357
最大锁定内存 (kbytes, -l) 64
最大内存大小 (kbytes, -m) 无限制
打开文件 (-n) 1024
管道大小(512 字节,-p)8
POSIX 消息队列(字节,-q)819200
实时优先级 (-r) 0
堆栈大小(千字节,-s)8192
cpu时间(秒,-t)无限制
最大用户进程 (-u) 63357
虚拟内存 (kbytes, -v) 无限制
文件锁 (-x) 无限制
我在这里加粗了最相关的线路,即open files
. 打开的外部连接被认为是打开的文件。一旦达到 1024 限制,任何应用程序都无法打开另一个文件,任何客户端也无法连接到您的服务器。假设您有一个用户,httpd
作为您的 Web 服务器。这应该让您了解可以进行哪些修改以提高该限制:
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
以使其在重新启动后仍然有效。