Django主从数据库分离配置

数据库主从配置,django

发表时间:2020-08-25

对网站的数据库作读写分离(Read/Write Splitting)可以提高性能,在Django中对此提供了支持,下面我们来简单看一下。注意,还需要运维人员作数据库的读写分离和数据同步 -DBA。

配置数据库

我们知道在Django项目的settings中,可以配置数据库,除了默认的数据库,我在下面又加了一个db2。因为是演示,我这里用的是MySQL 。

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'AAAA',
        'HOST': 'XXXXX',
        'PORT': 3306,
        'USER': 'root',
        'PASSWORD': '1qaz!QAZ',
        'CHARSET': 'utf8',
        'TIME_ZONE': 'Asia/Shanghai',
        },
    'slave1': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'AAAA_slave1',
        'HOST': 'XXXXX',
        'PORT': 3306,
        'USER': 'root',
        'PASSWORD': '1qaz!QAZ',
        'CHARSET': 'utf8',
        'TIME_ZONE': 'Asia/Shanghai',
    },

}

# 数据库路由配置
DATABASE_ROUTERS = [
    # 'common.db_routers.MultiDbRouter', # 多数据库配置
    'common.db_routers.MasterSlaveRouter',  # 主从数据库路由配置
]

迁移文件

其实第二步迁移默认有参数python manage.py migrate --database default ,在默认数据库上创建表。因此完成以上迁移后,执行python manage.py --database slave1,再迁移一次,就可以在slave1上创建相同的表。

读写分离

手动读写分离
在使用ORM 调用数据库时,通过.using(db_name)来手动指定要使用的数据库

自动读写分离

通过配置数据库路由,来自动实现,这样就不需要每次读写都手动指定数据库了。数据库路由中提供了四个方法。这里这里主要用其中的两个:def db_for_read()决定读操作的数据库,def db_for_write()决定写操作的数据库。

定义Router类
新建db_route.py脚本,定义Router类:

import random


# class MultiDbRouter:
#     """多数据库路由"""
#
#     @staticmethod
#     def db_for_read(model, **hints):
#         if model._meta.app_label == 'ar_map':
#             return 'slave1'
#         return 'default'
#
#     @staticmethod
#     def db_for_write(model, **hints):
#         if model._meta.app_label == 'ar_map':
#             return 'slave1'
#         return 'default'
#
#     @staticmethod
#     def allow_relation(obj1, obj2, **hints):
#         return None
#
#     @staticmethod
#     def allow_migrate(db, app_label, model_name=None, **hints):
#         return True


class MasterSlaveRouter:
    """主从复制路由"""

    @staticmethod
    def db_for_read(model, **hints):
        '''指定xxx_app 读数据时,使用指定setting配置的数据库xxx'''
        if model._meta.app_label == 'xxx_app':
            return 'xxx'
        return random.choice(('slave1', ))

    @staticmethod
    def db_for_write(model, **hints):
        '''指定xxx_app 写的时候,使用指定setting配置的数据库xxx'''
        if model._meta.app_label == 'xxx_app':
            return 'xxx'
        return 'default'

    @staticmethod
    def allow_relation(obj1, obj2, **hints):
        return None

    @staticmethod
    def allow_migrate(db, app_label, model_name=None, **hints):
        '''  python manage.py migrate --database=slave1
            django默认迁移 default 数据库
        '''
        return True
'''
稍微追溯一下源码, 当需要一个db时, 拿数据库的manager举例, 会通过django.db的router去获取

而router就是django.db.utils中定义的一个类, 它使用了setttings.py中DATABASE_ROUTERS配置. 

/home/liwuang/.pyenv/versions/3.6.5/lib/python3.6/site-packages/django/db/utils.py
'''

配置Router
settings.py中已经指定DATABASE_ROUTERS

DATABASE_ROUTERS = [
    # 'common.db_routers.MultiDbRouter', # 多数据库配置
    'common.db_routers.MasterSlaveRouter',  # 主从数据库路由配置
]

可以指定多个数据库路由,比如对于读操作,Django将会循环所有路由中的db_for_read()方法,直到其中一个有返回值,然后使用这个数据库进行当前操作。

一主多从方案

网站的读的性能通常更重要,因此,可以多配置几个数据库,并在读取时,随机选取,比如:

class Router:
    def db_for_read(self, model, **hints):
        """
        读取时随机选择一个数据库
        """
        import random
        return random.choice(['db2', 'db3', 'db4'])

    def db_for_write(self, model, **hints):
        """
        写入时选择主库
        """
        return 'default'

分库分表

在大型web项目中,常常会创建多个app来处理不同的业务,如果希望实现app之间的数据库分离,比如app01走数据库db1,app02走数据库

class Router:
    def db_for_read(self, model, **hints):
        if model._meta.app_label == 'app01':
            return 'db1'
        if model._meta.app_label == 'app02':
            return 'db2'

    def db_for_write(self, model, **hints):
       if model._meta.app_label == 'app01':
            return 'db1'
       if model._meta.app_label == 'app02':
            return 'db2'

 

参考地址:https://www.pythonf.cn/read/140551

你可能感兴趣的:(【Django】)