【问题标题】:Django Db routingDjango Db 路由
【发布时间】:2016-09-20 15:53:07
【问题描述】:

我正在尝试使用两个数据库(1 个主数据库,1 个只读副本)运行我的 Django 应用程序。我的问题是,如果我在写完代码后立即尝试阅读,代码就会爆炸。例如:

  • p = Product.objects.create()
    1. Product.objects.get(id=p.id)

    1. 如果用户被重定向到产品的 详情页

代码运行速度比只读副本快得多。如果读取操作使用副本,代码会崩溃,因为它没有及时更新。

有什么办法可以避免这种情况吗?例如,要读取的数据库是由请求而不是操作选择的?

我的路由器与 Django 的文档相同:

import random

class PrimaryReplicaRouter(object):
    def db_for_read(self, model, **hints):
        """
        Reads go to a randomly-chosen replica.
        """
        return random.choice(['replica1', 'replica2'])

    def db_for_write(self, model, **hints):
        """
        Writes always go to primary.
        """
        return 'primary'

    def allow_relation(self, obj1, obj2, **hints):
        """
        Relations between objects are allowed if both objects are
        in the primary/replica pool.
        """
        db_list = ('primary', 'replica1', 'replica2')
        if obj1._state.db in db_list and obj2._state.db in db_list:
            return True
        return None

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        """
        All non-auth models end up in this pool.
        """
        return True

【问题讨论】:

    标签: python django


    【解决方案1】:

    解决了:

    class Model(models.Model): 
        objects = models.Manager()  -> objects only access master
        sobjects = ReplicasManager() -> sobjects access either master and replicas
    
        class Meta: 
            abstract = True  -> so django doesn't create a table
    

    让每个模型都扩展这个而不是models.Model,然后使用对象或sobjects,无论我想只访问master还是要访问master或replicas

    【讨论】:

      【解决方案2】:

      根据数据的大小和应用程序,我将使用以下任一方法解决此问题:

      1. 数据库固定:

      扩展您的数据库路由器以允许将功能固定到特定数据库。例如:

      from customrouter.pinning import use_master
      
      @use_master
      def save_and_fetch_foo():
          ...
      

      django-multidb-router 就是一个很好的例子。 当然你也可以使用这个包。

      1. 使用model manager to route queries to specific databases

        class MyManager(models.Manager):
            def get_queryset(self):
                qs = CustomQuerySet(self.model)
                if self._db is not None:
                    qs = qs.using(self._db)
                return qs
        
      2. 编写一个中间件,将您的请求自动路由到主/从。 与 pinning 方法基本相同,但您不会指定何时对 master 运行 GET 请求。

      【讨论】:

      • 解决了它:class Model(models.Model): objects = models.Manager() sobjects = ReplicasManager() class Meta: abstract = True 是我想使用master我做User.objects。 ..如果我使用sobjects是master还是replica无关紧要
      【解决方案3】:

      在主副本配置中,新数据将需要几毫秒才能将数据复制到所有其他副本服务器/数据库上。

      所以每当你在写后尝试阅读时,它不会给你正确的结果。

      您可以使用 master 在写入后立即读取,而不是从副本读取,方法是在 get 查询中使用 using('primary') 关键字。

      【讨论】:

        猜你喜欢
        • 2019-01-15
        • 1970-01-01
        • 1970-01-01
        • 2021-12-14
        • 1970-01-01
        • 1970-01-01
        • 2013-09-11
        • 2015-09-06
        • 1970-01-01
        相关资源
        最近更新 更多