简介

什么是数据库读写分离

读写分离,基本的原理是让主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库处理SELECT查询操作。数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库。

为什么要搞数据库读写分离

在实际的生产环境中,对数据库的读和写都在同一个数据库服务器中,是不能满足实际需求的。无论是在安全性、高可用性还是高并发等各个方面都是完全不能满足实际需求的。因此,通过主从复制的方式来同步数据,再通过读写分离来提升数据库的并发负载能力。

配置主从同步的基本步骤

有很多种配置主从同步的方法,可以总结为如下的步骤:

  1. 在主服务器上,必须开启二进制日志机制和配置一个独立的ID
  2. 在每一个从服务器上,配置一个唯一的ID,创建一个用来专门复制主服务器数据的账号
  3. 在开始复制进程前,在主服务器上记录二进制文件的位置信息
  4. 如果在开始复制之前,数据库中已经有数据,就必须先创建一个数据快照(可以使用mysqldump导出数据库,或者直接复制数据文件)
  5. 配置从服务器要连接的主服务器的IP地址和登陆授权,二进制日志文件名和位置

实践阶段

测试环境

Mysql5.7.29主服务器:ubuntu16
Mysql5.7.29从服务器:ubuntu16上的docker容器
WEB框架:Django1.8

docker容器安装(若在不同服务器搭建数据库,此步可省略)

docker三个核心概念: Repository(仓库) -> Image(镜像) -> Container(容器)

卸载可能存在的旧版本

sudo apt-get remove docker docker-engine docker-ce docker.io

更新apt包

sudo apt-get update

安装以下包以使apt可以通过HTTPS使用存储库(repository):

sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common

在这里插入图片描述
添加GPG密钥

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

设置stable存储库

sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

再次更新apt包

sudo apt-get update

安装最新版本的Docker CE(社区免费版)

sudo apt-get install -y docker-ce

在这里插入图片描述

验证docker: sudo docker version 或 sudo docker info
在这里插入图片描述

查看docker服务是否启动

systemctl status docker

![在这里插入图片描述](https://img-blog.csdnimg.cn/20200324163304257.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1B5dGhvbmljYw==,size_16,color_FFFFFF,t_70
经典的hello world

运行docker命令时需要root权限或者加sudo

sudo docker pull hello-world拉取dockerHub上的hello-world镜像
sudo docker images查看镜像信息
在这里插入图片描述
可以看到已存在hello-world镜像

**字段解释**
	REPOSITORY: 来自于哪个仓库;
	TAG: 镜像的标签信息,比如 5.7、latest 表示不同的版本信息;
	IMAGE ID: 镜像的 ID, 如果您看到两个 ID 完全相同,那么实际上,它们指向的是同一个镜像,只是标签名称不同罢了;
	CREATED: 镜像最后的更新时间;
	SIZE: 镜像的大小,优秀的镜像一般体积都比较小

生成该镜像的实例容器(镜像与容器的关系就像类和实例类对象)

sudo docker run hello-world

在这里插入图片描述
有以上输出,表示docker安装成功.

Docker服务相关命令

开启Docker服务
systemctl start docker

停止Docker服务
systemctl stop docker

重启Docker服务
systemctl restart docker

开机自启Docker服务
systemctl enable docker

创建mysql容器

家目录下创建mysql_slave目录作为容器挂载数据卷
mkdir mysql_slave

进入mysql_slave目录
cd mysql_slave

创建data目录
mkdir data

将宿主机的mysql配置文件目录拷到当前数据卷目录下
cp -a /etc/mysql/mysql.conf.d ./

将配置文件拷贝过来后,编辑mysql.conf.d目录下的mysqld.cnf 文件

宿主机中的mysql做为主服务器,其server-id设为1,从服务器只要不是1都行,这边取2
server-id = 2

创建容器(如果没有该镜像,则自动从dockerHub拉取该镜像并创建容器)
docker run -id
-p 3308:3306
–name=mysql-slave
-e MYSQL_ROOT_PASSWORD=mysql
-v /root/mysql_slave/data:/var/lib/mysql
-v /root/mysql_slave/mysql.conf.d:/etc/mysql/mysql.conf.d
mysql:5.7.29

参数解释:
-p 指定映射的端口,左边为宿主机端口,右边为容器端口,这样就可以通过映射的3308端口在宿主机以外的外部机器访问该容器中的mysql
-id 表示该容器作为守护进程在后台运行,创建后马上运行,但是不会进入shell终端,退出后也不会真正退出
–name 指定实例容器的名称
-e 指定数据库密码
-v 指定要挂载的目录或文件,必须写绝对路径,左边为宿主机路径,右边为容器路径
mysql:5.7.29 指定要创建的容器的镜像及其版本,由于宿主机中mysql是5.7.29版本,所以我们这里创建mysql5.7.29的容器

查看运行中的容器

docker ps

在这里插入图片描述

Mysql主从同步配置

宿主机中导出mysql主服务器sql文件

mysqldump -uroot -pmysql --all-databases --lock-all-tables > ~/master_db.sql

参数解释:
-u :用户名
-p :示密码
–all-databases :导出所有数据库
–lock-all-tables :执行操作时锁住所有表,防止操作时有数据修改
~/master_db.sql :导出的备份数据(sql文件)位置,可自己指定

在这里插入图片描述
在宿主机中根据映射的端口将sql文件导入容器数据库中

mysql -uroot -pmysql -h127.0.0.1 --port=3308 < ~/master_db.sql

编辑设置mysqld的配置文件,设置log_bin和server-id

sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf

在这里插入图片描述
在这里插入图片描述
重启mysql服务

sudo service mysql restart

在这里插入图片描述
登入mysql,创建用于从服务器同步数据使用的帐号并刷新缓存

mysql –uroot –pmysql

GRANT REPLICATION SLAVE ON *.* TO 'slave'@'%' identified by 'slave';

FLUSH PRIVILEGES;

在这里插入图片描述
获取主服务器的二进制日志信息(File为使用的日志文件名字,Position为使用的文件位置,这两个参数须记下,配置从服务器时会用到)

SHOW MASTER STATUS;

在这里插入图片描述
进入docker容器配置mysql从服务器

执行以下命令进入指定名称的容器的shell终端

docker exec -it mysql-slave bash

在这里插入图片描述
进入容器中的mysql数据库并设置连接到master主服务器

mysql -uroot -pmysql
change master to master_host='192.168.254.137', master_user='slave', master_password='slave',master_log_file='mysql-bin.000001', master_log_pos=590;

参数解释:
master_host:主服务器宿主机Ubuntu的ip地址
master_log_file: 前面查询到的主服务器日志文件名
master_log_pos: 前面查询到的主服务器日志文件位置

在这里插入图片描述
开启同步,查看同步状态
在这里插入图片描述

Django项目搭建
项目创建
django-admin startproject test2
应用创建
python manage.py startapp booktest
模板定义

为应用booktest下的视图index创建模板index.html,目录结构如下图:
在这里插入图片描述
打开templtes/booktest/index.html文件,定义代码如下:

<html>
<head>
    <title>案例</title>
</head>
<body>
<a href="/create/">创建</a>
<ul>
{%for book in list%}
    <li>{{book.btitle}}--<a href="/delete{{book.id}}/">删除</a></li>
{%endfor%}
</ul>
</body>
</html>
编辑设置文件

添加应用名称
在这里插入图片描述
定义模板文件路径
在这里插入图片描述
注释原有的sqlite连接配置,写入如下代码:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'test2',  # 数据库名字,
        'USER': 'root',  # 数据库登录用户名
        'PASSWORD': 'mysql',  # 数据库登录密码
        'HOST': '192.168.254.137',  # 数据库所在主机
        'PORT': '3306',  # 数据库端口
    },
    'slave': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'test2',  # 数据库名字,
        'USER': 'root',  # 数据库登录用户名
        'PASSWORD': 'mysql',  # 数据库登录密码
        'HOST': '192.168.254.137',  # 数据库所在主机
        'PORT': '3308',  # 数据库端口
    },
}

在这里插入图片描述

模型类编写

打开booktest/models.py文件,定义模型类源码如下

from django.db import models

# 定义图书模型类BookInfo
class BookInfo(models.Model):
    btitle = models.CharField(max_length=20)  # 图书名称
    bpub_date = models.DateField()  # 发布日期
    bread = models.IntegerField(default=0)  # 阅读量
    bcomment = models.IntegerField(default=0)  # 评论量
    isDelete = models.BooleanField(default=False)  # 逻辑删除


# 定义英雄模型类HeroInfo
class HeroInfo(models.Model):
    hname = models.CharField(max_length=20)  # 英雄姓名
    hgender = models.BooleanField(default=True)  # 英雄性别
    isDelete = models.BooleanField(default=False)  # 逻辑删除
    hcomment = models.CharField(max_length=200)  # 英雄描述信息
    hbook = models.ForeignKey('BookInfo')  # 英雄与图书表的关系为一对多,所以属性定义在英雄模型类中
迁移
安装pymysql
pip install pymysql

安装成功之后,在test2/_init_.py文件中加上如下代码:
import pymysql
pymysql.install_as_MySQLdb()

生成迁移文件
python manage.py makemigrations

执行迁移文件在数据库生成表
python manage.py migrate

打开数据库的命令行,查看当前所有表如下图:
在这里插入图片描述

测试数据

在数据库命令行中,复制如下语句执行,向booktest_bookinfo表中插入测试数据:

insert into booktest_bookinfo(btitle,bpub_date,bread,bcomment,isDelete) values
('射雕英雄传','1980-5-1',12,34,0),
('天龙八部','1986-7-24',36,40,0),
('笑傲江湖','1995-12-24',20,80,0),
('雪山飞狐','1987-11-11',58,24,0);

再复制如下语句执行,向booktest_heroinfo表中插入测试数据:

insert into booktest_heroinfo(hname,hgender,hbook_id,hcomment,isDelete) values
('郭靖',1,1,'降龙十八掌',0),
('黄蓉',0,1,'打狗棍法',0),
('黄药师',1,1,'弹指神通',0),
('欧阳锋',1,1,'蛤蟆功',0),
('梅超风',0,1,'九阴白骨爪',0),
('乔峰',1,2,'降龙十八掌',0),
('段誉',1,2,'六脉神剑',0),
('虚竹',1,2,'天山六阳掌',0),
('王语嫣',0,2,'神仙姐姐',0),
('令狐冲',1,3,'独孤九剑',0),
('任盈盈',0,3,'弹琴',0),
('岳不群',1,3,'华山剑法',0),
('东方不败',0,3,'葵花宝典',0),
('胡斐',1,4,'胡家刀法',0),
('苗若兰',0,4,'黄衣',0),
('程灵素',0,4,'医术',0),
('袁紫衣',0,4,'六合拳',0);
视图编写

打开booktest/views.py文件,定义视图代码如下:

from django.shortcuts import render,redirect
from booktest.models import *
from datetime import date

#查询所有图书并显示
def index(request):
	#使用从服务器进行读操作
    list=BookInfo.objects.using('slave').all()
    return render(request,'booktest/index.html',{'list':list})

#默认使用主服务器进行写操作
#创建新图书
def create(request):
    book=BookInfo()
    book.btitle = '流星蝴蝶剑'
    book.bpub_date = date(1995,12,30)
    book.save()
    #转向到首页
    return redirect('/')

#逻辑删除指定编号的图书
def delete(request,id):
    book=BookInfo.objects.get(id=int(id))
    book.delete()
    #转向到首页
    return redirect('/')
url路由配置

打开test2/urls.py文件,配置url如下:

from django.conf.urls import include, url
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    #引入booktest的url配置
    url(r'^',include('booktest.urls')),
]

在booktest应用下创建urls.py文件,代码如下:

from django.conf.urls import url
from booktest import views

urlpatterns=[
    url(r'^$',views.index),
    url(r'^delete(\d+)/$',views.delete),
    url(r'^create/$',views.create),
]
运行
python manage.py runserver 127.0.0.1

html界面中点击创建或删除后,由主服务器执行写操作,由从服务器同步主服务器数据执行读操作,可以看到渲染的数据在增加或减少
在这里插入图片描述

Logo

更多推荐