本人小白,说错还请多多见谅。
目录
登陆服务器
首先明确,免密登陆是必要的。虽然有不适用免密登陆的方法,但这些方法都会泄露密码信息。直接使用ansible对一个小实验又没必要。因此这里使用免密登陆。
安装mysql,开启二进制日志
要实现主从同步,安装是必不可少的。由于我用的系统是centos7,用的是mariadb,所以我这样安装。
. /mysql-gaokeyong/kaiqierjinzhirizhi
#加载开启binlog日志的函数
yum -y install mariadb mariadb-server
#安装mysql
kaiqierjinzhirizhi
#执行开启binlog日志
systemctl restart mariadb
#重启mysql
以上是脚本代码的一部分,用来安装主库的mysql。其中,kaiqierjinzhirizhi(开启二进制日志)是我自己定义的一个函数,在另一个脚本中被调用。代码如下:
#/bin/bash
#这个函数是为了判断binlog日志有没有开启,没有开启就开启一下
function kaiqierjinzhirizhi
{
if ! grep -Eqw "server-id|log-bin=mariadb-bin" /etc/my.cnf;then
echo "需要写入"
sed -i '4i server-id=1' /etc/my.cnf
sed -i '5i log-bin=mariadb-bin' /etc/my.cnf
else
echo "不需要写入"
fi
}
这里grep -qw有一个判断功能,有内容返回0,没内容返回1.这里用!取反。所以,无值返回0,然后执行sed写入/etc/my.cnf的操作。这里的-E为了让-qw支持|的分支匹配。
在实际情况中,如果没有-E,在有分支匹配的情况下,会默认结果为零,然后你每次测试的时候都会sed写入,最后重复多条,汗流浃背了!
设置变量,数据库密码
在安装完mysql之后,需要定义一下主库的环境变量,设置主库密码,定义从库环境变量,设置从库密码。
MASTER_HOST="192.168.2.129"
MASTER_PORT=3306
MASTER_USER="root"
MASTER_PASSWORD="MTIzNDU2Cg=="
MASTER_MYSQL_PASSWORD="1234"
mysqladmin -u $MASTER_USER password $MASTER_MYSQL_PASSWORD
#设置主mysql的密码
SLAVE1_HOST="192.168.2.130"
SLAVE1_PORT="3306"
SLAVE1_USER="root"
SLAVE1_PASSWORD="MTIzNDU2Cg=="
SLAVE1_MYSQL_PASSWORD="1234"
rm -rf /mysql-gaokeyong/bianliang
#删除要发送到从的变量信息,开始新一次变量发送
ssh $SLAVE1_USER@$SLAVE1_HOST " rm -rf /root/binaliang"
#删除从服务器的接收授权变量文件
scp /mysql-gaokeyong/yuancheng-kaiqierjinzhirizhi $SLAVE1_USER@$SLAVE1_HOST:/usr/bin/
#发送写入server-id函数的命令到从服务器
ssh $SLAVE1_USER@$SLAVE1_HOST "yum -y install mariadb mariadb-server;\
yuancheng-kaiqierjinzhirizhi;systemctl start mariadb;mysqladmin -u $SLAVE1_USER password $SLAVE1_MYSQL_PASSWORD"
#从服务安装mysql,执行写入server-id的命令yuancheng-kaiqierjinzhirizhi.重启mysql设置mysql的密码
除此之外,上面还有一个变量信息的发送。
rm -rf /mysql-gaokeyong/bianliang
#删除要发送到从的变量信息,开始新一次变量发送
ssh $SLAVE1_USER@$SLAVE1_HOST " rm -rf /root/binaliang"
#删除从服务器的接收授权变量文件
scp /mysql-gaokeyong/yuancheng-kaiqierjinzhirizhi $SLAVE1_USER@$SLAVE1_HOST:/usr/bin/
因为从库需要进行授权,授权又要变量,变量无法在新的shell中存在,所以需要远程发送,一次次构建实在是太麻烦了。
yuancheng-kaiqierjinzhirizhi (远程开启二进制日志)。这个文件的作用是在远程执行开启server-id的操作,是为从库设定的。
#/bin/bash
#这个脚本是远程写入server-id的脚本。
function kaiqierjinzhirizhi
{
if ! grep -Eqw "server-id" /etc/my.cnf ;then
echo "需要写入"
sed -i '4i server-id=2' /etc/my.cnf
else
echo "不需要写入"
fi
}
kaiqierjinzhirizhi
这里其实如果有多台从库,server-id应该改成一个变量用位置参数变量调入,然后在一个专门的文件里修改。但是我只是简单的小实验,不用那么麻烦,有兴趣的可以尝试。
接下来在主库对从库进行授权设置。
然后就要考虑,mysql在脚本中,怎么通过非交互的方式进行授权。
mysql语句脚本中执行方式
这里有四种方式
第一种 :直接使用 mysql -e “命令” 进行授权。这样干的麻烦是命令太长了不太美观。
第二种:使用sql构造语句。
SQL_GRANT="GRANT REPLICATION SLAVE, SELECT ON *.* TO 'slave'@'%s' IDENTIFIED BY '%s';"
GRANT_CMD=$(printf "$SQL_GRANT" "$SLAVE1_HOST" "$SLAVE1_MYSQL_PASSWORD")
SQL_STATUS="SHOW MASTER STATUS;"
#主服务器构造sql语句,方遍后面输入
mysql -u "$MASTER_USER" -p"$MASTER_MYSQL_PASSWORD" -e "$GRANT_CMD"
#将构造好的授权语句在mysql中执行
这样的好处是最后执行的命令不长,而且方便修改变量。至于缺点,这个远程执行才会体现出来。
这里其实是在第一句中将变量写成%s,在第二句中将第一句当作变量输出,依次按照变量顺序输入变量。最后把第二局当作变量,给mysql执行。
第三种,使用管道符过滤,将echo的输出传输到后面的mysql
echo “命令” | mysql
这样做和以上一样也有一个巨大的缺点,再下面的内容会指出
第四种,将mysql的命令直接写入文件,用<指向mysql
mysql < 文件
在主库授权时,使用了构造语句的方式(一开始不知道使用文件输入的方式)
SQL_GRANT="GRANT REPLICATION SLAVE, SELECT ON *.* TO 'slave'@'%s' IDENTIFIED BY '%s';"
GRANT_CMD=$(printf "$SQL_GRANT" "$SLAVE1_HOST" "$SLAVE1_MYSQL_PASSWORD")
SQL_STATUS="SHOW MASTER STATUS;"
#主服务器构造sql语句,方遍后面输入
mysql -u "$MASTER_USER" -p"$MASTER_MYSQL_PASSWORD" -e "$GRANT_CMD"
#将构造好的授权语句在mysql中执行
接下来需要让从库接受授权,接收授权之前先要提取二进制日志文件名和偏移量。
将接受授权命令写入文件并发送
BINLOG=$(mysql -u "$MASTER_USER" -p"$MASTER_MYSQL_PASSWORD" -e "$SQL_STATUS" | awk 'NR>1{ print $1}')
#提取binlog日志名
POSITION=$(mysql -u "$MASTER_USER" -p"$MASTER_MYSQL_PASSWORD" -e "$SQL_STATUS"| awk 'NR>1{ print $2}')
#提取当前偏移量
touch /mysql-gaokeyong/bianliang
#创建确认授权变量文件
echo -e "CHANGE MASTER TO MASTER_HOST='$MASTER_HOST'\
,MASTER_PORT=3306,\
MASTER_USER='slave',\
MASTER_PASSWORD='$MASTER_MYSQL_PASSWORD',\
MASTER_LOG_FILE='$BINLOG'\
,MASTER_LOG_POS=$POSITION;" >> /mysql-gaokeyong/bianliang
#将确认授权,写入变量文件。
以上就是mysql的偏移量和二进制日志文件名提取作为变量,然后写入文件。
ssh $SLAVE1_USER@$SLAVE1_HOST "mkdir /root/mysqlbianliang/"
#创建变量文件所在目录
scp /mysql-gaokeyong/bianliang $SLAVE1_USER@$SLAVE1_HOST:/root/mysqlbianliang/
#将变量文件发送给远程服务器
ssh $SLAVE1_USER@$SLAVE1_HOST " chmod 777 /root/mysqlbinaliang/bianliang"
#为变量文件设置权限
这个是将变量文件发送到从服务器,方便被调用。
远程cat问题
现象
在命令行远程可以cat文件内容,同样的命令但在脚本就不行。(有兴趣的可以自己尝试一下)
这个有什么弊端?
如果不能cat,那么awk、grep同样不能使用,请问你怎么提取变量?
然后我去上网查了一下为什么在脚本中ssh 用户@ip “命令” 无法使用cat命令?
结果网上的答案是,cat以及其他查看文件内容的命令,其实需要一个终端,而shell脚本的bash环境其实不能提供这个终端,所以无法cat。
解决这个问题的方法也很简单,用-t生成一个伪终端。
ssh -tt $SLAVE1_USER@$SLAVE1_HOST <yuanchengjiaobeng.sh
#-t开启一个伪终端,在伪终端通过传入的脚本设置从服务器的mysql主从配置
这里的-tt表示生成一个更加好的伪终端,后面的脚本是在这个伪终端中执行的。因为一开始我不用脚本输入的方式依旧不能cat,具体原因我不太清楚,不过用脚本输入就可以执行了。
远程执行的接受授权脚本
#!/bin/bash
cd /root/
#确认存放变量文件的目录
rm -rf change_master.sql
#删除上次的变量文件
MASTER_HOST="192.168.2.129"
MASTER_PORT=3306
MASTER_USER="root"
MASTER_PASSWORD="MTIzNDU2Cg=="
MASTER_MYSQL_PASSWORD="MTIzNAo="
SLAVE1_HOST="192.168.2.130"
SLAVE1_PORT="3306"
SLAVE1_USER="root"
SLAVE1_PASSWORD="MTIzNDU2Cg=="
SLAVE1_MYSQL_PASSWORD="1234"
cp /root/mysqlbianliang/bianliang /root/change_master.sql
#将接收授权变量传递给授权文件
mysql -u $SLAVE1_USER -p$SLAVE1_MYSQL_PASSWORD < /root/change_master.sql
#确认授权的过程
echo "start slave;" |mysql -u$SLAVE1_USER -p$SLAVE1_MYSQL_PASSWORD
#开启主从
mysql -u$SLAVE1_USER -p$SLAVE1_MYSQL_PASSWORD -e "show slave status\G;"
#查看主从
exit
#退出终端
我这里懒得讲变量写入文件然后发送提取了,不过使用 ssh 用户@ip <脚本 的方式已经可以在这个脚本中实现awk提取了。有兴趣的可以试一下。
这里我重点讲一下为什么要文件传入命令给mysql的问题。
刚开始我使用awk提取变量,然后用sql构造语句的方式执行,最大的问题就是太长了,容易错。
什么地方多了个“立马报错,多次调用还很难找到。除此之外,我发现伪终端的行长度,是有限的,超出长度的变量会被夹断报错。
如图所示,将接收授权过程用直接写入的方式。看看脚本执行主从会不会报错。
CHANGE=$(awk 'NR==1' /root/mysqlbianliang/bianliang )
cp /root/mysqlbianliang/bianliang /root/change_master.sql
#将接收授权变量传递给授权文件
#mysql -u $SLAVE1_USER -p$SLAVE1_MYSQL_PASSWORD < /root/change_master.sql
#确认授权的过程
mysql -u $SLAVE1_USER -p$SLAVE1_MYSQL_PASSWORD -e "$CHANGE"
没报错,太尴尬了,不过,太长的命令确实容器报错,所以我最终使用了文件传入的方式。
其他可以实现的功能
其实还可以搞个keepalive+lvs实现高可用,可以自己去实现。另外使用函数调用和位置参数变量传入的方式,实现修改配置和脚本的解耦也是可以的,建议有兴趣的尝试,散会。