MySQL数据库的负载均衡:主从复制和读写分离

数据库进化之路

之前,我们了解了如何通过Nginx实现负载均衡。这时候就会陆续出现几个问题:

  1. Nginx将流量分配到了不同的Tomcat服务器上,为了保持数据的一致性,不同的Tomcat服务器应该操作同一个数据库。这样无论是访客被分配到了哪个Tomcat服务器上,其最终操作的都是一个数据库。最简单的做法就是配备一台专门的数据库服务器。如下图所示:
    file
  2. 然而这样做的话,相当于一台数据库服务器需要承载多台Tomcat服务器的数据库CRUD压力。Tomcat服务器的负载虽然被Nginx稀释了,数据库服务器的压力却依然很大。为了解决这个问题,我们希望也能够像Tomcat服务器一样有多台数据库服务器,这些数据库服务器要满足两个特点:
    A. CRUD操作被分流到多台数据库服务器上。
    B. 多台数据库服务器的数据需要实时同步。
    file
  3. 为了实现第2条的功能,我们需要实现数据库的“主从复制”和“读写分离”功能。
    A. 主从复制。一台主数据库服务器(Master),若干台从数据库服务器(Slave)。从数据库服务器实时同步主数据库服务器的数据。在MySQL中,实现主从复制不需要借助第三方软件,MySQL自带了相关的功能。其原理就是将主MySQL数据库的操作SQL语句以日志的方式保存下来,并复制到从MySQL数据库中,然后由从MySQL数据库执行日志中的SQL语句。
    B. 读写分离。数据库查询操作发送给从数据库服务器;数据库增删改操作发送给数据库主服务器。读写分离操作需要借助第三方软件,本文使用mycat实现。
    file

A1. 主从复制:环境搭建

1. 搭建3台数据库服务器。
我是在WorkStation下建立了3台虚拟机,每台虚拟机对应的IP地址如下:
file
2. 在服务器中安装MySQL数据库。
安装方法参考:http://www.moonlightgate.com/archives/173

3. MySQL客户端测试
三台服务器的MySQL安装好后,可以通过MySQL客户端测试一下,确保三台机器的MySQL都可以远程访问。
file

A2. 主从复制:主机Master操作步骤

1. 修改/etc/my.cnf
在文件中添加如下内容:

#以服务器IP地址作为server-id,随意取,确保不冲突即可
server-id=135
log_bin
#需要同步的数据库
binlog-do-db=royotech
#无需同步的数据库
binlog-ignore-db=mysql

2. 重启mysql服务

systemctl restart mysql

3. 查看并记录主数据库状态

mysql -uroot -p111111

然后

show master status

得到如下结果:
file
这里面最重要的信息是File和Position,120代表当前主数据库的位置。

A3. 主从复制:从机Slave1操作步骤

1. 删除auto.cnf文件

rm /usr/local/mysql/data/auto.cnf

注意:

  1. auto.cnf文件里面保存着mysql的uuid信息,由于我的测试环境是通过VMWare克隆出来的,因此三台MySQL服务器的uuid信息都相同,uuid冲突的情况下后面的操作会报错。
  2. 删除这个文件后重启mysql,会自动生成新的auto.cnf文件,这时里面的uuid就是全新的了。
  3. 不同安装方法auto.cnf的文件位置也不同。
    如果需要查找auto.cnf的位置,可以在mysql里面运行如下语句:

    user mysql;
    show variables like 'datadir';

2. 修改/etc/my.cnf
file
这里只需要添加一句:

server-id=136

3. 重启mysql服务

systemctl restart mysql

4. 登陆mysql,设置主MySQL连接信息

mysql -uroot -p111111

然后

stop slave

然后

change master to master_host='192.168.81.135',master_user='root',master_password='111111',master_log_file='localhost-bin.000001',master_log_pos=120;

然后

start slave

5. 查看从节点状态

show slave status\G

\G可以格式化输出,否则排版很乱,没法查看。
file
上面两个地方都是Yes的时候,说明操作成功了!

A4. 主从复制:从机Slave2操作步骤

和Slave1一样的操作

1. 删除auto.cnf文件

rm /usr/local/mysql/data/auto.cnf

2. 修改/etc/my.cnf
添加一句:

server-id=137

3. 重启mysql服务

systemctl restart mysql

4. 登陆mysql,设置主MySQL连接信息

mysql -uroot -p111111

然后

stop slave

然后

change master to master_host='192.168.81.135',master_user='root',master_password='111111',master_log_file='localhost-bin.000001',master_log_pos=120;

然后

start slave

5. 查看从节点状态

show slave status\G

file

A5. 主从复制:主从复制配置完成!测试一下

1. 在主MySQL中新建royotech数据库,新建user表
file

2. 在从MySQL中刷新一下
file
欧耶!同步过来了!

B1. 读写分离:环境搭建

1. 搭建Mycat服务器
在WorkStation中增加一台服务器用于安装Mycat,IP地址如下:
file

2. 在服务器中安装Mycat
第一步:下载Mycat安装包。
可以通过Mycat官网下载:http://www.mycat.io/
也可以通过本站下载:Mycat-server-1.6-RELEASE-20161028204710-linux.tar

第二步:上传、解压。

tar -zxvf Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz

然后将mycat复制到/usr/local/下

mycat /usr/local

第三步:放行8066(Mycat默认使用该端口号)端口。

firewall-cmd --zone=public --add-port=8066/tcp --permanent

然后

firewall-cmd --reload

B2. 读写分离:配置Mycat

1. 配置环境变量

vim /etc/profile

增加如下内容:

export MYCAT_HOME=/usr/local/mycat
export PATH=$MYCAT_HOME/bin:$PATH

file
然后:

source /etc/profile

2. 修改Mycat的server.xml和schema.xml配置文件
修改:/usr/local/mycat/conf/server.xml

    <user name="root">
        <property name="password">123456</property>
        <property name="schemas">TESTDB</property>
    </user>

这三个信息,是程序数据库接口连接Mycat时使用的“数据库名称”“用户名”“密码”,如果只是为了测试用,这三个信息可以不变。
修改:/usr/local/mycat/conf/schema.xml为以下内容

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

    <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"></schema>

    <dataNode name="dn1" dataHost="localhost1" database="royotech" />

    <dataHost name="localhost1" maxCon="1000" minCon="10" balance="3"
              writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="hostM1" url="192.168.81.135:3306" user="root" password="111111">
            <readHost host="hostS1" url="192.168.81.136:3306" user="root" password="111111" />
            <readHost host="hostS2" url="192.168.81.137:3306" user="root" password="111111" />
        </writeHost>
    </dataHost>
</mycat:schema>

balance=0:不开启读写分离,所有读操作发生在writeHost上
balance=1:所有读操作随机发送到readHost和备用的writeHost上
balance=2:所有读操作随机发送到writeHost和readHost上
balance=3:所有读操作只发送到readHost上。

file

3. 启动Mycat

mycat console

启动成功后,界面就不能关了。
启动Mycat时可能会遇到如下错误:

wrapper  | JVM exited while loading the application.
jvm 1    | Java HotSpot(TM) 64-Bit Server VM warning: Ignoring option MaxPermSize; support was removed in 8.0
jvm 1    | Unrecognized VM option 'AggressiveOpts'
jvm 1    | Error: Could not create the Java Virtual Machine.
jvm 1    | Error: A fatal exception has occurred. Program will exit.

修改/usr/local/mycat/conf/wrapper.conf,注释掉wrapper.java.additional.3=-XX:+AggressiveOpts即可:
file

B3. 读写分离:测试

1. 连接Mycat测试
file
如果能连接成功,则证明Mycat安装成功。

2. 测试读写分离
现在Slave1和Slave2中分别添加一条数据:
file
然后在Mycat中进行select测试,如果结果出现Slave1和Slave2中增加的内容,证明读写分离成功。
file

在CentOS8中配置JDK13、Tomcat9、MySQL5.6环境

准备和前提

1. 通过fileZilla和服务器建立连接。

连接方法参考:http://www.moonlightgate.com/archives/170

2. 安装JDK

2.1 安装思路。

JDK在Linux下的安装思路和在Windows下的安装思路类似:
A. 安装软件。其实就是上传文件和解压文件。
B. 配置两个环境变量:JAVA_HOME、BIN目录。

2.2 上传、解压、移动。

a. 压缩包jdk-13.0.1_linux-x64_bin.tar.gz上传到/usr/local/tmp目录
b. 解压压缩包

tar zxvf jdk-13.0.1_linux-x64_bin.tar.gz

c. 解压后的目录移动到/usr/local/jdk13

mv jdk-13.0.1 /usr/local/jdk13

2.3 配置环境变量。

vim /etc/profile

在文件中找到export部分,注释export行并增加以下内容:

#export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROL
export JAVA_HOME=/usr/local/jdk13
export PATH=$JAVA_HOME/bin:$PATH

export的作用是增加新的或修改已经存在的环境变量。
如果是修改已经存在的环境变量,需要注意在环境变量末尾加:$变量名。记住是冒号:(在Windows中是分号;)。

2.4 解析profile文件或重启服务器。

解析命令如下:

source /etc/profile

如果不解析,则配置不生效。

2.5 JDK安装完毕,测试一下。

file

3. 安装Tomcat

3.1 上传、解压、移动

a. 压缩包apache-tomcat-9.0.30.tar.gz上传到/usr/local/tmp目录
b. 解压压缩包

tar zxvf apache-tomcat-9.0.30.tar.gz

c. 解压后的目录移动到/usr/local/apache-tomcat-9

mv apache-tomcat-9.0.30 /usr/local/apache-tomcat-9

3.2 配置环境变量

vim /etc/profile

在文件中找到export部分,在上面的基础上修改为下面内容:

#export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROL
export JAVA_HOME=/usr/local/jdk13
export PATH=$JAVA_HOME/bin:$PATH

export TOMCAT_HOME=/usr/local/apache-tomcat-9
export CATALINA_HOME=/usr/local/apache-tomcat-9

4.3 解析profile文件或重启服务器。

解析命令如下:

source /etc/profile

如果不解析,则配置不生效。

4.4 Tomcat安装完毕,启动Tomcat。

file
注意:绿色的以.sh结尾的文件,是Linux中的可执行文件。运行.sh文件的命令为
./XXX.sh

4.5 配置防火墙,访问Tomcat。

方法A:直接停掉防火墙

systemctl stop firewalld

方法B:在firewalld里面放行8080端口

运行以下命令:

firewall-cmd --zone=public --add-port=8080/tcp --permanent

这条命令运行完成后,会将8080端口放行的内容添加到 /etc/firewalld/zones/public.xml中:
file
注意:在CentOS7之前的版本中,放行端口号是通过配置iptables完成的。
然后重启防火墙:

firewall-cmd --reload

4.6 大功告成,测试一下

file

4. 安装MySQL

4.1 上传、解压、移动

a. 压缩包mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz上传到/usr/local/tmp目录
b. 解压压缩包

tar zxvf mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz

c. 解压后的目录移动到/usr/local/mysql

mv mysql-5.6.46-linux-glibc2.12-x86_64 /usr/local/mysql

4.2 创建mysql专用用户组和用户,给mysql文件夹赋权

a. 创建用户组(groupadd 用户组名)

groupadd mysql

b. 创建用户(useradd -r用户名称 -g用户组名称)

useradd -r -g mysql mysql

c. 保证命令行当前在/usr/local/mysql中,为mysql目录赋权(注意最后的.前面有个空格)

[root@localhost mysql]# chgrp -R mysql .
[root@localhost mysql]# chown -R mysql .

4.3 注册MySQL服务

a. 确保/etc/my.cnf不存在,如果存在删除。
b. 保证命令行当前在/usr/local/mysql中,执行如下命令初始化数据库。

./scripts/mysql_install_db --user=mysql

运行完成后,会在/usr/local/mysql/support-files下自动生成一个my-default.cnf文件。
c. 复制上面的my-default.cnf文件到/etc/my.cnf

cp my-default.cnf /etc/my.cnf

d. 复制MySQL启动文件到自启动文件夹/etc/rc.d/init.d/下

cp mysql.server /etc/rc.d/init.d/mysql

注:mysql为service名称,其实可以按照个人爱好随便写。

4.4 启动MySQL

service mysql start

此时,如果在命令行里面输入mysql命令,还是无法使用的,原因是mysql命令文件目前位于/usr/local/mysql/bin文件夹下,想要直接在命令行里面使用mysql命令,mysql命令必须出现在/usr/bin/文件夹下。
这时只需要按照如下方法添加软连接即可:

ln -s /usr/local/mysql/bin/mysql /usr/bin/mysql

4.5 使用mysql命令报错解决

使用mysql命令时,可能会报如下错误:

mysql: error while loading shared libraries: libncurses.so.5: cannot open shared object file: No such file or directory

使用如下命令通过yum安装libncurses即可:

yum install libncurses*

4.6 修改MySQL的root用户密码

第一步:进入mysql数据库

use mysql

第二步:更新root用户的密码为111111

update user set  password = password("111111") where User = "root"

第三步:刷新权限使设定生效

flush privileges;

4.7 大功告成,本地测试一下:

file

4.8 配置以可以进行远程连接

截止到4.7,还是只能本机访问的,如果需要远程访问,还需要做如下配置。
第一步:赋予root用户远程连接权限。

grant all privileges on *.* to root@'%' identified by '111111' with grant option;
flush privileges;

第二步:开启3306端口。

firewall-cmd --zone=public --add-port=3306/tcp --permanent
firewall-cmd --reload

这时候,通过MySQL客户端就可以访问MySQL数据库啦。

MAVEN的安装及通过Eclipse建立一个简单的MAVEN项目

MAVEN好学吗?

话说那天在B站上看到个视频说MAVEN很重要,是学习JAVA中必须学习的内容。进而搜索了下,搜到了个100多小时的教程。瞬间被吓到了~~
看视频的体量,确实是很重要,估计也很难。
然而,大家千万不要和我一样被误导。
任何一门技术做到极致都是很难的,但是MAVEN入门并不难,看完这个帖子,估计你也能把MAVEN用起来。至于用到什么程度,那就看你后面自己怎么深入了。

1.什么是MAVEN

maven英文原意是:专家、内行的意思。
有关MAVEN的介绍,大家自己百度下。
MAVEN的读音是[ˈmeɪvn](“mei wen”),别读成“ma wen”。
我始终认为,一个技术人员的英文水平很大程度上决定了他的高度...
说多了,咱们开始进入主题!

2.为什么要用MAVEN

如果用一句话介绍MAVEN的话,就是帮助JAVA项目管理jar包的工具。以前jar包需要东找西找,jar包之间也有着各种依赖关系,特别容易搞错。
有了MAVEN就一站式搞定,简单的配置一下,jar包导入和依赖关系等都帮你自动搞定。
当然MAVEN还有更高级的功能,大家自行深入学习哈。

3.MAVEN安装

安装文件下载
MAVEN是APACHE的项目,可以通过以下网址下载MAVEN安装文件。
https://maven.apache.org/
我写这篇文章的时候MAVEN的最新版本是3.6.3,加之我是Windows系统,所以选择下载:apache-maven-3.6.3-bin.zip
file
下载完成后,我解压到以下位置:
F:\apache-maven-3.6.3
file
配置环境变量
两个地方:

  1. 增加MAVEN_HOME变量,值为:F:\apache-maven-3.6.3
  2. PATH变量追加增加:F:\apache-maven-3.6.3\bin
    修改MAVEN本地仓库
    这个地址说的是如果自动下载了jar包,这些jar包保存在本地电脑上的位置。
    这个地址默认是在C盘,一般都会改放在其它盘符。
    修改F:\apache-maven-3.6.3\conf\settings.xml
    file
    修改MAVEN远程仓库地址
    这个地址说的是从哪里下载jar包。
    默认的地址是国外服务器地址,下载速度太慢。所以改为阿里云的镜像地址(啰嗦下,阿里云里面各种镜像基本上都是与国外服务器实时同步的,可以说是个高速版的大宝库。建议大家自行探索下)。
    增加以下内容至settings.xml

    <mirror>
    <id>alimaven</id>
    <name>aliyun maven</name>
    <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
    <mirrorOf>central</mirrorOf>
    </mirror>

    file

    4.Eclipse中配置MAVEN

    A. 最新版的Eclipse中默认带了MAVEN插件,只需要将第三步中修改的settings.xml文件地址配置到插件上即可。
    file
    B.这个地方勾选上,每次启动Eclipse都会自动更新jar包仓库。
    file

到此为止,MAVEN的安装和配置就完成了!!!欢呼!!欢呼!!

5.MAVEN中Web项目的目录结构

先通过Eclipse新建一个基于MAVEN的web项目
A.从MAVEN新建项目
file
B.使用默认的位置
file
C.选择apache下的webapp骨架
file
D.填写项目信息
file
然后呢?你就会开心的发现,在你的项目里面,已经自动帮你下载好了各种Web项目可能用到的jar包
file
还没完,你还需要手动建些文件夹
以下是MAVEN对于web项目的目录结构要求
file
从Eclipse里面可以看到,MAVEN默认创建的骨架中还少几个文件夹。不要问为什么?我也不知道。反正大家按照提示手工建立那几个文件夹就是了。

6.使用MAVEN配置MySQL数据库

MAVEN的核心就是项目创建时自动生成的那个pom.xml文件。
MAVEN的使用也基本上都是围绕这个XML文件展开的。
比如说我们现在的项目要链接MySQL数据库,在没有MAVEN的时候,需要手工下载导入jar包。现在有MAVEN了,这个工作就变得很简单了。只需要将下面的代码加到pom.xml的<dependencies>标签下面

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.6</version>
</dependency>

然后ctrl+s保存下,和MySQL相关的jar包就自动下载并加载好了。
这下体会到MAVEN的意义了吧?

7.使用MAVEN配置Oracle数据库

说了MySQL,为啥还要专门说Oracle呢?
是因为我第一次使用MAVEN的时候就是想添加Oracle依赖,但是无论如何都添加不上,一直报错。
经过多方查找,竟然是因为版权!
Oracle估计没有开放版权,换句话说,你想用Oracle的jar包,你就得自己下载,然后自己导入到MAVEN仓库中,再通过MAVEN添加依赖。
具体做法如下:

  1. 在Oracle官网,或者本地安装的Oracle中找到对应的jar包。由于我本地安装了Oracle,确定jar包位置:F:\ORACLE_WORKPLACE\Oracle18c\jdbc\lib\ojdbc8.jar
  2. 打开cmd,运行以下代码:
    mvn install:install-file -DgroupId=com.oracle -DartifactId=ojdbc8 -Dversion=11.2.0.1.0 -Dpackaging=jar -Dfile=F:\ORACLE_WORKPLACE\Oracle18c\jdbc\lib\ojdbc8.jar

    意思就是说把这个jar包导入到MAVEN仓库。

  3. 导入成功后,在pom.xml中添加以下依赖即可。
    <dependency>
    <groupId>com.oracle</groupId>
    <artifactId>ojdbc8</artifactId>
    <version>11.2.0.1.0</version>
    </dependency>
  4. 既然Oracle出现这个问题,估计其他的依赖也有可能出现类似的问题,不过目前还未发现。所以这里先给大家提个醒。

8.从哪里找依赖的代码?

你可能会问,你怎么知道依赖里面的细节怎么写?
哈哈,给你个网站 https://mvnrepository.com/
所有的依赖都是从这里面查出来的。

9.大功告成,测试一下

package com.royotech.view;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;

public class InsertPerson {
    public static void main(String[] args) throws Exception{
        //加载驱动
        Class.forName("oracle.jdbc.OracleDriver");
        String username = "hr";
        //建立连接
        String password = "123123";
        String url = "jdbc:oracle:thin:@localhost:1521:orcl";
        Connection conn = DriverManager.getConnection(url, username, password);
        //新建发送SQL的工具
        String sql = "insert into t_person values(seq_person.nextval,'李小美','女','28','13838758888','金澳科技')";
        PreparedStatement pstm = conn.prepareStatement(sql);
        //发送并执行SQL
        int rows = pstm.executeUpdate();
        System.out.println("影响行数:" + rows);
        //处理结果集
        //释放资源
        pstm.close();
        conn.close();
    }
}

哈哈,成功了!
file

写在最后

当前是技术大爆发的时代,每个月甚至每天都会有新的技术、框架涌现出来。
从技术创作者的角度,他肯定是希望技术被大众使用,那么他就会尽可能降低初学者学习的门槛。
所以大家在遇到新生事物的时候,不要被吓倒,勇敢向前,你会发现你比你自己想象的更聪明!

MySQL新建数据库时utf8_general_ci、utf8_bin、utf8_unicode_ci的区别

创建数据库时的三要素

现在各种基于MySQL数据库的开源框架非常多,基本上大家都是先安装再二次开发。

在安装开源框架的时候,需要先在MySQL里面新建一个数据库,新建数据库的时候需要确定三个重要的信息:
file

  1. Database name
  2. Database charset
  3. Database collation

这个三个信息中文直译和对应的意思分别是:

  1. Database name
    数据库名称。就是新建的这个数据库的名字是什么。
  2. Database charset
    数据库字符集。这个数据库使用哪种字符集存储数据库。对于中文项目或者可能包含非英语的国际语言的项目而言,一般都会选择UTF-8,这个基本上有点开发经验的人都应该知道。
  3. Database collation
    数据库整理规则( 排序规则 )。这个选择起来可能就有些晕了,我们来看看可选项有哪些?
    file
    在众多选项中,多数人应该会在utf8_bin、utf8_general_ci、utf8_unicode_ci三者之间由于不定。

选哪个?

要想确定选哪个,其实看看三者的英文全称就能略知一二了。

  • utf8_bin是utf8 binary的缩写。该种排序方式区分字母大小写。
  • utf8_general_ci是utf8 general case insensitive的缩写。该种方式不区分字母大小写,排序效率高,且对绝大多数语言的字符能够做到有效的排序。
  • utf8_unicode_ci是utf8_unicode case insensitive的缩写。不区分大小写,排序效率较utf8_general_ci而言稍低,但对语言字符排序的支持比utf8_general_ci更好。

所以

一般情况下,选择utf8_general_ci就可以了。这也是目前绝大多数项目的首选。
如果遇到某些涉及大量非主流外文的项目的,可以考虑使用utf8_unicode_ci编码。
utf8_bin由于区分大小写,除非有特殊的要求,一般不建议使用。