MYSQL集群双主双备双VIP读写分离高可用优化版KEEPALIVED

时间:2023-01-10 07:55:47


规划:

主1:172.16.108.71 ---》从 1:172.16.108.73   同步

      |主1与主2双向同步

主2:172.16.108.72--》从2:172.16.108.74 同步

主2与从2是一个紧急备用,正常情况下不投入使用

 

VIP1:写入172.16.108.110

VIP2:读取172.16.108.111 

 

MYSQL集群双主双备双VIP读写分离高可用优化版KEEPALIVED

 

 

主机1

my.cnf
[client]
#password = your_password
port = 3306
socket = /tmp/mysql.sock# Here follows entries for some specific programs
# The MySQL server
[mysqld]
port = 3306
socket = /tmp/mysql.sock
skip-locking
key_buffer_size = 384M
max_allowed_packet = 128M
table_open_cache = 512
sort_buffer_size = 2M
read_buffer_size = 2M
read_rnd_buffer_size = 8M
myisam_sort_buffer_size = 64M
thread_cache_size = 8
query_cache_size = 32M
# Try number of CPU's*2 for thread_concurrency
thread_concurrency = 8log-bin=mysql-bin
binlog-do-db=tx
server-id = 1
auto-increment-increment=2
auto-increment-offset=1
log-slave-updates[mysqldump]
quick
max_allowed_packet = 128M [mysql]
no-auto-rehash
# Remove the next comment character if you are not familiar with SQL
#safe-updates[myisamchk]
key_buffer_size = 256M
sort_buffer_size = 256M
read_buffer = 2M
write_buffer = 2M[mysqlhotcopy]
interactive-timeout
主机2[client]
#password = your_password
port = 3306
socket = /tmp/mysql.sock# Here follows entries for some specific programs
server_id=2
# The MySQL server
[mysqld]
port = 3306
socket = /tmp/mysql.sock
skip-locking
key_buffer_size = 384M
max_allowed_packet = 128M
table_open_cache = 512
sort_buffer_size = 2M
read_buffer_size = 2M
read_rnd_buffer_size = 8M
myisam_sort_buffer_size = 64M
thread_cache_size = 8
query_cache_size = 32M
server_id=2# Try number of CPU's*2 for thread_concurrency
thread_concurrency = 8# binary logging is required for replication
log-bin=mysql-bin
binlog-do-db=tx
server-id = 2
auto-increment-increment=2
auto-increment-offset=2
log-slave-updates[mysqldump]
quick
max_allowed_packet = 128M[mysql]
no-auto-rehash
# Remove the next comment character if you are not familiar with SQL
#safe-updates[myisamchk]
key_buffer_size = 256M
sort_buffer_size = 256M
read_buffer = 2M
write_buffer = 2M[mysqlhotcopy]
interactive-timeout手下1同步主1
[client]
#password = your_password
port = 3306
socket = /tmp/mysql.sock# Here follows entries for some specific programs
# The MySQL server
[mysqld]
port = 3306
socket = /tmp/mysql.sock
skip-locking
key_buffer_size = 384M
max_allowed_packet = 128M
table_open_cache = 512
sort_buffer_size = 2M
read_buffer_size = 2M
read_rnd_buffer_size = 8M
myisam_sort_buffer_size = 64M
thread_cache_size = 8
query_cache_size = 32M
# Try number of CPU's*2 for thread_concurrency
thread_concurrency = 8log-bin=mysql-bin
server-id = 3
[mysqldump]
quick
max_allowed_packet = 128M[mysql]
no-auto-rehash
# Remove the next comment character if you are not familiar with SQL
#safe-updates[myisamchk]
key_buffer_size = 256M
sort_buffer_size = 256M
read_buffer = 2M
write_buffer = 2M[mysqlhotcopy]
interactive-timeout
手下2同步主2
[client]
#password = your_password
port = 3306
socket = /tmp/mysql.sock# Here follows entries for some specific programs
# The MySQL server
[mysqld]
port = 3306
socket = /tmp/mysql.sock
skip-locking
key_buffer_size = 384M
max_allowed_packet = 128M
table_open_cache = 512
sort_buffer_size = 2M
read_buffer_size = 2M
read_rnd_buffer_size = 8M
myisam_sort_buffer_size = 64M
thread_cache_size = 8
query_cache_size = 32M
# Try number of CPU's*2 for thread_concurrency
thread_concurrency = 8log-bin=mysql-bin
server-id = 4
[mysqldump]
quick
max_allowed_packet = 128M[mysql]
no-auto-rehash
# Remove the next comment character if you are not familiar with SQL
#safe-updates[myisamchk]
key_buffer_size = 256M
sort_buffer_size = 256M
read_buffer = 2M
write_buffer = 2M[mysqlhotcopy]
interactive-timeout
MYSQL集群脚本
GRANT REPLICATION SLAVE ON *.* TO 'root' @'%' IDENTIFIED BY '1';
SHOW MASTER STATUS;STOP SLAVE;
CHANGE MASTER TO MASTER_HOST='172.16.108.72',MASTER_USER='root',MASTER_PASSWORD='1',MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=106;
START SLAVE;

SHOW SLAVE STATUS

SHOW MASTER STATUS;

主机的keepalived
[root@k8s1 ~]# vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
notification_email {
root@localhost
}
notification_email_from keepalived@localhost
smtp_server 127.0.0.1 #邮件服务器的地址
smtp_connect_timeout 30
router_id k8s1 #主调度器的主机名
vrrp_mcast_group4 224.26.1.1 #发送心跳信息的组播地址}
vrrp_instance VI_1 {
state BACKUP #主调度器的初始角色
interface enp0s3
virtual_router_id 66 #虚拟路由的ID
nopreempt #设置虚拟ip不被抢占
priority 90 #主调度器的选举优先级
advert_int 1
authentication {
auth_type PASS #集群主机的认证方式
auth_pass 123456 #密钥,最长8位
}
virtual_ipaddress {
172.16.108.99
}
}vrrp_instance VI_2 {
state BACKUP #主调度器的初始角色
interface enp0s3
virtual_router_id 6 #虚拟路由的ID
# nopreempt #注释后要抢占
priority 90 #主调度器的选举优先级
advert_int 1
authentication {
auth_type PASS #集群主机的认证方式
auth_pass 123456 #密钥,最长8位
}
virtual_ipaddress {
172.16.108.110
}
} virtual_server 172.16.108.110 3306 {
delay_loop 2
lb_algo rr
lb_kind DR
persistence_timeout 60
protocol TCP
real_server 172.16.108.71 3306 {
weight 5
#notify_down /etc/keepalived/mysql.sh
TCP_CHECK {
connect_timeout 2
nb_get_retry 3
delay_before_retry 3
connect_port 3306
} }
主机2的keealived
[root@k8s2 ~]# vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
notification_email {
root@localhost
}
notification_email_from keepalived@localhost
smtp_server 127.0.0.1 #邮件服务器的地址
smtp_connect_timeout 30
router_id k8s2 #主调度器的主机名
vrrp_mcast_group4 224.26.1.1 #发送心跳信息的组播地址}
vrrp_instance VI_1 {
state BACKUP #主调度器的初始角色
interface enp0s3
virtual_router_id 66 #虚拟路由的ID
nopreempt #设置虚拟ip不被抢占
priority 90 #主调度器的选举优先级
advert_int 1
authentication {
auth_type PASS #集群主机的认证方式
auth_pass 123456 #密钥,最长8位
}
virtual_ipaddress {
172.16.108.99
}
} vrrp_instance VI_2 {
state BACKUP #主调度器的初始角色
interface enp0s3
virtual_router_id 6 #虚拟路由的ID
nopreempt #设置虚拟ip不被抢占
priority 10 #主调度器的选举优先级
advert_int 1
authentication {
auth_type PASS #集群主机的认证方式
auth_pass 123456 #密钥,最长8位
}
virtual_ipaddress {
172.16.108.110
}
}virtual_server 172.16.108.110 3306 {
delay_loop 2
lb_algo rr
lb_kind DR
persistence_timeout 60
protocol TCP
real_server 172.16.108.72 3306 {
weight 3
#notify_down /etc/keepalived/mysql.sh
TCP_CHECK {
connect_timeout 2
nb_get_retry 3
delay_before_retry 3
connect_port 3306
} }

主1的手下1的keepalived
! Configuration File for keepalived
global_defs {
notification_email {
root@localhost
}
notification_email_from keepalived@localhost
smtp_server 127.0.0.1 #邮件服务器的地址
smtp_connect_timeout 30
router_id k8s3 #主调度器的主机名
vrrp_mcast_group4 224.26.1.1 #发送心跳信息的组播地址}
vrrp_script chk_mysql {
script "/root/chk.sh"
interval 2
}
vrrp_instance VI_1 {
state BACKUP #主调度器的初始角色
interface enp0s3
virtual_router_id 66 #虚拟路由的ID
nopreempt #设置虚拟ip不被抢占
priority 90 #主调度器的选举优先级
advert_int 1
authentication {
auth_type PASS #集群主机的认证方式
auth_pass 123456 #密钥,最长8位
}
virtual_ipaddress {
172.16.108.99
}
}vrrp_instance VI_2 {
state BACKUP #主调度器的初始角色
interface enp0s3
virtual_router_id 7 #虚拟路由的ID
#nopreempt #抢占VIP
priority 90 #主调度器的选举优先级
advert_int 1
authentication {
auth_type PASS #集群主机的认证方式
auth_pass 123456 #密钥,最长8位
}
track_script {
chk_mysql
}
virtual_ipaddress {
172.16.108.111
}
}
主机2的手下2
! Configuration File for keepalived
global_defs {
notification_email {
root@localhost
}
notification_email_from keepalived@localhost
smtp_server 127.0.0.1 #邮件服务器的地址
smtp_connect_timeout 30
router_id k8s3 #主调度器的主机名
vrrp_mcast_group4 224.26.1.1 #发送心跳信息的组播地址}
vrrp_instance VI_1 {
state BACKUP #主调度器的初始角色
interface enp0s3
virtual_router_id 66 #虚拟路由的ID
nopreempt #设置虚拟ip不被抢占
priority 90 #主调度器的选举优先级
advert_int 1
authentication {
auth_type PASS #集群主机的认证方式
auth_pass 123456 #密钥,最长8位
}
virtual_ipaddress {
172.16.108.99
}
}vrrp_instance VI_2 {
state BACKUP #主调度器的初始角色
interface enp0s3
virtual_router_id 7 #虚拟路由的ID
nopreempt #设置虚拟ip不被抢占
priority 10 #主调度器的选举优先级
advert_int 1
authentication {
auth_type PASS #集群主机的认证方式
auth_pass 123456 #密钥,最长8位
}
virtual_ipaddress {
172.16.108.111
}
}
主机1的检查脚本,避免主机1挂了从1还在工作,产生信息孤岛。
/root/chk.sh
#/bin/sh
. /etc/init.d/functionsecho "Up"
count=0
for loop in 1 2 3
do
num=`echo -n "\n"|telnet 172.16.108.71 3306|grep Connected|wc -l`
if [ $num -eq 1 ]
then
action "network is open." /bin/true
systemctl start mysqld
count=0
echo "$count"
else
if [ $count == 2 ]
then
action "network is closed." /bin/false
systemctl stop mysqld
echo 'mysql stop...'
else
count=$((count+1))
fi
fi
done

-----

MYSQL集群双主双备双VIP读写分离高可用优化版KEEPALIVED

c#性能测试代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using MySql.Data;
using MySql.Data.MySqlClient;
namespace MYSQL_TEST
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
}
Thread th;
private void button1_Click(object sender, EventArgs e)
{
th = new Thread(insert);
th.Start();
Thread th1 = new Thread(reada);
th1.Start(); Thread th2 = new Thread(readb);
th2.Start(); Thread th3 = new Thread(readc);
th3.Start(); Thread th4 = new Thread(readd);
th4.Start();
} private void insert()
{
while (true)
{
MySqlConnection sqlCnn = new MySqlConnection();
sqlCnn.ConnectionString = "Database=tx;Data Source=172.16.108.110;Port=3306;User Id=root;Password=1;Charset=utf8;";
MySqlCommand sqlCmd = new MySqlCommand();
sqlCmd.Connection = sqlCnn;
sqlCmd.CommandText = "INSERT INTO ttxx(NAME) VALUES('dfhsdjkhfjkasdhfjkhsdjk');"; try
{
sqlCnn.Open();
int row = sqlCmd.ExecuteNonQuery();
sqlCnn.Close();
}
catch (Exception ex)
{
textBox1.Text += "插入失败:"+ex.Message+"\r\n";
sqlCnn.Close();
}
Thread.Sleep(Convert.ToInt32(textBox2.Text));
} }
private void reada()
{
while (true)
{
MySqlConnection sqlCnn = new MySqlConnection();
sqlCnn.ConnectionString = "Database=tx;Data Source=172.16.108.71;Port=3306;User Id=root;Password=1;Charset=utf8;";
MySqlCommand sqlCmd = new MySqlCommand();
sqlCmd.Connection = sqlCnn;
sqlCmd.CommandText = "select count(*) from ttxx;"; try
{
sqlCnn.Open();
int row = Convert.ToInt32(sqlCmd.ExecuteScalar());
sqlCnn.Close();
lbla.Text = row.ToString() + "条数据";
label1.BackColor = Color.Green;
}
catch (Exception ex)
{
textBox1.Text += "读取71失败:" + ex.Message + "\r\n";
label1.BackColor = Color.Red;
sqlCnn.Close();
}
Thread.Sleep(50);
}
}
private void readb()
{
while (true)
{
MySqlConnection sqlCnn = new MySqlConnection();
sqlCnn.ConnectionString = "Database=tx;Data Source=172.16.108.73;Port=3306;User Id=root;Password=1;Charset=utf8;";
MySqlCommand sqlCmd = new MySqlCommand();
sqlCmd.Connection = sqlCnn;
sqlCmd.CommandText = "select count(*) from ttxx;"; try
{
sqlCnn.Open();
int row = Convert.ToInt32(sqlCmd.ExecuteScalar());
sqlCnn.Close();
lblb.Text = row.ToString() + "条数据";
label2.BackColor = Color.Green;
}
catch (Exception ex)
{
textBox1.Text += "读取73失败:" + ex.Message + "\r\n";
label2.BackColor = Color.Red;
sqlCnn.Close();
}
Thread.Sleep(50);
}
}
private void readc()
{
while (true)
{
MySqlConnection sqlCnn = new MySqlConnection();
sqlCnn.ConnectionString = "Database=tx;Data Source=172.16.108.72;Port=3306;User Id=root;Password=1;Charset=utf8;";
MySqlCommand sqlCmd = new MySqlCommand();
sqlCmd.Connection = sqlCnn;
sqlCmd.CommandText = "select count(*) from ttxx;"; try
{
sqlCnn.Open();
int row = Convert.ToInt32(sqlCmd.ExecuteScalar());
sqlCnn.Close();
lblc.Text = row.ToString() + "条数据";
label3.BackColor = Color.Green;
}
catch (Exception ex)
{
textBox1.Text += "读取72失败:" + ex.Message + "\r\n";
label3.BackColor = Color.Red;
sqlCnn.Close();
}
Thread.Sleep(50);
}
}
private void readd()
{
while (true)
{
MySqlConnection sqlCnn = new MySqlConnection();
sqlCnn.ConnectionString = "Database=tx;Data Source=172.16.108.92;Port=3306;User Id=root;Password=1;Charset=utf8;";
MySqlCommand sqlCmd = new MySqlCommand();
sqlCmd.Connection = sqlCnn;
sqlCmd.CommandText = "select count(*) from ttxx;"; try
{
sqlCnn.Open();
int row = Convert.ToInt32(sqlCmd.ExecuteScalar());
sqlCnn.Close();
lbld.Text = row.ToString() + "条数据";
label4.BackColor = Color.Green;
}
catch (Exception ex)
{
textBox1.Text += "读取92失败:" + ex.Message + "\r\n";
label4.BackColor = Color.Red;
sqlCnn.Close();
}
Thread.Sleep(50);
if (textBox1.Text.Length > 1000) textBox1.Text = "";
}
} private void button2_Click(object sender, EventArgs e)
{ try
{
th.Abort();
}
catch (Exception)
{ th.Abort();
}

}
}
}