首页 文章

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

提问于
浏览
14

我有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_slave

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

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

这可能吗 ?我可以手动测试连接并继续前进吗?

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

需要一些解决方案/提示 raw queries 以及 orm queries

路由器的概念看起来不错,但是奴隶的后备不可达,我不知道这种可能性 .

UPDATE

如何进行MULTI-DATABASE

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',
    },
}  
'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',
    },
}

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

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

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

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

现在,使用查询集,我只是在写 static = Static.objects.get(pk = 1)
query_on = static.query_on dynamic = Dynamic.objects.get(static = static).using(alias=query_on)

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

  • 如果 <'query_on'>_slave :连接已启动:使用: <'query_on'>_slave

  • 如果 <'query_on'>_slave :连接已关闭:使用: <'query_on'>

怎么去那?

Further details for the application:

  • 有一个数据库:默认(配置和分析数据库):用于维护配置数据和报告分析数据

  • 有20个数据库(原始数据库):例如说:mac,linux,rhel,windows,pc ....(示例名称):用于收集原始数据,这不是分析流程

  • 每个数据库都有一个或多个从属,命名约定为:default_slave_0,default_slave_1,default_slave_2等等,对于其他数据库也是如此

现在,需要首先每5分钟,30分钟,1小时查询分析数据....并且该查询需要发送到特定数据库,因为并非每个数据库都将携带分析所需的特定数据集 .

要做到这一点,我们需要

  • 从中获取配置数据(默认或其任何一个从属(从属部分是问题))

  • 一旦我们有了配置,我们就可以轻松查看"raw"数据的位置

  • 查询原始数据,并收集结果并进行分析 - >将其存储在"default"数据库中 .

现在所有30个(原始)和1个默认数据库都需要“同步”,因为我们在所有节点中保持相同的数据abse结构 .

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

因此需要 using . 我无法想象路由器在这里会有什么帮助?

1 回答

  • 10

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

    (仅供参考,我将使用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缓存这些报告,或者只是解决奴隶问题,并首先在设置中更新数据库定义 .

相关问题