有没有办法加快 django 中的身份验证功能?
Posted
技术标签:
【中文标题】有没有办法加快 django 中的身份验证功能?【英文标题】:Is there a way to speed up the authenticate function in django? 【发布时间】:2013-01-06 08:55:20 【问题描述】:我们正在使用 django 为 mysql 创建一个 json webservice 前端。我们在 EC2 实例上运行 apache 和 django,在 RDS 实例上运行 MySQL。我们已经开始使用 apache bench 对性能进行基准测试,并且得到了一些非常糟糕的性能数据。我们还注意到,在运行测试时,我们的 apache/django 实例在非常低的负载下达到 100% 的 cpu 使用率,而 MySQL 实例的 cpu 使用率从未超过 2%。
我们试图弄清楚这一点并找出问题所在,因此我们进行了几次 ab 测试:
-
来自 apache 的静态 html 页面请求 -- ~2000 个请求/秒。
在 django 中执行一个小型 python 函数的请求,并且没有 db 交互 -- ~1000 个请求/秒。
执行我们的 django webservice 函数之一的请求,该函数调用身份验证,然后执行非常简单的查询以从表中获取一条记录 -- 11 个请求/秒
与 3 相同,但注释了身份验证调用 -- 95 个请求/秒。
为什么认证这么慢?是往数据库写数据,求十亿位数的圆周率,什么?
我们希望在这些函数中保留对身份验证的调用,因为我们不想让任何可以猜到 url 的人都可以使用它们。这里有没有人注意到身份验证很慢,任何人都可以建议一个有什么办法补救吗?
非常感谢!
【问题讨论】:
尝试一些事情:下载 django-debug-toolbar 并读取输出。看看它在做什么类型的查询。尝试 django-profile 并读取函数执行时间。最后,获得newrelic ...即使是免费版本也会向您显示每个视图功能的有用细分。很高兴听到一些结果! 【参考方案1】:我不是身份验证和安全方面的专家,但以下是一些关于为什么会发生这种情况以及可能如何提高性能的一些想法。
由于密码存储在数据库中,为了确保其存储安全,不存储明文密码,而是存储其哈希值。这样,您仍然可以通过将输入密码的计算哈希值与存储在数据库中的哈希值进行比较来验证用户登录。这提高了安全性,因此如果恶意方将获得数据库的副本,解码明文密码的唯一方法是使用彩虹表或进行暴力攻击。
这就是事情变得有趣的地方。根据摩尔定律,计算机正以指数级速度增长,因此计算哈希函数在时间上变得更便宜,尤其是像 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%,因此不确定这些是否会显着提高您的性能,但可能需要研究一下。【讨论】:
以上是关于有没有办法加快 django 中的身份验证功能?的主要内容,如果未能解决你的问题,请参考以下文章
在 Django simple-jwt 令牌身份验证中获取后端中的当前刷新令牌
Django中的Python社交身份验证,makemigrations检测到没有变化