使用docker run
运行一个新的容器的时候,通过参数 --add-host
来添加域名和IP
信息到容器的/etc/hosts
文件中。例如:
docker run -d --name test --add-host=addr.com:10.10.18.11 redis:latest
查看mysql
慢查询日志
-- 慢查询日志
show variables like '%slow_query%';
+---------------------+--------------------------------------+
| Variable_name | Value |
+---------------------+--------------------------------------+
| slow_query_log | OFF |
| slow_query_log_file | /var/lib/mysql/7b32a384231d-slow.log |
+---------------------+--------------------------------------+
2 rows in set
-- 不使用索引查询日志
mysql> show variables like '%log_que%';
+-------------------------------+-------+
| Variable_name | Value |
+-------------------------------+-------+
| log_queries_not_using_indexes | OFF |
+-------------------------------+-------+
1 row in set
-- 查询时间设置,查询超过多少秒才记录
mysql> show variables like '%long_que%';
+-----------------+-----------+
| Variable_name | Value |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
1 row in set
开启慢查询日志
-- 方法一
set global slow_query_log=ON;
set global log_queries_not_using_indexes=ON;
-- 方法二,修改配置文件my.cnf
slow_query_log = ON
slow_query_log_file = /usr/local/mysql/data/slow.log
long_query_time = 1
-- 方法二需要重启
service mysqld restart
慢查询分析工具
mysqldumpslow
pt-query-digest
MySQL主从复制包括异步模式、半同步模式、GTID模式以及多源复制模式,默认是异步模式.
Asynchronous replication
)所谓异步模式指的是MySQL 主服务器上I/O thread 线程将二进制日志写入binlog文件之后就返回客户端结果,不会考虑二进制日志是否完整传输到从服务器以及是否完整存放到从服务器上的relay log(中继日志)中,这种模式一旦主服务(器)宕机,数据就可能会发生丢失。
Fully synchronous replication
)指当主库执行完一个事务,所有的从库都执行了该事务才返回给客户端。因为需要等待所有从库执行完该事务才能返回,所以全同步复制的性能必然会收到严重的影响。
Semisynchronous replication
)介于异步复制和全同步复制之间,主库在执行完客户端提交的事务后不是立刻返回给客户端,而是等待至少一个从库接收到并写到relay log中才返回给客户端。相对于异步复制,半同步复制提高了数据的安全性,同时它也造成了一定程度的延迟,这个延迟最少是一个TCP/IP往返的时间。所以,半同步复制最好在低延时的网络中使用。
mysql5.7
版本前,客户端事务在存储引擎层提交后,在得到从库确认的过程中,主库宕机了,客户端会收到事务提交失败的信息,此时,可能的情况有两种:
此时客户端由于提交失败,再次提交事务,出现问题.
mysql5.7
版本引入新的半同步方式,事务提交需要从库同步完成.通过rpl_semi_sync_master_wait_point
参数控制:
AFTER_SYNC
, 这个是新的半同步方案AFTER_COMMIT
, 这个是老的半同步方案半同步复制的安装部署条件:
MySQL 5.5
及以上版本have_dynamic_loading
为YES
(查看命令:show variables like "have_dynamic_loading";
)半同步复制是以插件的形式安装的,默认安装包在/usr/local/mysql/lib/plugin/
目录下.可以通过命令查看
-- 查看所有插件
show plugins;
-- 模糊查询
SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE '%semi%';
-- 主库执行安装插件
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
-- 主库执行开启
SET GLOBAL rpl_semi_sync_master_enabled = 1;
-- 从库执行安装插件
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
-- 从库执行开启
SET GLOBAL rpl_semi_sync_master_enabled = 1;
-- 从库重启IO线程
STOP SLAVE IO_THREAD;
START SLAVE IO_THREAD;
-- 主库卸载插件(先关闭半同步复制功能)
UNINSTALL PLUGIN rpl_semi_sync_master;
-- 从库卸载插件(先关闭半同步复制功能)
UNINSTALL PLUGIN rpl_semi_sync_slave;
my.cnf
,需要重启mysql
# 主库配置
plugin-load=rpl_semi_sync_master=semisync_master.so
rpl_semi_sync_master_enabled=1
# 从库配置
plugin-load=rpl_semi_sync_slave=semisync_slave.so
rpl_semi_sync_slave_enabled=1
# 如果既是主又是从
plugin-load="rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so"
rpl-semi-sync-master-enabled=1
rpl-semi-sync-slave-enabled=1
需要注意,
Mysql半同步复制
并不是严格意义上的半同步复制。当半同步复制发生超时时(由rpl_semi_sync_master_timeout
参数控制,单位是毫秒,默认为10000
,即10s
),会暂时关闭半同步复制,转而使用异步复制。当master dump线程发送完一个事务的所有事件之后,如果在rpl_semi_sync_master_timeout
内,收到了从库的响应,则主从又重新恢复为半同步复制。一旦有一次超时自动降级为异步
.
-- 查看插件
mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE '%semi%';
+----------------------+---------------+
| PLUGIN_NAME | PLUGIN_STATUS |
+----------------------+---------------+
| rpl_semi_sync_master | ACTIVE |
+----------------------+---------------+
1 row in set (0.00 sec)
-- 主库
mysql> show status like 'Rpl_semi_sync_master_status';
+-----------------------------+-------+
| Variable_name | Value |
+-----------------------------+-------+
| Rpl_semi_sync_master_status | ON |
+-----------------------------+-------+
1 row in set (0.01 sec)
-- 从库
mysql> show status like 'Rpl_semi_sync_slave_status';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON |
+----------------------------+-------+
1 row in set (0.00 sec)
-- 查看主库半同步插件运行参数
-- rpl_semi_sync_master_wait_for_slave_count 设置主需要等待多少个slave应答,才能返回给客户端,默认为1
mysql> show variables like '%Rpl%';
+-------------------------------------------+------------+
| Variable_name | Value |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled | ON |
| rpl_semi_sync_master_timeout | 10000 |
| rpl_semi_sync_master_trace_level | 32 |
| rpl_semi_sync_master_wait_for_slave_count | 1 |
| rpl_semi_sync_master_wait_no_slave | ON |
| rpl_semi_sync_master_wait_point | AFTER_SYNC |
| rpl_stop_slave_timeout | 31536000 |
+-------------------------------------------+------------+
-- 查看从库半同步插件运行参数
mysql> show variables like '%Rpl%';
+---------------------------------+----------+
| Variable_name | Value |
+---------------------------------+----------+
| rpl_semi_sync_slave_enabled | ON |
| rpl_semi_sync_slave_trace_level | 32 |
| rpl_stop_slave_timeout | 31536000 |
+---------------------------------+----------+
3 rows in set (0.00 sec)
-- 查看主库半同步插件运行状态status
mysql> show status like '%Rpl_semi%';
+--------------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients | 1 |
| Rpl_semi_sync_master_net_avg_wait_time | 0 |
| Rpl_semi_sync_master_net_wait_time | 0 |
| Rpl_semi_sync_master_net_waits | 1 |
| Rpl_semi_sync_master_no_times | 0 |
| Rpl_semi_sync_master_no_tx | 0 |
| Rpl_semi_sync_master_status | ON |
| Rpl_semi_sync_master_timefunc_failures | 0 |
| Rpl_semi_sync_master_tx_avg_wait_time | 461 |
| Rpl_semi_sync_master_tx_wait_time | 461 |
| Rpl_semi_sync_master_tx_waits | 1 |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0 |
| Rpl_semi_sync_master_wait_sessions | 0 |
| Rpl_semi_sync_master_yes_tx | 1 |
+--------------------------------------------+-------+
14 rows in set (0.00 sec)
-- 正常情况下插入数据
mysql> insert into test.testttt values(1,'22');
Query OK, 1 row affected (0.00 sec)
-- 从库关闭主从复制
mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)
-- 再次插入数据,时间与设置的超时时间吻合
mysql> insert into test.testttt values(1,'222');
Query OK, 1 row affected (10.01 sec)
-- 查看半同步插件状态
mysql> show status like 'Rpl_semi_sync_master_status';
+-----------------------------+-------+
| Variable_name | Value |
+-----------------------------+-------+
| Rpl_semi_sync_master_status | OFF |
+-----------------------------+-------+
1 row in set (0.00 sec)
mysql> show status like 'Rpl_semi_sync_slave_status';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | OFF |
+----------------------------+-------+
1 row in set (0.00 sec)
-- 从库开启同步
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
-- 再次插入数据,恢复正常
mysql> insert into test.testttt values(1,'222');
Query OK, 1 row affected (0.00 sec)
-- 查看半同步插件状态也是ON
sync_binlog
默认,sync_binlog=0
,表示MySQL不控制binlog的刷新,由文件系统自己控制它的缓存的刷新。这时候的性能是最好的,但是风险也是最大的。因为一旦系统Crash,在binlog_cache中的所有binlog信息都会被丢失。
如果sync_binlog>0
,表示每sync_binlog次事务提交,MySQL调用文件系统的刷新操作将缓存刷下去。最安全的就是sync_binlog=1
了,表示每次事务提交,MySQL都会把binlog刷下去,是最安全但是性能损耗最大的设置。
默认为10000
,即每10000
次sync_relay_log
事件会刷新到磁盘。为0
则表示不刷新,交由系统的cache
控制
# my.cnf,最安全配置,牺牲性能
sync_binlog=1
sync_master_info=1
sync_relay_log=1
sync_relay_log_info=1
双主之间复制如果网络中断或者其它原因导致不可用,此时在不同主上修改了同一条数据,就会存在数据不一致的情况。
#slave-skip-errors=all # 忽略复制产生的错误
#slave-skip-errors=1062,1032,1060 # 跳过已知错误,主键冲突、表已存在等错误代码如1062,1032,1060等
但是这样数据不一致的问题还是存在.
# 从节点设置不能写,设置完需要重启mysql服务
read_only=ON
super_read_only=ON
# SQL
FLUSH TABLES WITH READ LOCK;
当BIN-LOG
里面出现错误导致主从不能同步的时候,
-- 错误状态的部分截图
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.41.141
Slave_IO_Running: Yes
Slave_SQL_Running: No
Replicate_Do_DB:
Last_Errno: 1032
Last_Error: Could not execute Update_rows event on table test.testttt; Can't find record in 'testttt', Error_code: 1032; handler error HA_ERR_END_OF_FILE; the event's master log mysql-bin.000004, end_log_pos 404
Skip_Counter: 0
Last_SQL_Errno: 1032
Last_SQL_Error: Could not execute Update_rows event on table test.testttt; Can't find record in 'testttt', Error_code: 1032; handler error HA_ERR_END_OF_FILE; the event's master log mysql-bin.000004, end_log_pos 404
Replicate_Ignore_Server_Ids:
Retrieved_Gtid_Set: 69a5d660-cfd9-11ea-8174-00505626c27e:1-5
Executed_Gtid_Set: 69a5d660-cfd9-11ea-8174-00505626c27e:4,
b3802ae3-cfd8-11ea-85e8-00505630c9f5:1-2
1 row in set (0.00 sec)
可以用下面方法掠过该错误语句行,继续同步:
stop slave;
set global sql_slave_skip_counter=1;
start slave;
当set global sql_slave_skip_counter=1;
是可能会出现一下错误:不支持GTID_MODE
模式运行的数据库
ERROR 1858 (HY000): sql_slave_skip_counter can not be set when the server is running with GTID_MODE = ON. Instead, for each transaction that you want to skip, generate an empty transaction with the same GTID as the transaction
show slave status\G
-- 找到这一行
Executed_Gtid_Set: 69a5d660-cfd9-11ea-8174-00505626c27e:1-5
reset master;
stop slave;
reset slave;
-- 1-5 可能出错,ID加1,1-6
set global gtid_purged='69a5d660-cfd9-11ea-8174-00505626c27e:1-6';
set global gtid_purged='xxxxx';
要求GTID_EXECUTED
为空,所以需要第二部重置操作.
change master to master_host='192.168.41.141',master_port=3306,master_user='slave',master_password='123456',master_auto_position=1;
start slave;
-- 确认Slave_IO_Running,Slave_SQL_Running,Last_Error,Last_SQL_Error等是否有错
-- 如果还有错但和上面的错误ID不一样,需要重复1~4
show slave status\G
双主
模式更麻烦,需要两边都要做1~4
操作,确认没有错误.
前文仅仅通过mysql双主 + keepalived
实现高可用,这种方式在一台出现问题的时候可以切换,但是正常情况下只有一台服务使用,无法实现负载均衡,本文引入haproxy
实现正常情况下也能有负载均衡的效果.
haproxy
yum install haproxy
haproxy
配置文件/etc/haproxy/haproxy.cfg
#---------------------------------------------------------------------
# Example configuration for a possible web application. See the
# full configuration options online.
#
# http://haproxy.1wt.eu/download/1.4/doc/configuration.txt
#
#---------------------------------------------------------------------
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
# to have these messages end up in /var/log/haproxy.log you will
# need to:
#
# 1) configure syslog to accept network log events. This is done
# by adding the '-r' option to the SYSLOGD_OPTIONS in
# /etc/sysconfig/syslog
#
# 2) configure local2 events to go to the /var/log/haproxy.log
# file. A line like the following can be added to
# /etc/sysconfig/syslog
#
# local2.* /var/log/haproxy.log
#
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
# turn on stats unix socket
stats socket /var/lib/haproxy/stats
#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.0/8
option redispatch
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000
######## 监控界面配置 #################
listen admin_status
bind 0.0.0.0:8888
mode http
stats refresh 30s
stats uri /
stats realm welcome login\ Haproxy
stats auth admin:123456
stats hide-version
stats admin if TRUE
########frontend配置##############
######## mysql负载均衡配置 ###############
listen mysql
bind 0.0.0.0:13306
mode tcp
balance roundrobin # 负载均衡策略
#option tcplog # tcp日志
option mysql-check user haproxy # 在mysql中创建无任何权限用户haproxy,且无密码
server mysql_1 192.168.41.141:3306 check weight 1 maxconn 2000
server mysql_2 192.168.41.142:3306 check weight 1 maxconn 2000
option tcpka # 缺少这个配置,可能无法查看到数据库
option mysql-check user haproxy
这里是配置健康检查的,需要在mysql中创建无任何权限用户haproxy
,且无密码.
CREATE USER 'haproxy'@'%' IDENTIFIED BY '';
haproxy
要求ulimit
大于(maxconn*2 + 15 )
#临时修改
ulimit -n 65536
#永久修改,需要修改/etc/security/limits.conf配置文件,文末增加以下内容,然后重新登录就可以生效
* soft nofile 65536
* hard nofile 65536
* soft nproc 65565
* hard nproc 65565
启动后访问8888
端口,使用admin/123456
登录就可以看到UI界面
了。
systemctl start haproxy
systemctl enable haproxy
keepalived
配置keepalived
监控的是mysqld
进程,需要修改成监控haproxy
进程.这样不管哪台机器的mysql
或者haproxy
或者keepalived
出现问题,都不影响使用.# 修改的配置如下
vrrp_script chk_mysql {
script "killall -0 haproxy"
interval 2
timeout 2
fall 3
}
VIP
连接数据库,增删改查测试.