zoukankan      html  css  js  c++  java
  • Mysql1 mysql主从同步,django实现读写分离

    MySql主从同步(基于docker)

    主从配置原理

    # 1 主从同步的原理
      mysql主从配置的流程大体如图:
      1)master会将变动记录到二进制日志里面;
      2)master有一个I/O线程将二进制日志发送到slave;
      3) slave有一个I/O线程把master发送的二进制写入到relay日志里面;
      4)slave有一个SQL线程,按照relay日志处理slave的数据;
    # 2 主从配置(两台服务器,用docker模拟),尽量环境完全一样,mysql版本一定一致
      -主库是docker中映射到宿主机的33307端口
      -从是docker中映射到宿主机的33306端口
      
    # 3 搭建步骤
    3.1 启动主库
    # 0 拉取mysql5.7镜像 之前已经拉过了
       # docker pull mysql:5.7
    1 在宿主机上创建目录#让docker挂载外部路径 mkdir /home/mysql mkdir /home/mysql/conf.d mkdir /home/mysql/data/ 创建my.cnf配置文件 touch /home/mysql/my.cnf 2 主库的配置 [mysqld]#配置的是服务端 vim my.cnf user=mysql#名字叫什么 character-set-server=utf8 default_authentication_plugin=mysql_native_password secure_file_priv=/var/lib/mysql expire_logs_days=7 sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION max_connections=1000 server-id=100#主库需要写一个id号,同一局域网内注意要唯一 log-bin=mysql-bin#需要开启blog日志,让从库读日志 3 启动主库 docker run -di -v /home/mysql/data/:/var/lib/mysql -v /home/mysql/conf.d:/etc/mysql/conf.d -v /home/mysql/my.cnf:/etc/mysql/my.cnf -p 33307:3306 --name mysql-master -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7 3.2 启动从库 1 在宿主机上创建目录 mkdir /home/mysql2 mkdir /home/mysql2/conf.d mkdir /home/mysql2/data/ 创建my.cnf配置文件 touch /home/mysql2/my.cnf 2 从库的配置 [mysqld] user=mysql character-set-server=utf8 default_authentication_plugin=mysql_native_password secure_file_priv=/var/lib/mysql expire_logs_days=7 sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION max_connections=1000 server-id=101#从库也要设置id号,不能重复 ## 开启二进制日志功能,以备Slave作为其它Slave的Master时使用 log-bin=mysql-slave-bin ## relay_log配置中继日志 relay_log=edu-mysql-relay-bin 3 启动从库 docker run -di -v /home/mysql2/data/:/var/lib/mysql -v /home/mysql2/conf.d:/etc/mysql/conf.d -v /home/mysql2/my.cnf:/etc/mysql/my.cnf -p 33306:3306 --name mysql-slave -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7 3.3 连到主库,进行配置 mysql -h 10.0.0.200 -P 33307 -u root -p123456 #装mysql客户端的机器去连接 #在主库创建用户并授权 ##创建test用户(root用户不允许发送数据,需要创建其他用户,给他授权) create user 'test'@'%' identified by '123';#@'%'从所有ip都能访问,identified by密码 ##授权用户 grant all privileges on *.* to 'test'@'%' ;#all privileges代表所有权限,*.*所有数据库和表权限 ###刷新权限 flush privileges; #查看主服务器状态(显示如下图) show master status; #可以看binlog日志 ## 显示 File mysql-bin.000003 binlog日志文件名字 Position 888 文件记录当前所处位置 ## 如果从库那边来做,需要指定复制文件名,还有哪个位置开始复制 3.4 连接到从库,进行配置 mysql -h 10.0.0.200 -P 33306 -u root -p123456 #配置详解 /* change master to master_host='MySQL主服务器IP地址', master_user='之前在MySQL主服务器上面创建的用户名', 以哪个用户来复制日志 master_password='之前创建的密码', master_log_file='MySQL主服务器状态中的二进制文件名', 依据的日志文件是哪个 master_log_pos='MySQL主服务器状态中的position值'; 开始的位置是哪 */ #命令如下 change master to master_host='10.0.0.200',master_port=33307,master_user='test',master_password='123',master_log_file='mysql-bin.000003',master_log_pos=0; #master_log_pos可以写查到的888。可以写0,代表把之前所有操作记录都复制过去 #启用从库 start slave; #查看从库状态(如下图) show slave statusG;

     这两个都必须是yes,一个是IO线程,一个是SQL线程。就可以完成主从功能

    ## 测试主从同步
    #在主库上创建数据库test1
    create database test1;
    use test1;
    #创建表
    create table tom (id int not null,name varchar(100)not null ,age tinyint);
    #插入数据
    insert tom (id,name,age) values(1,'xxx',20),(2,'yyy',7),(3,'zzz',23);
    
    #在从库上查看是否同步成功
    #查看数据库
    show database;
    use test1;
    #查看表
    show tables;
    #查看数据
    select * from test1;

    注意:同步是异步操作,所以会有一些延迟(主库进去了,从库还没有)

    解决方法:去主库里创建,从库查的时候,先返回一个空表示创建成功。再发一次请求查的时候(进详情页面时),数据就已经有了

    django实现读写分离

    手动操作

    # 1 写相关的操作,放到主库,读相关的操作,到从库上
    
    # 2 配置文件中:
    #注:如想对部分app迁移库操作,后面加上名字makemigrations [appname],migrate [appname]
    # makemigrations
    # migrate #直接migrate只会同步默认default数据库(不是配置第一个)
    数据迁移的时候,通过它来指定,同步到哪个库
    migrate --database=db1    # 迁移到db1数据库,如果是主从数据库,只要迁移到主库就可以了
    
    # 3 主库,从库
    default是主库
    db1是从库
    
    migrate app01 --databse="db1" # app01数据库迁移到db1数据库
    
    # 4 手动操作(queryset对象)
    ret=Book.objects.all().using("db1") # 读取db1数据库中的数据,必须是queryset对象

    下面用两个sqlite对象来演示

     # settings.py

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        },
        'db1': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite4'),   # 名字不能重复
        }
    }

    urls.py

    from django.contrib import admin
    from django.urls import path
    from app01 import views
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('', views.index),
    ]

    models.py

    from django.db import models
    
    class Book(models.Model):
        id = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)

    views.py

    from django.shortcuts import render,HttpResponse
    from app01 import models
    # Create your views here.
    def index(request):
        # 1发送一次请求,创建一条记录(创建在主库)
        ret = models.Book.objects.create(name='西行纪')
        print(ret)
        # 2 查询去从库查
        # 还是从default上查
        # ret = models.Book.objects.all().first()
        # 指定从db1上查,queryset对象.using('db1')
        ret = models.Book.objects.all().using('db1').first()    # 使用db1数据库
        # ret = models.Book.objects.all().using('default').first()  # 使用默认数据库
        print(ret)
        return HttpResponse('ok')

    自动做(通过配置,程序,读去从库读,写去主库写)[推荐]

    # 4 自动做(通过配置,程序,读去从库读,写去主库写)
    # 写一个router
    在项目路径下创建db_router.py(在app01路径下也行,在setting中路径配置要对)
    在里面写一个类    # 类名随便命名
    class Router1:    
            def db_for_read(self, model, **hints):
                    return 'db1'
    
            def db_for_write(self, model, **hints):
                    return 'default'
    
    #在setting中配置
    DATABASE_ROUTERS = ['db_router.Router1',]
    # 只要是写的操作,都到default上,只要是读的操作,都到db1上了

    此处db_router放在app01路径下 

     db_router.py

    class Router1:
        def db_for_read(self, model, **hints):
            # 以后,只要是读相关操作,都去db1上
            return 'db1'
    
        def db_for_write(self, model, **hints):
            # 只要是写相关操作,都是default
            return 'default'

    settings.py追加下面配置

    DATABASE_ROUTERS = ['app01.db_router.Router1',]

    views.py

    from django.shortcuts import render,HttpResponse
    from app01 import models
    # Create your views here.
    def index(request):
        # 测试自动读写分离
        # ret = models.Book.objects.create(name='西游记')
        # print(ret)
    
        ret = models.Book.objects.all().first() # 在setting中配置了读写分离的类,这里自动从读的库中读数据
        print(ret.name)
        return HttpResponse('ok')

    具体到某个表,只去某个库读,写
    # 5 具体到某个表,只去某个库读,写
    一主多从,通过random
    分库分表:user在其中一个库,book表在另一个库    # 存可以分app

    db_router.py

    class Router1:
        def db_for_read(self, model, **hints):
            # 以后,只要是读相关操作,都去db1上
            if model._meta.app_label == 'app01':    # 判断如果是app01的库,到哪个库里去
                return 'db1'
            print(str(model._meta)=='app01.book')    # 可以判断是哪个表,然后去哪个库
            return 'db1'
    
        def db_for_write(self, model, **hints):
            # 只要是写相关操作,都是default
            return 'default'
  • 相关阅读:
    UML类图图示样例
    在WSSv3中通过Javascript和创建Feature扩展站点的动作菜单
    LINQ之Select各种操作
    TroubleShoot: SharePoint工作流不能自动启动
    TroubleShoot:页面上WebPart显示错误
    ECMAScript对列表项的增删改查
    隐藏SharePoint查看所有内容及回收站
    Windows2000计划任务对机器进行重新启动
    CF576E Painting Edges
    CF1491H Yuezheng Ling and Dynamic Tree
  • 原文地址:https://www.cnblogs.com/ludingchao/p/14083578.html
Copyright © 2011-2022 走看看