了解多个gunicorn进程的工作原理

Ran*_*jay 5 python django acid django-rest-framework

我不知道我想要理解的是什么,上网把我带到了这里,现在我的代码中需要这个。

我使用 django-rest-framework、gunicorn 和 Nginx。

假设我有 3 个gunicorn 设置的工作进程。

我有一个非常简单的视图,它从数据库读取一个值,执行一项不同的任务,大约需要 1 秒,将值增加 1,然后将其保存回数据库。

class CreateView():
    value = MyModel.objects.get(id=1).integerValueField
    otherTask() #takes around 1 second (assume)
    updatedValue = value + 1
    MyModel.objects.filter(id=1).update(integerValueField=updatedValue)
    return
Run Code Online (Sandbox Code Playgroud)

这总是有效吗?

如果gunicorn的不同工作进程正在处理并发用户的请求怎么办?如果在读取值和由其他工作进程更新值之间由不同的进程更新数据库(integerValueField 字段) ?这是为了保持完整性而以某种方式锁定的吗?

如果我可以获得有效的链接来阅读有关该主题的更多信息,那么对我来说会很有效。

eeg*_*ega 4

扩展 Pjot\xe2\x80\x98s 注释 - 不,如果您使用多个 Gunicorn 工作线程执行您提供的代码,则该代码将无法可靠地工作。这里发生的情况称为竞争条件,实际上并不是 Django 特有的任何事情 -这里是在更通用的数据库设置中对此进行的讨论。

\n

现在,如果多个 Gunicorn 工作程序访问同一个对象(或具有多个线程的单个工作程序MyModel.objects.get(id=1).integerValueField),在您的特定情况下会发生什么,如果我们假设是100在开始时,则大致如下所示:

\n
    \n
  1. worker 1 执行value = MyModel.objects.get(id=1).integerValueField,这将访问数据库并检索带有主键的对象1并将其存储在内存中。value将被设置为 的值integerValueField100在我们的示例中
  2. \n
  3. 工人1执行otherTask()
  4. \n
  5. 工作程序 2 执行,就像工作程序 1 一样,它将把数据库中 的value = MyModel.objects.get(id=1).integerValueField当前值存储在 中。再次,因为数据库中的值尚未更改integerValueFieldvaluevalue100
  6. \n
  7. 工人2执行otherTask()
  8. \n
  9. 现在,worker 1 将执行updatedValue = value + 1,设置updatedValue101然后执行MyModel.objects.filter(id=1).update(integerValueField=updatedValue)以将其保存到数据库
  10. \n
  11. 现在,worker 2 也将执行updatedValue = value + 1- 但value也将101代替102,因为使用了数据库值的本地副本。这里不会发生额外的数据库访问。之后它也会执行MyModel.objects.filter(id=1).update(integerValueField=updatedValue),这将更新数据库,但不会更改值 - 它仍然会101
  12. \n
\n

它的作用select_for_update是锁定数据库行,这样它就不能被任何其他工作人员同时访问(这是一个称为互斥访问的概念,通常通过锁定来实现)。这将解决您丢失更新的问题。但是,您在这里应该考虑的是,您将在运行时阻止对此行的所有访问otherTask()(这显然是相当长的时间),这很容易导致您的客户长时间延迟甚至更糟。\n我真的会考虑如果有更好的方法来解决这个问题。如果不是,我至少会研究多线程 Gunicorn 工作人员-是一个很好的讨论。

\n