我不是身份验证和安全方面的专家,但以下是关于为什么会发生这种情况以及如何提高性能的一些想法。
由于密码存储在数据库中,为了使其存储安全,不存储明文密码,而是存储其哈希值。这样,您仍然可以通过将输入密码的计算哈希值与存储在数据库中的哈希值进行比较来验证用户登录。这增加了安全性,因此如果恶意方将获得数据库的副本,解码明文密码的唯一方法是使用彩虹表或进行暴力攻击。
这就是事情变得有趣的地方。根据摩尔定律,计算机正以指数级速度增长,因此计算哈希函数在时间上变得更便宜,尤其是像 md5 或 sha1 这样的快速哈希函数。这带来了一个问题,因为拥有当今可用的所有计算能力以及快速散列函数,黑客可以相对容易地暴力破解散列密码。为了解决这个问题,可以做两件事。一种是多次循环散列函数(散列的输出被反馈到散列中)。然而,这并不是很有效,因为它只会将散列函数的复杂性增加一个常数。这就是为什么首选第二种方法的原因,即使实际的散列函数更复杂且计算成本更高。具有更复杂的功能,计算哈希需要更多时间。即使计算需要一秒钟,对最终用户来说也没什么大不了的,但对于暴力攻击来说却是个大问题,因为必须计算数百万个哈希值。这就是为什么从 Django 1.4 开始,它使用了一个计算量非常大的函数,称为 PBKDF2。
回到你的答案。正是因为这个功能,当您启用身份验证时,您的基准测试数量会急剧下降,而您的 CPU 会上升。
以下是一些可以提高性能的方法。
- 从 Django 1.4 开始,您可以更改默认身份验证功能 ( docs )。如果您不需要太多安全性,您可以将默认函数更改为 SHA1 或 MD5。这应该会提高性能,但请记住,安全性会弱得多。我个人的观点是安全性很重要,值得花额外的时间,但如果它在您的应用程序中没有保证,那么您可能需要考虑这一点。
- 使用会话。昂贵的散列函数仅在初始登录时计算。一旦用户登录,就会为该会话创建一个会话,并将一个带有会话 ID 的 cookie 发送给用户。然后在后续请求中,用户上传一个 cookie,如果会话尚未过期,用户将自动进行身份验证(不要担心安全性,因为会话数据已签名......)。关键是,与计算昂贵的哈希函数相比,验证会话的计算成本要低得多。我猜在 ab 测试中你没有发送会话 cookie。尝试通过发送会话 cookie 来做一些测试,看看它是如何执行的。如果由于您正在制作 JSON API,因此发送 cookie 不是一个真正的选项,然后您可以修改会话后端以通过会话 GET 参数而不是 cookie 接受会话数据。但是不确定这样做的安全后果是什么。
- 切换到 nginx。我不是部署专家,但根据我的经验,与 Apache 相比,nginx 对 Django 更快、更友好。我认为您可能特别感兴趣的一个优势是 nginx 能够拥有多个工作进程以及它能够使用 proxy_pass 来处理对 Django 进程的请求。如果您将有多个工作进程,则可以通过 proxy_pass 将每个工作进程指向一个单独的 Django 进程,这将有效地将多处理添加到 Django。另一种选择是,如果您使用 gevent WSGI 服务器之类的东西,您可以在 Django 进程中创建一个池,这也可能会提高性能。由于您的 CPU 负载已经达到 100%,因此不确定这些是否会显着提高您的性能,但可能需要研究一下。