1. 程式人生 > 實用技巧 >MySQL主從搭建,讀寫分離

MySQL主從搭建,讀寫分離

一、主從配置

     

# mysql主從配置的流程大體如圖:

1)master會將變動記錄到二進位制日誌裡面;

2)master有一個I/O執行緒將二進位制日誌傳送到slave;

3) slave有一個I/O執行緒把master傳送的二進位制寫入到relay日誌裡面;

4)slave有一個SQL執行緒,按照relay日誌處理slave的資料;

二、操作

  正常是準備兩臺安裝好Mysql的伺服器,這裡就用Docker來做演示

  用Docker拉起兩個mysql容器,步驟如下: 

# 拉取mysql5.7映象
docker pull mysql:5.7
#在home目錄下建立mysql資料夾,下面建立data和conf.d資料夾
mkdir /home/mysql mkdir /home/mysql/conf.d mkdir /home/mysql/data/ # 建立my.cnf配置檔案 touch /home/mysql/my.cnf mkdir /home/mysql2 mkdir /home/mysql2/conf.d mkdir /home/mysql2/data/ touch /home/mysql2/my.cnf # 主庫配置 [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=100 log-bin=mysql-bin [client] default-character-set=utf8 [mysql] default-character-set=utf8 # 從庫配置 [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 log-bin=mysql-slave-bin relay_log=edu-mysql-relay-bin [client] default-character-set=utf8 [mysql] default-character-set=utf8 # 拉起容器 #啟動主庫容器(掛載外部目錄,埠對映成33307,密碼設定為123456) 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 #啟動從庫容器(掛載外部目錄,埠對映成33306,密碼設定為123456) 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

遠端連線入主庫和從庫

#連線主庫
mysql -h 172.16.209.100 -P 33307 -u root -p123456
#在主庫建立使用者並授權
##建立test使用者
create user 'test'@'%' identified by '123';
##授權使用者
grant all privileges on *.* to 'test'@'%' ;
###重新整理許可權
flush privileges;
#檢視主伺服器狀態(顯示如下圖)
show master status;

    

#連線從庫
mysql -h 172.16.209.100 -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='101.133.225.166',master_port=33307,master_user='test',master_password='123',master_log_file='mysql-bin.000003',master_log_pos=736;
#啟用從庫
start slave;
#檢視從庫狀態(如下圖)
show slave status\G;

              

    若是Slave_IO_Running為Connecting:則可能是防火牆問題

# //臨時關閉
systemctl stop firewalld
# //禁止開機啟動防火牆
systemctl disable firewalld  

三、Django實現讀寫分離:

  配置settings:

DATABASES = {
    # 只寫
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'test',
        'USER': 'root',
        'PASSWORD': '123456',
        'HOST': '10.0.0.200',
        'PORT': 33307,

    },
    # 只讀
    'db1': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'test',
        'USER': 'root',
        'PASSWORD': '123456',
        'HOST': '10.0.0.200',
        'PORT': 33306,

    }
}

  手動指定:

def index(request):
    # 手動指定哪個庫
    res = models.Book.objects.using('default').create(name='jpm', price=66.3)
    print(res.name)
    res1 = models.Book.objects.using('db1').all().first()
    print(res1.name)
    return HttpResponse('ok')

  自動配置:

# 在任意位置建立一個py檔案:

-read&write.py

class Routers:

    def db_for_read(self, model, **hints):
        return 'db1'  # 只讀配置

    def db_for_write(self, model, **hints):
        return 'default'  # 只寫配置


# 然後在settings裡面註冊:
# 註冊
DATABASE_ROUTERS = ['read&write.Routers']

  更細的:

#  更細粒度
class Routers:
    def db_for_read(self, model, **hints):
        if model._meta.model_name == 'book':
            return 'db1'
        else:
            return 'default'

    def db_for_write(self, model, **hints):
        return 'default'

  tips:

# 在資料庫遷移時,可以指定把哪個app的表結構遷移到哪個庫
python manage.py migrate app01 --database=default