如何进行读写分离

  • 由开发人员根据所执行的SQL类型连接不同的服务器
  • 由数据库中间层实现读写分离

读写分离时,需要注意,对于实时性要求比较高的数据,不适合在从库上查询(因为主从复制存在一定延迟(毫秒级)),比如库存就应该在主库上查询,如果放在从库上查询,可能会存在超卖的情况

由开发人员根据所执行的SQL类型进行读写分离的方式

优点:

1. 完全由开发人员控制,实现更加灵活

2. 由程序直接连接数据库,所以性能损耗比较少

缺点:

1. 增加了开发的工作量,使程序代码更加复杂

2. 人为控制,容易出现错误

  1. 可采用DNS轮询的方式

DNS轮询:在同一个域名服务器上为同一个域名配置多个不同IP地址的A记录

应用端使用域名来连接数据库服务器,这样在进行域名解析时,域名服务器会循环的将不同的IP返回给应用端,应用端就可以按地址连接不同的只读服务器来进行读取操作

这种操作比较简单,只需要修改域名服务器的配置即可,但是如果某一后端服务器出现故障,则必须通过修改DNS的方式把故障服务器剔除到只读服务器列表之外,性能较差,负载也不均衡,大多数情况下不推荐此方式

  1. 使用LVS/Haproxy 等代理层软件

由于是通用的代理层软件,所以不能自动对SQL语句进行分析,实现读写分离,但是可以完成只读服务器的负载均衡操作

LVS 四层代理,Haproxy 七层代理,所以从性能来看LVS高于Haproxy

  1. F5硬件:成本较高

keepalived+lvs的架构方式

此处使用keepalived+lvs的架构方式,演示如下

优点:

抗负载能力较强,属于四层代理,只进行流量分发,不会对数据内容进行解析,对内存和CPU的消耗也比较低,处理效率更高

工作稳定,自身有完整的双机热备方案,可进行高可用配置

无流量,只分发请求,流量不从它本身出去,不会对主机的网络IO造成影响

服务器信息

# 主DB         IP:192.168.3.100
# 主备DB IP:192.168.3.101
# SlaveDB IP:192.168.3.102
# keepalived vip:192.168.3.99
# lvs manage : 192.168.3.100/101
# lvs vip :192.168.3.98

1. 安装lvs管理工具

在192.168.3.100 和192.168.3.101上安装lvs管理工具

[root@Node1 keepalived]#    yum install -y ipvsadmin.x86_64

2. 加载ipvs模块

在 192.168.3.100 和192.168.3.101以及192.168.3.102 执行以下命令,加载ipvs模块

[root@Node1 keepalived]#    modprobe ip_vs

3. 在slave服务器上编写并运行要使用lvs脚本

在 192.168.3.101和 192.168.3.102上编写脚本

/etc/init.d/lvsrs 脚本文件内容如下

#!/bin/bash
VIP=192.168.3.98
. /etc/rc.d/init.d/functions
case "$1" in
start)
/sbin/ifconfig lo down
/sbin/ifconfig lo up
echo "1" >/proc/sys/net/ipv4/conf/lo/arp_ignore
echo "2" >/proc/sys/net/ipv4/conf/lo/arp_announce
echo "1" >/proc/sys/net/ipv4/conf/all/arp_ignore
echo "2" >/proc/sys/net/ipv4/conf/all/arp_announce
/sbin/sysctl -p >/dev/null 2>&1
/sbin/ifconfig lo:0 $VIP netmask 255.255.255.255 up
/sbin/route add -host $VIP dev lo:0
echo "LVS-DR real server starts successfully.\n"
;;
stop)
/sbin/ifconfig lo:0 down
/sbin/route del $VIP >/dev/null 2>&1
echo "0" >/proc/sys/net/ipv4/conf/lo/arp_ignore
echo "0" >/proc/sys/net/ipv4/conf/lo/arp_announce
echo "0" >/proc/sys/net/ipv4/conf/all/arp_ignore
echo "0" >/proc/sys/net/ipv4/conf/all/arp_announce
echo "LVS-DR real server stopped."
;;
status)
isLoOn=`/sbin/ifconfig lo:0 | grep "$VIP"`
isRoOn=`/bin/netstat -rn | grep "$VIP"`
if [ "$isLoOn" == "" -a "$isRoOn" == "" ]; then
echo "LVS-DR real server has to run yet."
else
echo "LVS-DR real server is running."
fi
exit 3
;;
*)
echo "Usage: $0 {start|stop|status}"
exit 1
esac
exit 0

/etc/init.d/lvsrs 需要具有可执行权限

运行脚本

[root@Node1 keepalived]#  /etc/init.d/lvsrs start

运行成功后 通过ip addr 命令 可以看到lo中除了127.0.0.1外还有192.168.3.98

4. 修改主服务器上的keepalived.conf文件,通过keepalived,保证lvs的高可用

! Configuration File for keepalived

global_defs {
router_id mysql_ha
}
vrrp_script check_run {
script "/etc/keepalived/check_mysql.sh"
interval 2
} vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 200
priority 99
advert_int 1
nopreempt
authentication {
auth_type PASS
auth_pass 1200
} track_script {
check_run
} virtual_ipaddress {
192.168.3.99/24
}
} vrrp_instance VI_2 {
state BACKUP
interface eth0
virtual_router_id 201
priority 99
advert_int 1
nopreempt
authentication {
auth_type PASS
auth_pass 1200
} virtual_ipaddress {
192.168.3.98/24
}
}
virtual_server 192.168.3.99/24 3306 {
delay_loop 5
lb_algo rr
lb_kind DR
persistence_timeout 120
protocol TCP
sorry_server 192.168.3.99 3306
real_server 192.168.3.101 3306 {
weight 1
MISC_CHECK {
misc_path "/etc/keepalived/check_slave.sh -udba_monitor -p123456 -h10.103.9.204 -P3306"
misc_dynamic
}
}
real_server 192.168.3.102 3306 {
weight 1
MISC_CHECK {
misc_path "/etc/keepalived/check_slave.sh -udba_monitor -p123456 -h10.103.9.205 -P3306"
misc_dynamic
}
}

delay_loop :健康检查时间,单位秒

lb_algo :lvs负载均衡调度算法,rr:轮询算法

lb_kind :lvs实现负载均衡的机制,有NAT,TUN,DR三种模式

persistence_timeout:会话保存时间,单位秒,如果要做session保持,可以将值设大点,可以保证同一个连接在指定时间内都会读取到同一台客户端服务器

sorry_server :后端所有服务器失效后,就会访问此服务器

check_slave.sh 用来监测slave服务器是否可用,当slave服务器宕机或者slave服务器延迟比较大时,脚本会把此slave服务器从lvs的读列表中去掉

脚本内容如下

#/bin/bash
# check_slave.sh
MYSQL=`which mysql`
VIP=192.168.3.98
VPORT=3306
function usage()
{
echo "usage:"
echo "example:# mysql -umonitor -pmonitor -P3306 -h192.168.3.100"
echo "-p, --password[=name]"
echo "-P, --port"
echo "-h, --host=name"
echo "-u, --user=name"
} while getopts "u:p:h:P:" option
do
case "$option" in
u)
dbuser="$OPTARG";;
p)
dbpwd="$OPTARG";;
h)
dbhost="$OPTARG";;
P)
dbport="$OPTARG";;
\?)
usage
exit 1;;
esac
done if [ "-$dbuser" = "-" ]; then
usage
exit 1
fi if [ "-$dbpwd" = "-" ]; then
usage
exit 1
fi if [ "-$dbhost" = "-" ]; then
usage
exit 1
fi if [ "-$dbport" = "-" ]; then
usage
exit 1
fi $MYSQL -u$dbuser -p$dbpwd -P$dbport -h$dbhost -e "select @@version;" >/dev/null 2>&1
if [ $? = 0 ] ;then
MySQL_ok=1
else
/sbin/ipvsadm -d -t $VIP:$VPORT -r $dbhost:$VPORT
exit 1
fi slave_status=$(${MYSQL} -u$dbuser -p$dbpwd -P$dbport -h$dbhost -e 'show slave status \G' | awk ' \
/Slave_IO_Running/{io=$2} \
/Slave_SQL_Running/{sql=$2} \
/Seconds_Behind_Master/{printf "%s %s %d\n",io,sql,$2}') >/dev/null 2>&1 arr=($slave_status)
io=${arr[0]}
sql=${arr[1]}
behind=${arr[2]} if [ "$io" == "No" ]||[ "$sql" == "No" ]; then
/sbin/ipvsadm -d -t $VIP:$VPORT -r $dbhost:$VPORT
exit 1
elif [ $behind -gt 60 ]; then
/sbin/ipvsadm -d -t $VIP:$VPORT -r $dbhost:$VPORT
exit 1
else
/sbin/ipvsadm -a -t $VIP:$VPORT -r $dbhost:$VPORT -g
exit 0
fi

5. 创建lvs用于监控后端数据库所使用的数据库账号

[root@Node1 keepalived]# mysql  -uroot -p

mysql> grant all privileges on *.* to dba_monitor@'192.168.3.%' identified  by '123456';

6. 在使用lvs的manage服务器上编写并运行lvs所需要的脚本

在 192.168.3.100 上编写脚本lvsdr

/etc/init.d/lvsdr 脚本文件内容如下

#!/bin/bash
VIP=192.168.3.98
DEV=eth0
. /etc/rc.d/init.d/functions
case "$1" in
start)
echo "1">/proc/sys/net/ipv4/ip_forward
/sbin/ipvsadm -A -t $VIP:3306 -s rr -p 60
/sbin/ipvsadm -a -t $VIP:3306 -r 10.103.9.204:3306 -g
/sbin/ipvsadm -a -t $VIP:3306 -r 10.103.9.205:3306 -g
/sbin/ipvsadm --start-daemon
echo "LVS-DR server starts successfully.\n"
;;
stop)
/sbin/route del $VIP >/dev/null 2>&1
echo "0" >/proc/sys/net/ipv4/ip_forward
/sbin/ipvsadm -C
echo "LVS-DR real server stopped."
;;
status)
isLoOn=`/sbin/ifconfig lo:0 | grep "$VIP"`
isRoOn=`/bin/netstat -rn | grep "$VIP"`
if [ "$isLoOn" == "" -a "$isRoOn" == "" ]; then
echo "LVS-DR real server has to run yet."
else
echo "LVS-DR real server is running."
fi
exit 3
;;
*)
echo "Usage: $0 {start|stop|status}"
exit 1
esac
exit 0

/etc/init.d/lvsdr 需要具有可执行权限

运行脚本

[root@Node1 keepalived]#  /etc/init.d/lvsdr start

7. 在从服务器上访问虚拟IP,进行测试

[root@Node3 ~]# mysql  -udba_monitor -p123456 -h192.168.3.98 -e"show variables like ''server_id";

可以通过以上命令查看虚拟IP当前所在服务器的server_id

由于我们persistence_timeout设置的是120秒,所以接下来的120秒如果一直运行以上命令可以发现,一直访问的是同一个server_id

下面我们在192.168.3.102上查看一下ipvs的状态,命令如下

 [root@Node2 init.d]#  ipvsadm -L -n

可以看到 192.168.3.98:3306 对应了两个服务器ip 192.168.3.101 和192.168.3.102

接下来我们模拟其中一个服务器宕机的情况

[root@Node3 ~]# /etc/init.d/mysqld stop

然后我们再来查询ipvs状态

 [root@Node1 keepalived]#  ipvsadm -L -n

发现 192.168.3.98:3306 现在只对应了1个服务器ip 192.168.3.101,而192.168.3.102已被剔除

二. 由数据库中间层完成读写分离

常用中间层软件有:MysqlProxy、MaxScale、OneProxy 、 ProxySQL等

优点:

1. 由中间件根据查询语法分析,自动完成读写分离

通过判断SQL语句如果是select语句则使用slave,如果是update、insert、delete、create语句则使用master服务器,无法判断的则使用master

2. 对程序透明,对于已有程序不用做任何调整

3. 前面所说到的一些中间层软件除了能做到读写分离外,还具有能对多个只读数据库进行负载均衡的功能

缺点:

1. 由于增加了中间层,所以对查询效率有损耗

2. 对于延迟敏感的业务无法自动在主库执行

使用MaxScale解决读压力大的问题

MaxScale介绍

支持高可用,负载均衡,良好扩展的插件式数据库中间层软件

MaxScale允许用户开发和定制适合自己的插件,目前MaxScale提供的插件功能主要分为5个种类

1. 认证插件

提供数据库登录认证的功能

2. 协议插件

负责 MaxScale和外部系统间接口的协议,包括客户端到MaxScale的接口,以及MaxScale 到后端数据库的接口

3. 路由插件

ReadConnRoute 用来解决多台读服务器的负载均衡

ReadWriteSplit 用来实现读写分离

4. 监控插件

用于对后端数据库进行实时监控,以便将前端请求发送到正确的(即正常的可以对外提供服务的)数据库中

5. 过滤和日志插件

提供了简单的数据库防火墙功能,可以对某些SQL进行过滤和改写,可以进行一些简单的SQL容错和语句的自动转换

使用MaxScale

安装方法自行百度

服务器信息

MaxScale 节点 192.168.3.102
Master DB:192.168.3.100
Slave DB:192.168.3.101
Slave DB:192.168.3.102

1. 为监控模块创建mysql账号

mysql> create user scalemon@'192.168.3.%' identified by '123456';
mysql> grant replication slave,replication client on *.* to scalemon@'192.168.3.%';

2. 为路由模块创建mysql账号

用来读取mysql系统库下的表,获取后端数据库的权限

mysql> create user scaleroute@'192.168.3.%' identified by '123456';
mysql> grant select on mysql.* to scaleroute@'192.168.3.%';

3. 对数据库密码进行加密

因为maxScale的配置文件是一个文本格式的明文文件,在文件中直接书写mysql密码是不安全的

maxScale提供了加密mysql密码的命令,这个命令是在maxScale节点中运行

[root@Node3 tools]#  maxpassword  /var/lib/maxscale/    123456
E3AEE4B7125B9C76BF742AE6246ECC5C

生成了密码123456对应的加密字符串

4. 对maxscale进行配置

[root@Node3 tools]#   vim /etc/maxscale.cnf

参数说明

[maxscale]
thread=1 # 不要超过cpu的数量 [server1]
type=server
address=192.168.3.100
port=3306
protocol=MySQLBackend [server2]
type=server
address=192.168.3.101
port=3306
protocol=MySQLBackend [server3]
type=server
address=192.168.3.102
port=3306
protocol=MySQLBackend [MySQL Monitor]
type=monitor
module =mysqlmon
servers=server1,server2,server3
user=scalemon
passwd=E3AEE4B7125B9C76BF742AE6246ECC5C # 使用刚刚的加密字符串
monitor_interval=1000 # 毫秒 [Read-Write Service]
type=service
router=readwritesplit
servers=server1,server2,server3
user=scalerouter
passwd=E3AEE4B7125B9C76BF742AE6246ECC5C # 使用刚刚的加密字符串
max_slave_connections=100%
max_slave_replication_lag=60 [MaxAdmin Service]
type=service
router=cli [Read-Write Listener]
type=listener
service=Read-Write Service
protocol=MySQLClient
port=4006 [MaxAdmin Listener]
type=listener
service=MaxAdmin Service
protocol=maxscaled
port=6603

5. 启动maxscale服务

[root@Node3 tools]# maxscale -f /etc/maxscale.cnf

6. 查看maxscale服务状态

maxscale是使用maxadmin进行管理的,默认账号是admin,密码是mariadb

 [root@Node3 tools]#    maxadmin --user=admin --password=mariadb
# 查看后端服务器列表
MaxScale> list servers # 查看是否读取到了后端数据库服务器的账号
MaxScale> show dbusers "Read-Write Service"

引入MaxScale后的架构

将双主架构改为了单主架构,因为MaxScale会自动识别后端服务器的角色,如果使用双主架构,则无法分清当前的主是哪一个

(10) 如何MySQL读压力大的问题的更多相关文章

  1. 高并发大流量专题---10、MySQL数据库层的优化

    高并发大流量专题---10.MySQL数据库层的优化 一.总结 一句话总结: mysql先考虑做分布式缓存,过了缓存后就做mysql数据库层面的优化 1.mysql数据库层的优化的前面一层是什么? 数 ...

  2. Mysql千万级大表优化

    Mysql的单张表的最大数据存储量尚没有定论,一般情况下mysql单表记录超过千万以后性能会变得很差.因此,总结一些相关的Mysql千万级大表的优化策略. 1.优化sql以及索引 1.1优化sql 1 ...

  3. mysql+mycat压力测试一例【转】

    前言 有很多人担心生产系统上新东西的程序怕压力跟不上和稳定性不行,是的,大家都怕,所以领导要求做一次压力测试,我个人也觉得是有必要的. 如果按原理来说,mycat如果不做分片,纯粹只是代理的话,他所做 ...

  4. 如何优化MySQL千万级大表

    很好的一篇博客,转载 如何优化MySQL千万级大表 原文链接::https://blog.csdn.net/yangjianrong1985/article/details/102675334 千万级 ...

  5. 第 10 章 MySQL Server 性能优化

    前言: 本章主要通过针对MySQL Server(mysqld)相关实现机制的分析,得到一些相应的优化建议.主要涉及MySQL的安装以及相关参数设置的优化,但不包括mysqld之外的比如存储引擎相关的 ...

  6. 10 个 MySQL 经典错误【转】

    Top 1:Too many connections(连接数过多,导致连接不上数据库,业务无法正常进行) 问题还原 mysql> show variables like '%max_connec ...

  7. MySQL性能调优与架构设计——第10章 MySQL数据库Schema设计的性能优化

    第10章 MySQL Server性能优化 前言: 本章主要通过针对MySQL Server(mysqld)相关实现机制的分析,得到一些相应的优化建议.主要涉及MySQL的安装以及相关参数设置的优化, ...

  8. 重新学习MySQL数据库10:MySQL里的那些日志们

    重新学习MySQL数据库10:MySQL里的那些日志们 同大多数关系型数据库一样,日志文件是MySQL数据库的重要组成部分.MySQL有几种不同的日志文件,通常包括错误日志文件,二进制日志,通用日志, ...

  9. mysql之 mysql数据库压力测试工具(mysqlslap)

    mysqlslap是从MySQL的5.1.4版开始就开始官方提供的压力测试工具.通过模拟多个并发客户端并发访问MySQL来执行压力测试,同时提供了较详细的SQL执行数据性能报告,并且能很好的对比多个存 ...

随机推荐

  1. git 将主分支的提交合并到分支上(主分支同步到分支)

    通常都会遇到将分支修改的内容合并到主分支中,但是在主分支中修改了内容怎么同步到分支上呢,这个时候需要将主分支上的提交操作在分支上再做一次: 1.首先在主分支上执行: git log 2.找到你想要同步 ...

  2. AGC 007D.Shik and Game(DP)

    题目链接 \(Description\) 数轴上有一个人,从\(0\)出发到\(E\),速度为\(1\).数轴上还有\(n\)只熊,每只熊会在经过后的\(T\)时刻后产生一个金币.给定\(E,T\)以 ...

  3. Linux下MySQL数据库常用基本操作

    1.显示数据库 show databases; 2.选择数据库 use 数据库名; 3.显示数据库中的表 show tables; 4.显示数据表的结构 describe 表名; 5.显示表中记录 S ...

  4. docker 与启动后的镜像进行交互

    docker ps docker exec -t -i jenk /bin/bash 在启动时进行交互 docker run -i -t ubuntu:15.10 /bin/bash

  5. HTML5:在移动端禁用长按选中文本功能

    很多时候,我们在写的手机页面需要用户进行长按然后响应一个事件.但是在微信中用户的长按操作被默认为谈出来一个复制的选项.那么这个时候如何去禁止这个东西呢? 其实很简单,方法看下面: 只需要在你需要禁止的 ...

  6. python网络编程(四)

    TFTP客户端 1. TFTP协议介绍 TFTP(Trivial File Transfer Protocol,简单文件传输协议) 是TCP/IP协议族中的一个用来在客户端与服务器之间进行简单文件传输 ...

  7. C++程序设计方法5:接口设计

    一切都在变化,因此程序要适应变化: 变化分层 封装 接口与隐藏: 接口:类暴露出来的部分,是类所提供的功能: 隐藏实现的细节: UML类图 接口在哪儿? 设计思路:从上到下设计 实现类的接口 细化

  8. idea快捷键列表

    Ctrl+Shift + Enter,语句完成 “!”,否定完成,输入表达式时按 “!”键 Ctrl+E,最近的文件 Ctrl+Shift+E,最近更改的文件 Shift+Click,可以关闭文件 C ...

  9. F - 质数检测 V2

    https://vjudge.net/contest/218366 Java解 import java.math.BigInteger; import java.util.Scanner; publi ...

  10. C#设置WebBrowser IE浏览器版本

    通过修改注册表的值,来指定winform程序打开的webBrowser的IE版本 1>方法一,通过程序修改注册表的值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ...