总结: 简单点说 不论是mysql主从还是redis主从,其核心原理在于通过日志同步执行的更改命令,一般主库用来写,从库用来读。
这里采用docker在同一台机器上模拟两台mysql服务器
# 主库的配置文件 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 # 开启binlog日志(二进制日志功能,可以随便取(关键))
# 从库配置文件
[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
# 开启二进制日志功能,以备Slave作为其它Slave的Master时使用
log-bin=mysql-slave-bin
# relay_log配置中继日志
relay_log=edu-mysql-relay-bin
# 使用docker 启动mysql容器,映射目录 data,my.cnf master
docker run -di -v /py20/mysql/data/:/var/lib/mysql/ -v /py20/mysql/conf.d:/etc/mysql/conf.d -v /py20/mysql/my.cnf:/etc/mysql/my.cnf -p 3306:3306 --name mysql-master -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
# 使用docker 启动mysql容器,映射目录 data,my.cnf
docker run -di -v /py20/mysql2/data/:/var/lib/mysql -v /py20/mysql2/conf.d:/etc/mysql/conf.d -v /py20/mysql2/my.cnf:/etc/mysql/my.cnf -p 3307:3306 --name mysql-slave -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
# 从库要复制 bin-log日志---》使用用户复制---》在主库创建用户并授予权限--》root用户不行
-这个用户连接到主库上,复制数据,需要所有权限
1. 进入容器中连接mysql
docker exec -it 76c9727e709b /bin/bash
2. ##创建test用户
create user 'test'@'%' identified by '123';
##授权用户
grant all privileges on *.* to 'test'@'%' ;
###刷新权限
flush privileges;
#查看主服务器状态
show master status;
3. # 连接从库
# 从库中连接主库账户
change master to master_host='139.5.60.54',master_port=3307,master_user='test',master_password='123',master_log_file='mysql-bin.000003',master_log_pos=0;
#启用从库
start slave;
#查看从库状态(如下图)
show slave status\G; # 双yes就成功了
django读写分离 基于mysql主从同步的基础实现
1. 数据库配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'HOST': ip,
'USER': user,
'PASSWORD': password,
'NAME': database-master,
'PORT': '3306',
'CHARSET': 'utf-8',
},
'slave': {
'ENGINE': 'django.db.backends.mysql',
'HOST': ip,
'USER': user,
'PASSWORD': password,
'NAME': database-slave,
'PORT': '3307',
'CHARSET': 'utf-8',
},
}
2. 使用
1. 手动指定 .objects.using('slave') 默认是default
2. 写一个路由自动读写分离
class DatabaseAppsRouter(object):
def db_for_read(self, model, **hints):
# 从models中取出表名---》通过这个可以更细粒度的控制哪个表哪个库查
'''可以通过model进行更细粒度的控制进行分库分表'''
return 'slave'
def db_for_write(self, model, **hints):
return 'default'
# 需要在配置文件中配置
DATABASE_ROUTERS = ['django_databases.db_routers.DatabaseAppsRouter']
class DBRouter(object):
def db_for_read(self, model, **hints):
"""
Reads go to a randomly-chosen replica.
"""
if model._meta.app_label == 'monitor':
return 'monitor'
elif model._meta.app_label == 'analysis':
return 'analysis'
else:
return random.choice(['slave'])
# return random.choice(['slave'])
def db_for_write(self, model, **hints):
"""
Writes always go to primary.
"""
if model._meta.app_label == 'analysis':
return 'analysis'
return 'default'
def allow_relation(self, obj1, obj2, **hints):
"""
Relations between objects are allowed if both objects are
in the primary/replica pool.
"""
db_list = ('default', 'slave')
if obj1._state.db in db_list and obj2._state.db in db_list:
return True
return None
def allow_migrate(self, db, app_label, model=None, **hints):
return True