如果Slave关闭,Django多个数据库将回退到Master

时间:2014-10-28 12:54:21

标签: mysql django python-2.7 multiple-databases

我为Django的MySQL数据库后端设置了主 - 从复制设置。 目前我只为Master DB阅读和写作,但我的仪表板非常查询。 我正在寻找一个选项,我可以在其中定义如下 DATABASES

DATABASES = {
'default_slave': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'application',
        'USER': 'root',
        'PASSWORD': '',
        'HOST': '',
        'PORT': '3306',
    },
'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'application',
        'USER': 'root',
        'PASSWORD': '',
        'HOST': '', 
        'PORT': '3306',
    },
}  

对于仪表板,报告和各种其他应用,我想要做的是:

尝试连接:default_slave:使用default_slave如果使用default

可以使用raw queries

也就是说,如果slave已启动,则从slave数据库本身获取报告,如果没有从master数据库中获取报告。

Catch是,slave可以是up或down,我希望根据可恢复性,可以动态选择哪个数据库用于获取报告。

这可能吗?我可以预先测试连接并向前移动吗?

有了这个,我会在Master中写和sync_db,并且如果slave已经启动,它总是从Slave读取。

需要orm queries以及DATABASES = { 'default_slave': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'application', 'USER': 'root', 'PASSWORD': '', 'HOST': '', 'PORT': '3306', }, 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'application', 'USER': 'root', 'PASSWORD': '', 'HOST': '', 'PORT': '3306', }, } 'linux': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'application', 'USER': 'root', 'PASSWORD': '', 'HOST': '', 'PORT': '3306', }, } 'linux_slave': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'application', 'USER': 'root', 'PASSWORD': '', 'HOST': '', 'PORT': '3306', }, } 'mac': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'application', 'USER': 'root', 'PASSWORD': '', 'HOST': '', 'PORT': '3306', }, } 'mac_slave': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'application', 'USER': 'root', 'PASSWORD': '', 'HOST': '', 'PORT': '3306', }, } 'pc': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'application', 'USER': 'root', 'PASSWORD': '', 'HOST': '', 'PORT': '3306', }, } 'pc_slave': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'application', 'USER': 'root', 'PASSWORD': '', 'HOST': '', 'PORT': '3306', }, }

的解决方案/提示

路由器的概念看起来很不错,但奴隶的回退无法到达,我不知道这种可能性。

更新

如何进行MULTI-DATABASE

数据库

static = Static.objects.get(pk = 1)

现在,我有 1.静态数据 2.动态数据

静态数据必须存储在'default'中,并将其复制到'default_slave'

对于动态数据,查询首先需要判断动态数据的位置:'mac'或'pc'或'linux'

为了实现这一点,我在'静态表'中添加了一个字段:'query_on',其中包含['mac'或'linux'或'pc']

现在,使用查询集,我只是在写 query_on = static.query_on
dynamic = Dynamic.objects.get(static = static).using(alias=query_on) <'query_on'>_slave

这很好用,查询路由到需要执行的数据库,在这里我需要判断:

  1. 如果<'query_on'>_slave:连接已启动:请使用:<'query_on'>_slave OR
  2. 如果<'query_on'>:连接已关闭:请使用:using
  3. 如何去做?

    该应用程序的更多详细信息:

    1. 有一个数据库:默认(配置和分析数据库):用于维护配置数据和报告分析数据
    2. 有20个数据库(原始数据库):例如说:mac,linux,rhel,windows,pc ....(示例名称):用于收集原始数据,这不是分析过程
    3. 每个数据库都有一个或多个从属,命名约定为:default_slave_0,default_slave_1,default_slave_2以及其他数据库也是如此
    4. 现在需要首先每5分钟,30分钟,1小时查询分析数据....并且该查询需要发送到特定数据库,因为并非每个数据库都将携带分析所需的特定数据集。

      要做到这一点,我们需要

      1. 从(默认或其任何一个从属(奴隶部分是问题))
      2. 获取配置数据
      3. 一旦我们有了配置,我们就可以轻松地查看“原始”数据的位置
      4. 查询原始数据,收集结果并进行分析 - &gt;将其存储在“默认”数据库中。
      5. 现在所有30个(原始)和1个默认数据库都需要“同步”,因为我们在所有节点中保持相同的数据abse结构。

        现在,由于我们正在研究所有数据库的CPU峰值,因此使用“slave”数据库查询“原始”数据是有意义的。

        因此{{1}}的要求。我无法想象路由器在这里会有什么帮助?

1 个答案:

答案 0 :(得分:13)

使用路由器,你走在正确的轨道上。我假设您的两个数据库定义相同只是一个错字。

(仅供参考,我将使用the more sensitive master->follower来引用数据库层次结构)

在db_for_read()函数中,您可以检查与关注者的连接。这可能会产生更多的开销,但这是为数据库进行自动故障转移的成本。一个示例数据库定义是:

DATABASES = {
'follower': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'follower',
        'USER': 'root',
        'HOST': '54.34.65.24',
        'PORT': '3306',
    },
'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'application',
        'USER': 'root',
        'HOST': '54.34.65.23',
        'PORT': '3306',
    },
}  

您可以使用this example之类的快速尝试来测试连接。使用它的路由器可以满足您的需求:

from django.conf import settings
import socket


def test_connection_to_db(database_name):
    try:
        db_definition = getattr(settings, 'DATABASES')[database_name]
        s = socket.create_connection((db_definition['HOST'], db_definition['PORT']), 5)
        s.close()
        return True
    except (AttributeError, socket.timeout) as e:
        return False


class FailoverRouter(object):
    """A router that defaults reads to the follower but provides a failover back to the default"""

    def db_for_read(self, model, **hints):
        if test_connection_to_db('follower'):
            return 'follower'
        return 'default'

    def db_for_write(self, model, **hints):
        "Point all writes to the default db"
        return 'default'

    def allow_syncdb(self, db, model):
        "Make sure only the default db allows syncdb"
        return db == 'default'

这仍然会像你想要的那样在master中同步。此外,您可以使db_for_read()db_for_write()的逻辑更加复杂(例如,仅为查询报告的某些模型选择跟随者数据库。

我不知道这个test_connection()会对每次读取产生什么开销,因为这取决于MySQL服务器和超时。也许更好的架构是使用memcached缓存这些报告,或者只是解决奴隶问题,并首先在设置中更新数据库定义。