本文首发于我的个人网站: https://hewanyue.com/
本文作者: Hechao
本文链接: https://hewanyue.com/blog/d006fe9f.html
一、多实例
1、概述
MySQL多实例就是在一台机器上开启多个不同的服务端口(如:3306,3307),运行多个MySQL服务进程,通过不同的socket监听不同的服务端口来提供各自的服务
2.1、优点
1)有效利用服务器资源
当单个服务器资源过剩时,可以充分利用剩余的资源来提供更多的服务;
2)节约服务器资源
当公司资金紧张,但数据库又需要数据库之间各自提供服务时,并且还想使用主从同步等技术,此时多实例就再好不过了;
3)方便后期架构扩展
当公司的某个项目才启动时,启动初期并不一定有很大的用户量,因此可以先用一组物理数据库服务器,在上面部署多个实例,方便后续架构扩展、迁移;
2.2、缺点
资源互相抢占问题
当某个服务实例并发很高或者有慢查询时,整个实例会消耗更多的内存、CPU和IO资源,这将导致服务器上的其它实例提供服务的质量下降。这就比如说合租房的各个租客,每当早晨上班时,都会洗漱,此时卫生间的占用率就大,各个租客总会发生等待。
3、部署mysql多实例的两种方式
① 基于多配置文件
通过使用多个配置文件来启动不同的进程,以此来实现多实例。
优点:逻辑简单,配置简单
缺点:管理起来不方便
② 基于mysqld_multi
通过官方自带的 mysqld_multi 工具,使用单独配置文件来实现多实例
优点: 便于集中管理管理
缺点: 不方便针对每个实例配置进行定制
4、同一开发环境下安装两个数据库,必须处理以下问题
(1) 配置文件安装路径不能相同
(2)数据库目录不能相同
(3)启动脚本不能同名
(4)端口不能相同
(5)socket文件的生成路径不能相同
5、配置搭建
实现目标:
1、源码编译安装或者二进制安装或者yum安装mysql或mariadb客户端以及server端,若没有创建mysql用户、组则创建。
2、在指定路径下创建3个数据库目录
mkdir -p /data/mysql330{789}
挂载在不同的三块硬盘上
mount /dev/sdb /data/mysql3307
mount /dev/sdc /data/mysql3308
mount /dev/sdd /data/mysql3309
3、用server端带的初始化脚本生成三个数据库
scripts/mariadb-install-db --datadir=/data/mysql3307/ --user=mysql
scripts/mariadb-install-db --datadir=/data/mysql3308/ --user=mysql
scripts/mariadb-install-db --datadir=/data/mysql3309/ --user=mysql
4、准备三个配置文件
cp /etc/my.cnf /data/mysql3307/my.cnf
cp /etc/my.cnf /data/mysql3308/my.cnf
cp /etc/my.cnf /data/mysql3309/my.cnf
修改分别其中配置(以下以实例3307为例,3308、3309将下面所有数字对应改成自己的端口号)
[client]
#password = your_password
port = 3307
socket = /data/mysql3307/mysql.sock
[mysqld]
datadir=/data/mysql3307/
innodb_file_per-table=on
skip_name_resolve=on
port = 3307
socket = /data/mysql3307/mysql.sock
log-bin=mysql-bin
log-slave-updates
server-id = 3307 #每个数据库server-id全局唯一
default-character-set=utf8
read_only=ON #3307特有选项-开启中继日志
relay_log=relay-log #3307特有选项
relay_log_index=relay-log.index #3307特有选项
5、编写服务启动脚本(并加执行权限和修改PATH路径)
vim mysqld
#!/bin/bash
port=$1
mysql_user="root"
mysql_pwd="password"
cmd_path="/usr/local/mysql/bin"
mysql_basedir="/data/mysql"
mysql_sock="${mysql_basedir}${port}/mysql.sock"
function_start_mysql()
{
if [ ! -e "$mysql_sock" ];then
printf "Starting MySQL...\n"
${cmd_path}/mysqld_safe --defaults-file=${mysql_basedir}${port}/my.cnf &> /dev/null &
else
printf "MySQL is running...\n"
exit
fi
}
function_stop_mysql()
{
if [ ! -e "$mysql_sock" ];then
printf "MySQL is stopped...\n"
exit
else
printf "Stoping MySQL...\n"
${cmd_path}/mysqladmin -u ${mysql_user} -p${mysql_pwd} -S ${mysql_sock} shutdown
fi
}
function_restart_mysql()
{
printf "Restarting MySQL...\n"
function_stop_mysql
sleep 1
function_start_mysql
}
if [ ! -n "$2" ];then
printf "Usage: ${mysql_basedir}${port}/bin/mysqld [PORT] {start|stop|restart}\n"
else
case $2 in
start)
function_start_mysql
;;
stop)
function_stop_mysql
;;
restart)
function_restart_mysql
;;
*)
printf "Usage: ${mysql_basedir}${port}/bin/mysqld {start|stop|restart}\n"
esac
fi
6、现在就可以实现执行mysqld 3307 start启动数据库服务了。启动三台数据库后(可运行安全加固脚本去掉test数据库以及多余账户),在主机数据库及这3个数据库中分别增加主从配置。
192.168.32.71主机数据库:
MariaDB [(none)]> GRANT REPLICATION SLAVE ON *.* TO 'repluser'@'192.168.32.72' IDENTIFIED BY 'replpasswd';
MariaDB [(none)]> SHOW MASTER STATUS;
MariaDB [(none)]> show master status;
±-------------------±--------------±----------------±--------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
±-------------------±--------------±----------------±--------------------+
| mysql-bin.000026 | 1136 | | |
±-------------------±--------------±----------------±--------------------+
查看并记录主机当前二进制日志文件信息及位置。
用mysqldump (或者物理备份),并还原至3个从节点。
192.168.32.71主机:
mysqldump -uroot -ppassword -A --default-character-set=utf8 --master-data=1 --hex-blob >/data/fullbak_`date +%F`.sql
scp /data/fullbak_`date +%F`.sql 192.168.32.72:/data/
192.168.32.72主机:
启动3个实例的服务mysqld 3307 start;mysqld 3308 start;mysqld 3309 start
连接3307实例mysql -S /data/mysql3307/mysql.sock
MariaDB [(none)]> source /data/fullbak_XXX.sql
MariaDB [(none)]> SHOW MASTER STATUS;
MariaDB [(none)]> show master status;
±-------------------±--------------±----------------±--------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
±-------------------±--------------±----------------±--------------------+
| mysql-bin.000006 | 1167 | | |
±-------------------±--------------±----------------±--------------------+
记录3307实例的当前二进制日志文件信息及位置。
在从节点3307添加主节点配置信息。
MariaDB [(none)]> change master to master_host='192.168.32.71',
master_user='repluser',
master_password='replpasswd',
master_port=3306,
master_log_file='mysql-bin.000026',master_log_pos=1136;
MariaDB [(none)]>start slave;
连接3308实例mysql -S /data/mysql3308/mysql.sock
在从节点3308添加主节点配置信息。
MariaDB [(none)]> source /data/fullbak_XXX.sql
MariaDB [(none)]> change master to master_host='192.168.32.72,
master_user='repluser',
master_password='replpasswd',
master_port=3307,
master_log_file='mysql-bin.000006',master_log_pos=1167;
MariaDB [(none)]>start slave;
连接3309实例mysql -S /data/mysql3309/mysql.sock
在从节点3309添加主节点配置信息。
MariaDB [(none)]> source /data/fullbak_XXX.sql
MariaDB [(none)]> change master to master_host='192.168.32.72,
master_user='repluser',
master_password='replpasswd',
master_port=3307,
master_log_file='mysql-bin.000006',master_log_pos=1167;
MariaDB [(none)]>start slave;
三个从节点数据库依次show slave status\G
查看主从状态信息,确认主从配置无误且均已启动,至此,多实例主从级联配置就完成了。
二、读写分离
1、什么是读写分离?
读写分离,基本的原理是让主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库处理SELECT查询操作。数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库。
2、为什么要实现读写分离?
因为数据库的“写”(写10000条数据到oracle可能要3分钟)操作是比较耗时的。
但是数据库的“读”(从oracle读10000条数据可能只要5秒钟)。
所以读写分离,解决的是,数据库的写入,影响了查询的效率。
3、什么时候要读写分离?
数据库不一定要读写分离,如果程序使用数据库较多时,而更新少,查询多的情况下会考虑使用,利用数据库 主从同步 。可以减少数据库压力,提高性能。当然,数据库也有其它优化方案。memcache 或是 表折分,或是搜索引擎。都是解决方法。
4、部署读写分离
本次使用proxy实现读写分离,最终实现下图所示
1、部署代理机ip:192.168.32.70
安装proxy及mysql客户端
cat /etc/yum.repos.d/proxysql.repo <<EOF
[proxysql_repo]
name= ProxySQL YUM repository
baseurl=http://repo.proxysql.com/ProxySQL/proxysql-1.4.x/centos/\$releasever
gpgcheck=1
gpgkey=http://repo.proxysql.com/ProxySQL/repo_pub_key
EOF
yum install proxysql -y
yum install mysql -y
修改代理机配置文件端口号 6033 改为 3306(方便客户机连接,其他保持默认)
sed -ri 's@(interfaces="0.0.0.0:)6033@\13306@' /etc/proxysql.cnf
登陆proxysql数据库
mysql -uadmin -padmin -P6032 -h127.0.0.1
在代理服务器上增加主机信息
MySQL [(none)]>
insert into mysql_servers(hostgroup_id,hostname,port) values(10,'192.168.32.71',3306),
(10,'192.168.32.72',3307),
(10,'192.168.32.72',3308),
(10,'192.168.32.72',3309);
加载:MySQL [(none)]> load mysql servers to runtime
保存:MySQL [(none)]> save mysql servers to disk
#设置监控帐号(使用默认监控账号(账号:密码=monitor:monitor)的话,此步可跳过)
MySQL [(none)]>
set mysql-monitor_username='username'
set mysql-monitor_password='password'
MySQL [(none)]> load mysql variables to runtime;
MySQL [(none)]> save mysql variables to disk;
2、在主服务器上增加创建proxy的监控帐号并授权(从节点会自动复制创建,无需再创)
MySQL [(none)]> grant replication client on *.* to monitor@'192.168.32.71' identified by 'monitor';
3、在代理机上查看监控连接是否正常的 (对connect指标的监控):
如果connect_error的结果为NULL则表示正常
MySQL>select * from mysql_server_connect_log;
查看监控心跳信息 (对ping指标的监控):
MySQL> select * from mysql_server_ping_log;
(如果显示连接失败,可尝试在从节点刷新权限flush privileges;
)
4、设置分组信息
需要修改的是main库中的mysql_replication_hostgroups表,该表有3个字段:writer_hostgroup,reader_hostgroup,comment, 指定写组的id为10,读组的id为20
MySQL>insert into mysql_replication_hostgroups values(10,20,"CentOS7");
将mysql_replication_hostgroups表的修改加载到RUNTIME生效
MySQL> load mysql servers to runtime;
MySQL> save mysql servers to disk;
Monitor模块监控后端的read_only值,按照read_only的值将节点自动移动到读/写组
查看添加的主机分组表,应该已经自动分组了:
MySQL>select hostgroup_id,hostname,port,status,weight from mysql_servers;
5、在proxysql上配置路由规则,实现读写分离
与规则有关的表:mysql_query_rules和mysql_query_rules_fast_routing,后者是前者的扩展表,1.4.7之后支持
插入路由规则:将select语句分离到20的读组,select语句中有一个特殊语句
SELECT…FOR UPDATE它会申请写锁,应路由到10的写组
MySQL>insert into mysql_query_rules(rule_id,active,match_digest,destination_hostgroup,apply) VALUES (1,1,'^SELECT.*FOR UPDATE$',10,1),(2,1,'^SELECT',20,1);
MySQL> load mysql query rules to runtime;
MySQL> save mysql query rules to disk;
注意:因ProxySQL根据rule_id顺序进行规则匹配,select … for update规则的rule_id必须要小于普通的select规则的rule_id
在代理机上用命令测试相应读写的是哪个数据库:
mysql -uroot -pPASSWORD -P3306 -h127.0.0.1 -e 'start transaction;select @@server_id;commit;select @@server_id'
±-----------------+
| @@server_id |
±-----------------+
| 3306 |
±-----------------+
±-----------------+
| @@server_id |
±-----------------+
| 3307 |
±-----------------+
说明读写分离,在两个终端上成功实现~