一.

因为认识有限, 在目前我的知识范围内, 还没有了解到可以使用原生的django框架实现当某个主数据库宕机后, 自动切换请求到另外一个主数据库上, 这里应该是要通过制作网络中间件去实现, 或者在DB层面进行配置, 至于mysql分布式集群的容灾措施, 主从切换,那完全就是DB的工作与知识范畴了

二.

这里假设项目具备了较大的业务量,服务器的垂直拓展已经不能很好的提高整个web server的性能, 所以只能从水平拓展这个方向着手, 优化的思路之一就是分库分表, 读写分离, 使用分布式集群数据库.

1.分库: 每个应用单独使用一个数据库(即便该应用所使用的数据库服务器宕机, 也不会影响到其他应用, 具备一定程度的容灾能力)

2.读写分离, 主数据库进行写,  从数据库进行读. 数据库实现主从复制, 保证数据一致性

三.

配置django项目使用多个数据

1) 配置数据库信息

DATABASES = {
    'default': {        
        'NAME': 'test_project',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'root',
        'PASSWORD': 'default_db',
        'HOST': '192.168.3.114',
        'PORT': 3306,
    },
    'users_write': {
        'NAME': 'test_project_users',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'root',
        'PASSWORD': 'users_write',
        'HOST': '192.168.3.8',
        'PORT': 3306,
    },
    'users_read': {
        'NAME': 'test_project_users',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'root',
        'PASSWORD': 'users_read',
        'HOST': '192.168.3.9',
        'PORT': 3306,
    },
    'robots_write': {
        'NAME': 'test_projects_robots',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'root',
        'PASSWORD': 'robots_write'
        'HOST': '192.168.3.25',
        'PORT': 3306,
    },
    'robots_read': {
        'NAME': 'test_projects_robots',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'root',
        'PASSWORD': 'robots_read'
        'HOST': '192.168.3.26',
        'PORT': 3306,
    },
}

这里配置了四个数据库, users_write, users_read 分别为服务于 users 应用的读写数据库, robots_write, robots_read 分别为服务于 robots 应用的读写数据库, 读写数据库之间必须要配置数据同步, 即主从数据库.

注意: 这里如果没有配置 default 数据库, 就必须为所有需要保存数据到数据库中的其他应用项指定一个数据库, 所以如果没有特殊需求, 必须配置上 default 数据库

2) 配置数据库和应用之间的映射路由文件路径

# 路径可以自定义, 这里是: 和 manage.py 文件同级目录下的 settings 包下的 database_router.py 文件内的 DbRouter 类 
DATABASE_ROUTERS = ['settings.database_router.DbRouter']

3)需要进行单独配置数据库的应用列表

ALONE_DB_APPS = ["users", "robots"]

4)定义数据库与应用进行映射的路由文件

在 settings/database_router.py 内

from django.conf import settings


class DbRouter(object):
    """
    数据库与应用的路由映射、读写配置
    """

    ALONE_DB_APPS = settings.__getattr("ALONE_DB_APPS")

    def db_for_read(self, model, **hints):
        """
        返回读操作的数据库
        """
        # 需要在模型中定义好各自的 app_label 属性值
        if model._meta.app_label in ALONE_DB_APPS:
            return model._meta.app_label + "read"
        else:
            return "defalut"

    def db_for_write(self, model, **hints):
        """
        返回写操作的数据库
        """
        if model._meta.app_label in ALONE_DB_APPS:
            return model._meta.app_label + "write"
        else:
            return "default"

    # 方法 db_for_read 返回读数据库, 方法 db_for_write 返回写数据库
    # 每个应用分别单独使用各自的数据库, 如果没有为某个应用配置数据库, 则使用默认数据库
    # 如果需要使用多个从数据库, 可以在这里进行随机返回一个读数据库即可

其他可能会使用到方法:

allow_relation(): 允许同一数据库中每个app的表之间差生关系(Foreignkey, OneToOneField, ManyToManyField)

allow_migrate(): 确定migrate操作统一,要app与对应映射的数据库统一

5)为需要配置数据库的应用的model添加 app_label属性值

    在 users 应用的 models.py 文件的模型内, 添加如下代码:

calss Users(model.Models): 

    ...

    class Meta:
        app_label = "users"  # 这个属性值就是标识该模型属于那个应用

    在 robots 应用的 models.py 文件的模型内, 添加如下代码

calss Robots(model.Models): 

    ...

    class Meta:
        app_label = "robots"  # 这个属性值就是标识该模型属于那个应用

6) 生成迁移文件, 进行迁移, 在各应用使用的数据库中生成数据表

# 生成所有模型的迁移文件
python manage.py makemigrations
 
# 创建应用users的模型表到 users_write 与 users_read 数据库中
python manage.py migrate --database=users_write
python manage.py migrate --database=users_read
 
# 创建应用robots的模型表到 robots_write 与 robots_read 数据库中
python manage.py migrate --database=robots_write
python manage.py migrate --datgbase=robots_read
 
# 如果还有使用default数据库的应用
python manage.py migrate --database=default

7)数据的备份与导入

备份

python manage.py dumpdata [appname] --database=dbname > appname_data.json

# 只导出某个模型的数据
python manage.py dumpdata [appname.modelname] --database=dbname > appname_data.json

导入

python manage.py loaddata [appname] --database=dbname appname_data.json

# 只导入某个模型的数据
python manage.py loaddata [appname.modelname] --database=dbname appname_data.json

8)

因为创建了数据库与应用的关系映射, 所以进行 CRUD 时会自动使用 应用(app) 自己的数据库, 如果没有配置关系映射, 就需要手动指定数据库.如:

查询

# 默认会使用'default' 数据库 进行查询.
Users.objects.all()
 
# 指定数据库
Users.objects.using('users_read').all()

手动指定的方式虽然更加灵活, 但是在 web server 中实用性似乎并不高, 个人没有使用过

四.多主从mysql数据库分布式集群搭建