實現MySQL複製及讀寫分離

實驗拓撲:

wKiom1OlLJfy18EcAAEuo42x8Wo992.jpg

實驗要求:

1、完成node1與node2的MySQL主從複製,並且實現node2從服務器只讀

2、實現node1 node2半同步複製

3、完成node5與node1基於SSL的遠程複製

4、實現node5只複製部分數據庫既庫過濾功能

5、實現MySQL Proxy轉發不同讀寫請求至不同服務器(MySQL讀寫分離)


實驗平臺:

RHEL5.8

MySQL5.5


1、node1 node2實現主從複製

修改master  my.cnf配置文件,主要修改以下內容

[mysqld]
server-id=111    --------  每服務器server-id需不一致
innodb_file_per_table=1  ------- 使得innodb每表表空間
datadir=/mydata/data  ---- 修改數據存放路徑
log-bin=/mylog/log/mybinlog  --- 開啓二進制日誌,日誌與數據不要存放在同一磁盤上,注意這裏指的是具體文件而非路徑
binlog_format=row  ---建議二進制日誌存放格式爲行格式
../mysql/scripts/mysql_install_db --user=mysql --datadir=/mydata/data  初始化數據庫後啓動服務即可
grant replication slave,replication client on *.* to repliuser identified by "redhat";--授權一個僅有複製權限的用戶


修改slave1  my.cnf配置文件,主要修改以下內容

[mysqld]
server-id=112    --------  每服務器server-id需不一致
innodb_file_per_table=1  
datadir=/mydata/data  
relay_log =/mylog/log/relay.log ---開啓並指定二進制日誌,從服務器可不必開啓二進制日誌以減少磁盤IO
read_only=1  ---- 設置從服務器爲只讀,該權限對具有管理員權限的無效

初始化數據庫並啓動從服務器

從服務器指向主服務器地址及開始複製的二進制日誌及位置

change master to MASTER_HOST='10.32.9.51',MASTER_USER='repliuser',MASTER_PASSWORD='redhat',MASTER_LOG_FILE='mybinlog.000004',MASTER_LOG_POS=107;
MASTER_LOG_FILE = 'master_log_name'  ----- 指定要開始複製的二進制日誌名
MASTER_LOG_POS = master_log_pos ---- 指定要開始複製的二進制日誌位置(POSITION)

之後

start slave;-----啓動從服務器複製的IO線程與SQL線程 


驗證

wKiom1OlQWzzYLI2AABcwSSDCNI264.jpg

wKioL1OlQOvyhyOFAADgRxnRrVU606.jpg



node2 從服務器實現只讀

node2實現只讀的方法主要有:1、開啓全局變量read_only  2、申請全局鎖flash tables with read lock

測試:主服務器授權一個可以寫創建及刪除表的普通用戶,用普通用戶連接連接slave1並創建表

wKioL1OlQ_ngUwqqAACB9JagFIo403.jpg

wKioL1OlRD6zd8wuAAItY8VpFKo781.jpg




2、實現node1 node2半同步複製

半同步複製爲google公司提供的源代碼,主要爲了防止出現從服務器的數據庫落後於主服務器的問題,同步複製需要所有從服務器SQL線程寫完數據返回給主服務器告知已經完成,所謂半同步主要指當出現多個從節點時,選取其中離主服務器帶寬最大的一臺,主服務器只要確認該服務器完成同步即可。


主服務器配置

INSTALL  PLUGIN  rpl_semi_sync_master  SONAME  'semisync_master.so' --安裝主服務器的半同步擴展插件


設置服務器變量

rpl_semi_sync_master_enabled=ON  開啓半同步複製功能  
rpl_semi_sync_master_timeout=1000  等待從服務器超時時間毫秒
rpl_semi_sync_master_trace_level
rpl_semi_sync_master_wait_no_slave  如果沒有從節點是否等待其上線


從服務器配置

INSTALL  PLUGIN  rpl_semi_sync_slave  SONAME  'semisync_slave.so' --安裝主服務器的半同步擴展插件


設置從服務器變量

rpl_semi_sync_slave_enabled = ON 開啓


重新啓動從服務器的IO線程即可


主服務器上驗證半同步客戶端的個數

wKioL1OlSJ7xJarqAAJ_rxMH3S4280.jpg



3、完成node5與node1基於SSL的遠程複製

3.1 配置iptables規則,做DNAT將node3外網地址的3306端口轉發至node1 3306端口

iptables -t nat -A PREROUTING -d 1.1.1.1 -p tcp --dport 3306 -j DNAT --to-destination 10.32.9.51:3306

測試

wKiom1OlTPHxPGseAAD5hH3qGYQ537.jpg


3.2 配置mysql slave2

[mysqld]
server-id=115   --------  每服務器server-id需不一致
innodb_file_per_table=1  
datadir=/mydata/data

初始化並啓動slave2服務器


3.3使node1成爲CA併爲node5簽署數字證書

這裏使用我自己寫的腳本,直接運行既可以成爲CA

#!/bin/bash
#
#
echo -e "now setting CA work directory /etc/pki/CA\n\n"
sed -i s@"../../CA"@"/etc/pki/CA"@ /etc/pki/tls/openssl.cnf
sleep 1
echo -e "done!!\n"
#The work directory should be /etc/pki/CA
DIR=/etc/pki/CA
echo -e "now testing the necessary directory or file. if not creat,the next will creat auto\n"
#test the work directory and file
[ ! -d $DIR ] && mkdirp -p $DIR &> /dev/null;echo -e "$DIR is creating!! done!\n"
sleep 1
[ ! -e $DIR/certs ] && touch $DIR/certs;echo -e "$DIR/certs is creating!! done!\n"
sleep 1
[ ! -d $DIR/crl ] && mkdirp -p $DIR/crl &> /dev/null;echo -e "$DIR/crl is creating!! done!\n"
sleep 1
[ ! -e $DIR/index.txt ] && touch $DIR/index.txt;echo -e "$DIR/index.txt is creating!! done!\n"
sleep 1
[ ! -d $DIR/newcerts ] && mkdir -p $DIR/newcerts;echo -e "$DIR/newcerts is creating!! done!\n"
sleep 1
[ ! -e $DIR/serial ] && touch $DIR/serial ; echo "01" > $DIR/serial;echo -e "$DIR/serial is creating!! done!\n"
sleep 1
[ ! -e $DIR/crlnumber ] && touch $DIR/crlnumber;echo  -e "$DIR/crlnumber is creating!! done!\n"
sleep 1
[ ! -d $DIR/private ] && mkdir -p $DIR/private;echo -e "$DIR/private is creating!! done!\n"
sleep 1
echo -e "The next please input cacert info\n\n"
read -p "please input your country(2 letters) like CN|JP.....:" A
read -p "please input your province:" B
read -p "please input your city:" C
read -p "please input your company:" D
read -p "please input your Unit name:" E
read -p "please input your name or your server's hostname:" F
read -p "please input your email address:" G
openssl genrsa -out $DIR/private/cakey.pem 2048 &> /dev/null
openssl rsa -in $DIR/private/cakey.pem -pubout  > /tmp/pub.key &> /dev/null
echo "$A
$B
$C
$D
$E
$F
$G" | openssl req -new -x509 -key $DIR/private/cakey.pem -out $DIR/cacert.pem -days 365 &> /dev/null
rm -rf /tmp/pub.key
echo -e "\n\n"
echo -e "the cacert is in $DIR/cacert.pem,and the cacert info is::\n\n "
sleep 5
openssl x509 -text -in $DIR/cacert.pem

node5 配置

openssl genrsa -out FILENAME   ------ 生成私鑰
openssl req -new -key 私鑰名 -out 證書請求文件  ----  生成證書籤署請求,私有證書機構 部門 組織單位都要與CA保持一致,否則不給籤
openssl ca -in 證書請求文件 -out 證書位置  ------   該條指令在CA上執行,需要node5發送證書至CA,這樣就簽署了並生成證書,再使用SCP發回node5即可在node5上使用。


node1在配置文件中開啓ssl功能並指定相關文件路徑後啓服務進程

ssl             ------------ 開啓ssl功能
ssl_ca=/opt/cacert.pem   ---------ca證書位置
ssl_cert=/opt/cacert.pem  ---------公鑰位置
ssl_key=/opt/cakey.pem    -----私鑰位置

爲slave2創造需要ssl連接才能進行復制的權限賬號

grant replication slave,replication client on *.* to node5 identified by "redhat" require ssl


node5配置:

change master to MASTER_HOST='1.1.1.1',MASTER_USER='node5',MASTER_PASSWORD='hadoop',MASTER_LOG_FILE='mybinlog.000004',MASTER_LOG_POS=107, MASTER_SSL=1,MASTER_SSL_CA='/opt/cacert.pem', MASTER_SSL_CERT = '/opt/privite.crt',MASTER_SSL_KEY='/opt/privite';
MASTER_SSL=1表示開啓SSL功能
MASTER_SSL_CA 指定CA證書位置
MASTER_SSL_CERT 指定從節點證書的位置
MASTER_SSL_KEY  指定從節點私鑰的位置

驗證:

方法1

wKioL1Ol1AvAT1PKAAO6IItmMNE281.jpg

方法2

mysql -unode5 -phadoop -h1.1.1.1 --ssl-ca=/opt/cacert.pem  --ssl-cert=/opt/privite.crt --ssl-key=/opt/privite  測試是否可以使用SSL加密登陸主服務器



4、實現node5只複製部分數據庫既庫過濾功能

複製時實現數據過濾的方法有兩種,均是通過修改配置文件參數

master:設置binlog_do_db表示複製哪些數據到二進制日誌   binlog_ignore_db忽略哪些數據庫
slave: replicate_do_db  replicate_ignore_db  
        replicate_do_table  replicate_ignore_table  (需要指明是哪個庫的表)
        replicate_wild_do_table   replicate_wild_ignore_table 支持通配的寫法

測試:

主服務器創建aa數據庫,數據庫中創建cc dd表

wKiom1OmSHyQyxlLAAIDJMIJMaI697.jpg


觀察從服務器的複製情況及設置

wKioL1OmSGTSxk3FAAQLAz7mUOs684.jpg



5、實現MySQL Proxy轉發不同讀寫請求至不同服務器(MySQL讀寫分離)

5.1官網下載通用二進制安裝mysql-proxy

5.2爲mysql-proxy提供SysV啓動腳本

#!/bin/bash
#
# mysql-proxy This script starts and stops the mysql-proxy daemon
#
# chkconfig: - 78 30
# processname: mysql-proxy
# description: mysql-proxy is a proxy daemon for mysql
# Source function library.
. /etc/rc.d/init.d/functions
prog="/usr/local/mysql-proxy/bin/mysql-proxy"
# Source networking configuration.
if [ -f /etc/sysconfig/network ]; then
    . /etc/sysconfig/network
fi
# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 0
# Set default mysql-proxy configuration.
ADMIN_USER="admin"
ADMIN_PASSWD="admin"
ADMIN_LUA_SCRIPT="/usr/local/mysql-proxy/share/doc/mysql-proxy/admin.lua"
PROXY_OPTIONS="--daemon"
PROXY_PID=/var/run/mysql-proxy.pid
PROXY_USER="mysql-proxy"
# Source mysql-proxy configuration.
if [ -f /etc/sysconfig/mysql-proxy ]; then
    . /etc/sysconfig/mysql-proxy
fi
RETVAL=0
start() {
    echo -n $"Starting $prog: "
    daemon $prog $PROXY_OPTIONS --pid-file=$PROXY_PID --proxy-address="$PROXY_ADDRESS" --user=$PROXY_USER --admin-username="$ADMIN_USER" --admin-lua-script="$ADMIN_LUA_SCRIPT" --admin-password="$ADMIN_PASSWORD"
    RETVAL=$?
    echo
    if [ $RETVAL -eq 0 ]; then
        touch /var/lock/subsys/mysql-proxy
    fi
}
stop() {
    echo -n $"Stopping $prog: "
    killproc -p $PROXY_PID -d 3 $prog
    RETVAL=$?
    echo
    if [ $RETVAL -eq 0 ]; then
        rm -f /var/lock/subsys/mysql-proxy
        rm -f $PROXY_PID
    fi
}
# See how we were called.
case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    restart)
        stop
        start
        ;;
    condrestart|try-restart)
        if status -p $PROXY_PIDFILE $prog >&/dev/null; then
            stop
            start
        fi
        ;;
    status)
        status -p $PROXY_PID $prog
        ;;
    *)
        echo "Usage: $0 {start|stop|restart|reload|status|condrestart|try-restart}"
        RETVAL=1
        ;;
esac
exit $RETVAL

5.3 爲服務腳本提供配置文件/etc/sysconfig/mysql-proxy

# Options for mysql-proxy 
ADMIN_USER="admin"
ADMIN_PASSWORD="admin"
ADMIN_ADDRESS="1.1.1.1"
ADMIN_LUA_SCRIPT="/usr/local/mysql-proxy/share/doc/mysql-proxy/admin.lua"
PROXY_ADDRESS="1.1.1.1"
PROXY_USER="mysql-proxy"
PROXY_OPTIONS="--daemon --log-level=info --log-use-syslog"
其中最後一行,需要按實際場景進行修改,例如:
PROXY_OPTIONS="--daemon --log-level=info --log-use-syslog --plugins=proxy --plugins=admin --proxy-backend-addresses=10.32.9.51:3306 --proxy-read-only-backend-addresses=10.32.9.52:3306 --proxy-lua-script=/usr/local/mysql-proxy/share/doc/mysql-proxy/rw-splitting.lua"
其中的proxy-backend-addresses選項和proxy-read-only-backend-addresses選項均可重複使用多次,以實現指定多個讀寫服務器或只讀服務器。

5.4爲mysql-proxy提供管理lua腳本,admin.lua文件,將其保存至/usr/local/mysql-proxy/share/doc/mysql-proxy/目錄中

--[[ $%BEGINLICENSE%$
 Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as
 published by the Free Software Foundation; version 2 of the
 License.
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 GNU General Public License for more details.
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 02110-1301  USA
 $%ENDLICENSE%$ --]]
function set_error(errmsg) 
proxy.response = {
type = proxy.MYSQLD_PACKET_ERR,
errmsg = errmsg or "error"
}
end
function read_query(packet)
if packet:byte() ~= proxy.COM_QUERY then
set_error("[admin] we only handle text-based queries (COM_QUERY)")
return proxy.PROXY_SEND_RESULT
end
local query = packet:sub(2)
local rows = { }
local fields = { }
if query:lower() == "select * from backends" then
fields = { 
{ name = "backend_ndx", 
  type = proxy.MYSQL_TYPE_LONG },
{ name = "address",
  type = proxy.MYSQL_TYPE_STRING },
{ name = "state",
  type = proxy.MYSQL_TYPE_STRING },
{ name = "type",
  type = proxy.MYSQL_TYPE_STRING },
{ name = "uuid",
  type = proxy.MYSQL_TYPE_STRING },
{ name = "connected_clients", 
  type = proxy.MYSQL_TYPE_LONG },
}


for i = 1, #proxy.global.backends do
local states = {
"unknown",
"up",
"down"
}
local types = {
"unknown",
"rw",
"ro"
}
local b = proxy.global.backends[i]
rows[#rows + 1] = {
i,
b.dst.name,          -- configured backend address
states[b.state + 1], -- the C-id is pushed down starting at 0
types[b.type + 1],   -- the C-id is pushed down starting at 0
b.uuid,              -- the MySQL Server's UUID if it is managed
b.connected_clients  -- currently connected clients
}
end
elseif query:lower() == "select * from help" then
fields = { 
{ name = "command", 
  type = proxy.MYSQL_TYPE_STRING },
{ name = "description", 
  type = proxy.MYSQL_TYPE_STRING },
}
rows[#rows + 1] = { "SELECT * FROM help", "shows this help" }
rows[#rows + 1] = { "SELECT * FROM backends", "lists the backends and their state" }
else
set_error("use 'SELECT * FROM help' to see the supported commands")
return proxy.PROXY_SEND_RESULT
end
proxy.response = {
type = proxy.MYSQLD_PACKET_OK,
resultset = {
fields = fields,
rows = rows
}
}
return proxy.PROXY_SEND_RESULT
end


測試管理功能

wKiom1OmdLXysK92AAEUQfi0vro835.jpg

測試讀操作是否分擔發往主從服務器

利用一簡單腳本實現批量查詢

#!/bin/bash
#
while :;do
        mysql -ukeyia -predhat -h1.1.1.1 -e "select * from mysql.user;"
done

管理方式登陸mysql-proxy,可以發現兩個backend都已經up

wKioL1OmftSjHadIAAIHMAiwEwg562.jpg

通過tcpdump抓包可以觀察寫操作僅發給主服務器

tcpdump -i eth0  -p tcp port 3306 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章