在高负载Django应用程序中避免数据丢失的最佳方法是什么?

时间:2014-09-08 10:26:58

标签: python django postgresql high-load

想象一下具有前端和后端部分的相当复杂的Django应用程序。一些用户修改前端部分的一些数据。有些脚本会在后端部分定期修改相同的数据。

示例:

instance = SomeModel.objects.get(...)
# (long-running part where various fields are changed, takes from 3 to 20 seconds)
instance.field = 123
instance.another_field = 'abc'
instance.save()

如果某个人(或某个东西)在该部分更改某些字段时更改了实例,那么更改将会丢失,因为最近将保存实例,从Python(Django)类转储数据。换句话说,如果代码中的某些内容需要数据,然后等待一段时间,然后将数据保存回来 - 那么只有最新的“保护程序”将保存其数据,所有其他(之前的)数据将丢失其更改。 / p>

这是一个“高负载”应用程序,数据库负载(我们使用Postgres)非常高,我想避免任何会导致DB活动或内存大量增加的内容。

另一个问题 - 我们附加了许多信号,甚至覆盖了save()方法,因此我想避免任何可能破坏信号或可能与自定义save()或update()方法不兼容的内容。< / p>

在这种情况下你会推荐什么?有什么特别的应用吗?交易?还有什么吗?

谢谢!

1 个答案:

答案 0 :(得分:2)

防止这种情况的正确方法是使用select_for_update确保数据在读取和写入之间不会发生变化。但是,这会导致行被锁定以进行更新,因此这可能会显着降低应用程序的速度。

Oen解决方案可能是读取数据并执行长时间运行的任务。然后在保存之前启动事务,再次读取数据,但现在使用select_for_update并验证原始数据是否未更改。如果数据仍然相同,则保存。如果数据已更改,则中止并重新运行长时间运行的任务。这样你就可以尽可能地保持锁定。

类似的东西:

success = False
while not success:
  instance1 = SomeModel.objects.get(...)
  # (long-running part)

  with django.db.transaction.atomic():
    instance2 = SomeModel.objects.select_for_update().get(...)
    # (compare relevant data from instance1 vs instance2)
    if unchanged:
      # (make the changes on instance2)
      instance2.field = 123
      instance2.another_field = 'abc'
      instance2.save()
      success = True

如果这是一种可行的方法,那取决于您长期运行的任务究竟是什么。并且用户可能仍会覆盖您在此处保存的数据。