mysql-物理备份-Percona xtrabackup

xtrabackup是percona公司开发的一个用于mysql物理热备的备份工具。

软件安装后一共有4个可执行文件:

  • innobackupex:perl脚本,用来备份非innodb表,同时会调用xtrabackup来备份innodb表,会和mysql server进行交互。如:加读锁(FTWRL),获取位点(show slave status)等。即封装了xtrabackup

  • xbcrypt:用来解密

  • xbstream:类似tar,一种支持并发写的流文件格式。和xbcrypt都在备份和解压会用到

  • xtrabackup:c/c++编译的二进制,用来备份innodb表,和mysql server没有交互

原理

通信方式:xtrabackup和innobackupex之间的交互和协调是通过控制文件的创建和删除来实现的。

主要文件:

    xtrabackup_suspended_1
    xtrabackup_suspended_2
    xtrabackup_log_copied

例:看看备份时xtrabackup_suspended_2是怎么协调2个工具进程的:

  1. innobackupex在启动xtrabackup进程后,会一直等xtrabackup备份完innodb文件,方式就是等待xtrabackup_suspended_2被创建出

  2. xtrabackup备份完innodb数据后,就在指定目录下创建出xtrabackup_suspended_2,然后等到这个文件被innobackupex删除,

  3. innobackupex 检测到文件 xtrabackup_suspended_2 被创建出来后,就继续往下走;

  4. innobackupex 在备份完非 InnoDB 表后,删除 xtrabackup_suspended_2 这个文件,这样就通知 xtrabackup 可以继续了,然后等 xtrabackup_log_copied 被创建;

  5. xtrabackup 检测到 xtrabackup_suspended_2 文件删除后,就可以继续往下了。

未分类

备份过程图

未分类

说明:

  1. innobackupex 在启动后,会先 fork 一个进程,启动 xtrabackup进程,然后就等待 xtrabackup 备份完 ibd 数据文件;

  2. xtrabackup 在备份 InnoDB 相关数据时,是有2种线程的,1种是 redo 拷贝线程,负责拷贝 redo 文件,1种是 ibd 拷贝线程,负责拷贝 ibd 文件;redo 拷贝线程只有一个,在 ibd 拷贝线程之前启动,在 ibd 线程结束后结束。xtrabackup 进程开始执行后,先启动 redo 拷贝线程,从最新的 checkpoint 点开始顺序拷贝 redo 日志;然后再启动 ibd 数据拷贝线程,在 xtrabackup 拷贝 ibd 过程中,innobackupex 进程一直处于等待状态(等待文件被创建)。

  3. xtrabackup 拷贝完成idb后,通知 innobackupex(通过创建文件),同时自己进入等待(redo 线程仍然继续拷贝);

  4. innobackupex 收到 xtrabackup 通知后,执行FLUSH TABLES WITH READ LOCK (FTWRL),取得一致性位点,然后开始备份非 InnoDB 文件(包括 frm、MYD、MYI、CSV、opt、par等)。拷贝非 InnoDB 文件过程中,因为数据库处于全局只读状态,如果在业务的主库备份的话,要特别小心,非 InnoDB 表(主要是MyISAM)比较多的话整库只读时间就会比较长,这个影响一定要评估到。

  5. 当 innobackupex 拷贝完所有非 InnoDB 表文件后,通知 xtrabackup(通过删文件) ,同时自己进入等待(等待另一个文件被创建);

  6. xtrabackup 收到 innobackupex 备份完非 InnoDB 通知后,就停止 redo 拷贝线程,然后通知 innobackupex redo log 拷贝完成(通过创建文件);

  7. innobackupex 收到 redo 备份完成通知后,就开始解锁,执行 UNLOCK TABLES;

  8. 最后 innobackupex 和 xtrabackup 进程各自完成收尾工作,如资源的释放、写备份元数据信息等,innobackupex 等待 xtrabackup 子进程结束后退出。

在备份进程中都是直接通过操作系统读取数据文件的,只在执行SQL命令时和数据库有交互,基本不会影响数据库的运行,在备份非innodb时会有一段时间只读,对备份innodb表时完全没有影响。

备份innodb文件和非innodb都是通过拷贝文件,但实现的方式不一样,innodb是以page粒度(xtrabackup),在读取每个page时会检验checksum值,保证数据块是一致的;非innodb是cp或者tar(innobackupex),由于对文件做了FTWRL,磁盘上的文件也是完整的,备份的数据也是完整的。

keepalived + haproxy + mysql 构建高可用数据库

keepalived + haproxy + mysql 构建高可用

  • keepalived 的高可用是主备,有一台作为备用
  • keepalived + haproxy 搭建的高可用是可以两台都会调度的高可用

拓扑图:

未分类

keepalived:负责抢占虚拟ip,使用vrrp协议
haproxy:负责做访问调度,减轻单点压力,单独监听一个端口,这里用23306

1、安装mysql

分别在两台机器上面搭建mysql,并做主从配置,这里不做介绍

2、搭建haproxy

  1. download 源码包,下载地址:http://www.haproxy.org/#down
  2. 在81.128和81.129解压缩安装
tar xf haproxy-1.8.4.tar.gz
cd haproxy-1.8.4
yum install -y gcc
make TARGET=linux310 ARCH=x86_64 # uname -a查看主机信息填写
make install SBINDIR=/usr/sbin/ MANDIR=/usr/share/man/ DOCDIR=/usr/share/doc/

3、提供启动脚本

#!/bin/sh
#
# haproxy
#
# chkconfig:   - 85 15
# description:  HAProxy is a free, very fast and reliable solution 
#               offering high availability, load balancing, and 
#               proxying for TCP and  HTTP-based applications
# processname: haproxy
# config:      /etc/haproxy/haproxy.cfg
# pidfile:     /var/run/haproxy.pid

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0

exec="/usr/sbin/haproxy"
prog=$(basename $exec)

[ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog

cfgfile=/etc/haproxy/haproxy.cfg
pidfile=/var/run/haproxy.pid
lockfile=/var/lock/subsys/haproxy

check() {
    $exec -c -V -f $cfgfile $OPTIONS
}

start() {
    $exec -c -q -f $cfgfile $OPTIONS
    if [ $? -ne 0 ]; then
        echo "Errors in configuration file, check with $prog check."
        return 1
    fi

    echo -n $"Starting $prog: "
    # start it up here, usually something like "daemon $exec"
    daemon $exec -D -f $cfgfile -p $pidfile $OPTIONS
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}

stop() {
    echo -n $"Stopping $prog: "
    # stop it here, often "killproc $prog"
    killproc $prog
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}

restart() {
    $exec -c -q -f $cfgfile $OPTIONS
    if [ $? -ne 0 ]; then
        echo "Errors in configuration file, check with $prog check."
        return 1
    fi
    stop
    start
}

reload() {
    $exec -c -q -f $cfgfile $OPTIONS
    if [ $? -ne 0 ]; then
        echo "Errors in configuration file, check with $prog check."
        return 1
    fi
    echo -n $"Reloading $prog: "
    $exec -D -f $cfgfile -p $pidfile $OPTIONS -sf $(cat $pidfile)
    retval=$?
    echo
    return $retval
}

force_reload() {
    restart
}

fdr_status() {
    status $prog
}

case "$1" in
    start|stop|restart|reload)
        $1
        ;;
    force-reload)
        force_reload
        ;;
    check)
        check
        ;;
    status)
        fdr_status
        ;;
    condrestart|try-restart)
        [ ! -f $lockfile ] || restart
        ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|try-restart|reload|force-reload}"
        exit 2
esac

4、提供配置文件

mkdir /etc/haproxy
mkdir /var/lib/haproxy
useradd -r haproxy
vim /etc/haproxy/haproxy.cfg
global

    log         127.0.0.1 local2

    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon

    stats socket /var/lib/haproxy/stats

defaults
    mode                    tcp
    log                     global
    option                  dontlognull
    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                 600

listen stats
    mode http
    bind :6677 
    stats enable
    stats hide-version              
    stats uri     /haproxyadmin?stats
    stats realm   Haproxy Statistics
    stats auth    admin:admin
    stats admin if TRUE 

frontend  main 
    bind  *:23306
    default_backend             mysql

backend mysql
    balance     leastconn
    server m1 192.168.81.128:3306 check port 3306 maxconn 300
    server m2 192.168.81.129:3306 check port 3306 maxconn 300

5、修改日志系统

###Provides UDP syslog reception //去掉下面两行注释,开启UDP监听

$ModLoad imudp
$UDPServerRun 514

local2.* /var/log/haproxy.log //添加此行
service rsyslog restart

6、启动测试haproxy

service haproxy start 
chkconfig --add haproxy
chkconfig haproxy on
netstat -tnlp
mysql -P23306 -uroot -p123456 -h192.168.81.129 # 查看

server_id,判断是否成功

7、搭建keepalived

1、download 源码包,下载地址:http://www.keepalived.org/download.html

2、在81.128和81.129解压缩安装

tar xf keepalived-1.2.7.tar.gz 
cd keepalived-1.2.7
./configure --prefix=/usr/local/keepalived --sbindir=/usr/sbin/ --sysconfdir=/etc/ --mandir=/usr/local/share/man/
make && make install
chkconfig --add keepalived
chkconfig keepalived on

3、提供配置文件

vim /etc/keepalived/keepalived.conf # 两个机器配置文件不同

! Configuration File for keepalived

global_defs {           
notification_email {          # 忽略
     [email protected]
     [email protected]
     [email protected]
   }
   notification_email_from [email protected]
   smtp_server 192.168.200.1
   smtp_connect_timeout 30
   router_id LVS_DEVEL
}

vrrp_script chk_haproxy {
    script "/etc/keepalived/chk.sh"     # 检查haproxy的脚本
    interval 2                          # 每两秒检查一次
}

vrrp_instance VI_1 {
    state BACKUP                        # 定义为BACKUP节点
    nopreempt                           # 开启不抢占,另一个不写
    interface ens33
    virtual_router_id 51
    priority 100                        # 开启了不抢占,所以此处优先级必须高于另一台,另一个写99
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass abcd
    }
    virtual_ipaddress {
        192.168.81.150                  # 配置VIP
    }
    track_script {
        chk_haproxy                     # 调用检查脚本
    }

    notify_backup "/etc/init.d/haproxy restart"
    notify_fault "/etc/init.d/haproxy stop"
} 

4、创建check文件

vim /etc/keepalived/chk.sh
#!/bin/bash

if [ $(ps -C haproxy --no-header | wc -l) -eq 0 ]; then
       /etc/init.d/keepalived stop
fi
chmod +x /etc/keepalived/chk.sh 
service keepalived start

5、测试

ip addr # 查看是否绑定了虚ip
tcpdump -nn -i ens33 vrrp # 抓包查看
http://192.168.81.128:6677/haproxyadmin?stats # 通过haproxy查看状态

CentOS 7离线安装MySQL 5.7

前言

网上已经有那么多的关于CentOS 7如何安装MySQL的文章了, 那为什么我还要写这没一篇关于CentOS 7安装MySQL的文章呢?主要有以下几个原因:

  • 网上很多都是在线安装;由于很多时候,在生产环境进行部署时,生产机器都是不可能直接连公网的,导致网上很多的文章没有借鉴意义;

  • 网上很多文章都比较旧,安装的MySQL版本也比较旧,没有进行更新,导致很多步骤在新的MySQL版本安装上不适用;

  • 网上很多文章本身就是错的,很容易误导读者;我曾经就被误导过;

为了总结一篇实用的,不误导大家的文章,也让搜索到我这篇文章的读者们不用再浪费时间去搜索别的安装教程,节省大家的时间,所以抽点时间把如何在CentOS 7下离线安装MySQL的步骤进行详细的总结;为大家图个方便,也为自己做个笔记和总结。

前期准备

1、MySQL 5.7 Linux安装包下载:
https://dev.mysql.com/downloads/mysql/

未分类

2、查询并卸载系统自带的Mariadb

rpm -qa | grep mariadb
rpm -e --nodeps 文件名

安装实施

1、为了方便数据库管理,对于安装的MySQL数据库,生产上我们都会建立一个mysql用户和mysql用户组:

# 添加mysql用户组
groupadd mysql

# 添加mysql用户
useradd -g mysql mysql -d /home/mysql

# 修改mysql用户的登陆密码
passwd mysql

2、创建临时目录、数据目录和日志目录

/home/mysql/3306/data
/home/mysql/3306/log
/home/mysql/3306/tmp

3、将下载的mysql-5.7.21-linux-glibc2.12-x86_64.tar安装包上传至服务器/usr/local目录下;

# 解压缩
tar -xvf mysql-5.7.21-linux-glibc2.12-x86_64.tar

# 会得到一个mysql-5.7.21-linux-glibc2.12-x86_64.tar.gz文件,再解压缩
tar -zxvf mysql-5.7.21-linux-glibc2.12-x86_64.tar.gz

# 建立软链接,便于以后版本升级
ln -s mysql-5.7.21-linux-glibc2.12-x86_64 mysql

# 修改mysql文件夹下所有文件的用户和用户组
chown -R mysql:mysql mysql/

4、创建配置文件

# 创建配置文件
cd /etc

# 在my.cnf文件中添加对应的配置项,文章末尾会提供一个默认的my.cnf配置
vi my.cnf

5、安装数据库

# 初始化数据库,并指定启动mysql的用户
./mysqld --initialize --user=mysql

安装完成后,在my.cnf中配置的datadir目录下生成一个error.log文件,里面记录了root用户的随机密码。

6、设置开机自启动服务

# 复制启动脚本到资源目录
cp ./support-files/mysql.server /etc/rc.d/init.d/mysqld

# 增加mysqld服务控制脚本执行权限
chmod +x /etc/rc.d/init.d/mysqld

# 将mysqld服务加入到系统服务
chkconfig --add mysqld

# 检查mysqld服务是否已经生效
chkconfig --list mysqld

# 切换至mysql用户,启动mysql
service mysqld start

7、配置环境变量

为了更好的操作mysql,配置环境变量。

# 切换至mysql用户
su - mysql

# 修改配置文件,增加export PATH=$PATH:/usr/local/mysql/bin
vi .bash_profile

# 立即生效
source .bash_profile

8、登陆,修改密码

# 登陆mysql
mysql -uroot -p

# 修改root用户密码
set password for root@localhost=password("123456");

总结

好了,到此关于CentOS 7离线安装MySQL5.7的总结完毕。如果大家有任何疑问,或者在安装过程中卡住了,都可以在下方留言。希望我的这篇文章对大家有帮助。

附录

下述的my.cnf配置仅供参考,如果你有更好的建议,请告诉我。

[client]                                        # 客户端设置,即客户端默认的连接参数
port = 3306                                    # 默认连接端口
socket = /home/mysql/3306/tmp/mysql.sock                        # 用于本地连接的socket套接字,mysqld守护进程生成了这个文件

[mysqld]                                        # 服务端基本设置
# 基础设置
server-id = 1                                  # Mysql服务的唯一编号 每个mysql服务Id需唯一
port = 3306                                    # MySQL监听端口
basedir = /usr/local/mysql                      # MySQL安装根目录
datadir = /home/mysql/3306/data                      # MySQL数据文件所在位置
tmpdir  = /home/mysql/3306/tmp                                  # 临时目录,比如load data infile会用到
socket = /home/mysql/3306/tmp/mysql.sock        # 为MySQL客户端程序和服务器之间的本地通讯指定一个套接字文件
pid-file = /home/mysql/3306/log/mysql.pid      # pid文件所在目录
skip_name_resolve = 1                          # 只能用IP地址检查客户端的登录,不用主机名
character-set-server = utf8mb4                  # 数据库默认字符集,主流字符集支持一些特殊表情符号(特殊表情符占用4个字节)
transaction_isolation = READ-COMMITTED          # 事务隔离级别,默认为可重复读,MySQL默认可重复读级别
collation-server = utf8mb4_general_ci          # 数据库字符集对应一些排序等规则,注意要和character-set-server对应
init_connect='SET NAMES utf8mb4'                # 设置client连接mysql时的字符集,防止乱码
lower_case_table_names = 1                      # 是否对sql语句大小写敏感,1表示不敏感
max_connections = 400                          # 最大连接数
max_connect_errors = 1000                      # 最大错误连接数
explicit_defaults_for_timestamp = true          # TIMESTAMP如果没有显示声明NOT NULL,允许NULL值
max_allowed_packet = 128M                      # SQL数据包发送的大小,如果有BLOB对象建议修改成1G
interactive_timeout = 1800                      # MySQL连接闲置超过一定时间后(单位:秒)将会被强行关闭
wait_timeout = 1800                            # MySQL默认的wait_timeout值为8个小时, interactive_timeout参数需要同时配置才能生效
tmp_table_size = 16M                            # 内部内存临时表的最大值 ,设置成128M;比如大数据量的group by ,order by时可能用到临时表;超过了这个值将写入磁盘,系统IO压力增大
max_heap_table_size = 128M                      # 定义了用户可以创建的内存表(memory table)的大小
query_cache_size = 0                            # 禁用mysql的缓存查询结果集功能;后期根据业务情况测试决定是否开启;大部分情况下关闭下面两项
query_cache_type = 0

# 用户进程分配到的内存设置,每个session将会分配参数设置的内存大小
read_buffer_size = 2M                          # MySQL读入缓冲区大小。对表进行顺序扫描的请求将分配一个读入缓冲区,MySQL会为它分配一段内存缓冲区。
read_rnd_buffer_size = 8M                      # MySQL的随机读缓冲区大小
sort_buffer_size = 8M                          # MySQL执行排序使用的缓冲大小
binlog_cache_size = 1M                          # 一个事务,在没有提交的时候,产生的日志,记录到Cache中;等到事务提交需要提交的时候,则把日志持久化到磁盘。默认binlog_cache_size大小32K

back_log = 130                                  # 在MySQL暂时停止响应新请求之前的短时间内多少个请求可以被存在堆栈中;官方建议back_log = 50 + (max_connections / 5),封顶数为900

# 日志设置
log_error = /home/mysql/3306/log/error.log                          # 数据库错误日志文件
slow_query_log = 1                              # 慢查询sql日志设置
long_query_time = 1                            # 慢查询时间;超过1秒则为慢查询
slow_query_log_file = /home/mysql/3306/log/slow.log                  # 慢查询日志文件
log_queries_not_using_indexes = 1              # 检查未使用到索引的sql
log_throttle_queries_not_using_indexes = 5      # 用来表示每分钟允许记录到slow log的且未使用索引的SQL语句次数。该值默认为0,表示没有限制
min_examined_row_limit = 100                    # 检索的行数必须达到此值才可被记为慢查询,查询检查返回少于该参数指定行的SQL不被记录到慢查询日志
expire_logs_days = 5                            # MySQL binlog日志文件保存的过期时间,过期后自动删除

# 主从复制设置
log-bin = mysql-bin                            # 开启mysql binlog功能
binlog_format = ROW                            # binlog记录内容的方式,记录被操作的每一行
binlog_row_image = minimal                      # 对于binlog_format = ROW模式时,减少记录日志的内容,只记录受影响的列

# Innodb设置
innodb_open_files = 500                        # 限制Innodb能打开的表的数据,如果库里的表特别多的情况,请增加这个。这个值默认是300
innodb_buffer_pool_size = 64M                  # InnoDB使用一个缓冲池来保存索引和原始数据,一般设置物理存储的60% ~ 70%;这里你设置越大,你在存取表里面数据时所需要的磁盘I/O越少
innodb_log_buffer_size = 2M                    # 此参数确定写日志文件所用的内存大小,以M为单位。缓冲区更大能提高性能,但意外的故障将会丢失数据。MySQL开发人员建议设置为1-8M之间
innodb_flush_method = O_DIRECT                  # O_DIRECT减少操作系统级别VFS的缓存和Innodb本身的buffer缓存之间的冲突
innodb_write_io_threads = 4                    # CPU多核处理能力设置,根据读,写比例进行调整
innodb_read_io_threads = 4
innodb_lock_wait_timeout = 120                  # InnoDB事务在被回滚之前可以等待一个锁定的超时秒数。InnoDB在它自己的锁定表中自动检测事务死锁并且回滚事务。InnoDB用LOCK TABLES语句注意到锁定设置。默认值是50秒
innodb_log_file_size = 32M                      # 此参数确定数据日志文件的大小,更大的设置可以提高性能,但也会增加恢复故障数据库所需的时间

安装错误说明

1、在安装过程中出现./mysqld: error while loading shared libraries: libaio.so.1: cannot open shared object file: No such file or directory错误时,请切回root用户,执行以下命令即可:

yum install libaio

Django中Mysql Redis连接池

MySQL 连接

对Django服务进行压测,DB报错数据库连接数过多,如果设置MySQL的最大连接数为1000,很快连接数就会达到上限,调整到2000,也很快连接数达到上限。

xuetangx DB最大连接数2048

mysql> show variables like 'max_connections';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 2048   |
+-----------------+-------+
1 row in set (0.00 sec)

通过Django文档可以发现Django其实提供了一个连接池的另一种时间方式

Django的默认数据库连接

Django程序接受到请求之后,在第一次访问数据库的时候会创建一个数据库连接,直到请求结束,关闭数据库连接。(Django opens a connection to the database when it first makes a database query. It keeps this connection open and reuses it in subsequent requests.)下次请求也是如此。因此,这种情况下,随着访问的并发数越来越高,就会产生大量的数据库连接。也就是我们在压测时出现的情况。

使用CONN_MAX_AGE减少数据库请求(连接池)

每次请求都会创建新的数据库连接,这对于高并发的应用来说是不能接受的。因此在Django1.6时,提供了持久的数据库连接,通过DATABASE配置CONN_MAX_AGE来控制每个连接的最大存活时间。

The default value is 0, preserving the historical behavior of closing the database connection at the end of each request. To enable persistent connections, set CONN_MAX_AGE to a positive number of seconds. For unlimited persistent connections, set it to None.

这个参数的原理就是在每次创建完数据库连接之后,把连接放到一个Theard.local的实例中。在request请求开始结束的时候,打算关闭连接时会判断是否超过CONN_MAX_AGE设置这个有效期。超过则关闭。每次进行数据库请求的时候其实只是判断local中有没有已存在的连接,有则复用。

基于上述原因,Django中对于CONN_MAX_AGE的使用是有些限制的,使用不当,会适得其反。因为保存的连接是基于线程局部变量的,因此如果你部署方式采用多线程,必须要注意保证你的最大线程数不会多余数据库能支持的最大连接数(一个线程一个连接)。另外,如果使用开发模式运行程序(直接runserver的方式),建议不要设置CONN_MAX_AGE,因为这种情况下,每次请求都会创建一个Thread。同时如果你设置了CONN_MAX_AGE,将会导致你创建大量的不可复用的持久的连接。

CONN_MAX_AGE设置

CONN_MAX_AGE的时间怎么设置主要取决于数据库对空闲连接的管理,比如你的MySQL设置了空闲1分钟就关闭连接,那你的CONN_MAX_AGE就不能大于一分钟,不过DBA已经习惯了程序中的线程池的概念,会在数据库中设置一个较大的值。

Redis 连接

在做一个直播活动时,所有评论数据保存Redis,收到Redis服务报错:max number of clients reached

redis 127.0.0.1:6379> CONFIG GET maxclients
1) "maxclients"
2) "200"

发现设置的这个最大连接数太小了,因为每次request都会创建redis连接,几百个人同时使用就达到最大上线了。

Django-redis可以设置Redis连接池,并设置最大连接数,这样就能保证连接的复用和连接数的控制。

the default connection pool is simple. You can only customize the maximum number of connections in the pool, by setting CONNECTION_POOL_KWARGS in the CACHES setting。

CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        ...
        "OPTIONS": {
            "CONNECTION_POOL_KWARGS": {"max_connections": 100}
        }
    }
}

END

利用 xtrabackup 工具实现增量备份 mysql(附脚本)

1、安装 percona 源

yum install http://www.percona.com/downloads/percona-release/redhat/0.1-4/percona-release-0.1-4.noarch.rpm

2、安装 xtrabackup

yum install percona-xtrabackup-24 -y            #2.4 之前版本可能不支持 mysql5.7

3、创建备份文件夹

mkdir /data/backup/mysqlbak

4、编写备份脚本

vim mysqldump.sh
#!/bin/sh
base_dir="/data/backup/mysqlbak/"
log_file="/tmp/Backup.log"
increse_dir=
grep "Backup created in directory" $log_file | awk -F "'" {'print$2'}

dir_name=
grep "Backup created in directory" $log_file | awk -F "'" {'print$2'} | awk -F "/" {'print$5'}

increse_dir_path=
grep "Backup created in directory" $log_file | awk -F "'" {'print$2'} | awk -F '/' '{for(i=1;i<=4;i++)printf $i"/"; printf "n"}'

fullbackup_exist=
ls $base_dir | wc -l

if [$fullbackup_exist = 0 -a "$1" != "full_backup"];then
echo "you must make the fullbackup first! please usage: $0 full_backup"
exit 88;
fi
full_backup() {
innobackupex --user=root --password=password $base_dir
}
increase_backup() {
innobackupex --user=root --password=password --incremental-basedir=$increse_dir --incremental $base_dir
cd $increse_dir_path
tar -zcvf ${dir_name}.tar.gz $dir_name
mv $increse_dir /tmp/
}
case "$1" in
full_backup)
full_backup > $log_file 2>& 1
;;
increase_backup)
increase_backup > $log_file 2>& 1
;;
)
echo "usage: $0 {full_backup|increase_backup}"
;;
esac

5、执行第一次全量备份

./mysqldump.sh full_backup

6、创建计划任务,进行日常增量备份

crontab -e


01 00 sh /root/mysqldump.sh increase_backup

7、制作还原脚本

#!/bin/sh
base_dir="/data/backup/"
tar_files=
find $base_dir -name "*.tar.gz"

recover_mysql() {
for tar_file in $tar_files
do
cd $base_dir
tar -zxvf $tar_file
rm -f $tar_file
done
full_dir=
ls -lt $base_dir | tail -1 | awk {'print$9'}

increase_dirs=
ls -lrt $base_dir | grep "root" | awk {'print$9'}

innobackupex --apply-log --redo-only ${base_dir}${full_dir}
for increase_dir in $increase_dirs
do
if ["$increase_dir" != "$full_dir"];then
innobackupex --apply-log --redo-only --incremental ${base_dir}${full_dir} --incremental-dir=${base_dir}${increase_dir}
fi
done
innobackupex --copy-back ${base_dir}${full_dir}
}
recover_mysql > /tmp/recover_mysql.log 2>& 1

Xtrabackup实现Mysql的InnoDB引擎热备份

前面Zabbix使用的数据库是mysql,数据库备份不用多说,必须滴,由于使用的是innodb引擎,既然做,那就使用第三方强大的Xtrabackup工具来热备吧,Xtrabackup的说明,参见https://my.oschina.net/u/1171265/blog/200437

数据库备份

简单粗暴,下面给出mysql备份脚本:

#!/bin/bash
#mysql热备脚本,Version:1.0
#Author:jzd
#备份策略:每周一进行完整备份,以后每一天在前一天的基础上进行增量备份
#
#备份目录
back_dir="/back"

#备份数据库信息
host="127.0.0.1"
dbuser="dbuser"
dbpasswd="dbpasswd"

#日志文件
back_log="${back_dir}/mysql_back.log"

#week day
week_day=`date +%w`
#yesterday
yesterday=`date +%F -d "1 days ago"`

#日志记录函数
function log(){

  echo "`date` $1" | tee -a ${back_log}

}

#判断当前日期,是周一进行全备份,其他时间进行增量备份
if [ ${week_day} -eq 1 ]; then
#完整备份
  log "周${week_day}开始完全备份..."
  innobackupex --host=${host} --user=${dbuser} --password=${dbpasswd} ${back_dir} &>> ${back_log}
  if [ $? -eq 0 ]; then
    log "完全备份完毕."
    else
       log "完全备份出错,请检查."
       exit 1
  fi
  else
    let dir_num=`find ${back_dir} -type d -name "${yesterday}*" | wc -l`
    if [ ${dir_num} -ne 1 ]; then
      log "昨天增量目录未找到或昨天备份目录大于等于2个,请确认后再次备份."
      exit 1
    fi
    incremental_dir=`find ${back_dir} -type d -name "${yesterday}*"`
    log "周${week_day}开始增量备份..."
    #增量备份
    innobackupex --host=${host} --user=${dbuser} --password=${dbpasswd} --incremental ${back_dir} --incremental-basedir=${incremental_dir} &>> ${back_log}
    if [ $? -eq 0 ]; then
      log "增量备份成功."
      else
        log "备份失败,请检查日志..."
        exit 1
    fi
fi

exit $?

需修改的地方,也可以写成配置文件source进去,完全可以用在生产环境。

#备份目录

back_dir="/back"



#备份数据库信息

host="127.0.0.1"

dbuser="dbuser"

dbpasswd="dbpasswd"



#日志文件

back_log="${back_dir}/mysql_back.log"

数据恢复

话说备份容易,恢复不易啊,下面也给出恢复脚本,配合上面备份脚本使用,但是恢复完毕后,需手动恢复当日的二进制文件,恢复方法见开篇Xtrabackup介绍文章;

恢复脚本的星期和日期对应的转换,搞得头都大了,缠了两天,判断太多,导致太乱,于是多使用函数,发现自己对函数的使用加强了(哈哈,相对于以前,感觉自己有面向对象的思想了,但这是shell)

#!/bin/bash
#mysql数据恢复脚本
#Author:jzd
#Version:V1.0

#back dir
back_dir='/back'
#full back day
full_back_day=1
#today
today=`date +%F`
#week day
week_day=`date +%w`
#log file
recovery_log="${back_dir}/mysql_recovery.log"

#log
function log(){
  echo "`date` $1" | tee -a ${recovery_log}
}

#find back dir
function finddir(){
  if [ `find $back_dir -type d -name "$1*" | wc -l` -ne 1 ]; then
    log "发现备份目录$1为0个或多于一个,请检查..."
    exit 1
    else
      log "发现备份目录`find $back_dir -type d -name "$1*"`"
      find_dir="`find $back_dir -type d -name "$1*"`"
  fi
}

#all recovery
function allredo(){
 log "开始完整备份恢复准备..."
 innobackupex --apply-log --redo-only $1 &>> ${recovery_log}
 if [ $? -ne 0 ]; then
    log "完整恢复准备出错,请检查..."
    exit 1
 fi
 log "完整备份恢复准备完成"
}

#incremental recovery
function incredo(){
 log "开始增量数据恢复准备..."
 innobackupex --apply-log --redo-only $1 --incremental-dir=$2 &>> ${recovery_log}
 if [ $? -ne 0 ]; then
    log "增量数据恢复准备出错,请检查..."
    exit 1
  fi
  log "增量数据$2恢复准备完成"
}
#real recovery
function recovery(){
  log "备份数据准备完成,开始恢复数据..."
  innobackupex --copy-back $1 &>> ${recovery_log}
  if [ $? -ne 0 ]; then
    log "完整恢复准备出错,请检查..."
    exit 1
  fi
  log "恢复数据完成,请检查."
  log "请手动恢复二进制文件数据."
}

#判断今日是否是周一

if [ $week_day -eq ${full_back_day} ]; then
  finddir ${today}
  all_dir="${find_dir}"
  if [ ! -z "${all_dir}" ]; then
    allredo $all_dir
    recovery $all_dir
    else
      log "未发现今日备份,恢复上周数据."
      for i in "7 6 5 4 3 2 1"
        do
          back_date=`date +%F -d "${i} days ago"`
          if [ $i -eq 7 ]; then
            finddir ${back_date}
            all_dir="${find_dir}"
            allredo ${all_dir}
            else
              finddir ${back_date}
              dir_back=${find_dir}
              incredo ${all_dir} ${dir_back}
          fi
      done
      recovery ${all_dir}
  fi
  else
    back_date=`date +%F -d "$((${week_day}-${full_back_day})) days ago"`
    finddir ${back_date}
    all_dir="${find_dir}"
    allredo ${all_dir}
    let flag=$((${week_day}-1-${full_back_day}))
    while [ ${flag} -ge 0 ]
      do
        incr_date=`date +%F -d "${flag} days ago"`
        finddir ${incr_date}
        incr_dir="${find_dir}"
        incredo ${all_dir} ${incr_dir}
        let flag=`expr $flag - 1`
    done
    recovery ${all_dir}
fi

exit 0

批量 kill mysql 中运行时间长的sql

以下内容来自mysql手册:

13.5.5.3. KILL语法
KILL [CONNECTION | QUERY] thread_id
每个与mysqld的连接都在一个独立的线程里运行,您可以使用SHOW PROCESSLIST语句查看哪些线程正在运行,并使用KILL thread_id语句终止一个线程。

KILL允许自选的CONNECTION或QUERY修改符:

  • KILL CONNECTION与不含修改符的KILL一样:它会终止与给定的thread_id有关的连接。

  • KILL QUERY会终止连接当前正在执行的语句,但是会保持连接的原状。
    如果您拥有PROCESS权限,则您可以查看所有线程。如果您拥有SUPER权限,您可以终止所有线程和语句。否则,您只能查看和终止您自己的线程和语句。
    您也可以使用mysqladmin processlist和mysqladmin kill命令来检查和终止线程。
    注释:您不能同时使用KILL和Embedded MySQL Server库,因为内植的服务器只运行主机应用程序的线程。它不能创建任何自身的连接线程。
    当您进行一个KILL时,对线程设置一个特有的终止标记。在多数情况下,线程终止可能要花一些时间,这是因为终止标记只会在在特定的间隔被检查:

  • 在SELECT, ORDER BY和GROUP BY循环中,在读取一组行后检查标记。如果设置了终止标记,则该语句被放弃。

  • 在ALTER TABLE过程中,在每组行从原来的表中被读取前,检查终止标记。如果设置了终止标记,则语句被放弃,临时表被删除。

  • 在UPDATE或DELETE运行期间,在每个组读取之后以及每个已更行或已删除的行之后,检查终止标记。如果终止标记被设置,则该语句被放弃。注意,如果您正在使用事务,则变更不会被 回滚。

  • GET_LOCK()会放弃和返回NULL。

  • INSERT DELAYED线程会快速地刷新(插入)它在存储器中的所有的行,然后终止。

  • 如果线程在表锁定管理程序中(状态:锁定),则表锁定被快速地放弃。

  • 如果在写入调用中,线程正在等待空闲的磁盘空间,则写入被放弃,并伴随”disk full”错误消息。

  • 警告:对MyISAM表终止一个REPAIR TABLE或OPTIMIZE TABLE操作会导致出现一个被损坏的没有用的表。对这样的表的任何读取或写入都会失败,直到您再次优化或修复它(不中断)。

1、通过information_schema.processlist表中的连接信息生成需要处理掉的MySQL连接的语句临时文件,然后执行临时文件中生成的指令

mysql> select concat('KILL ',id,';') from information_schema.processlist where user='root';
+------------------------+| concat('KILL ',id,';')
+------------------------+| KILL 3101;
| KILL 2946;
+------------------------+2 rows in set (0.00 sec)
mysql>select concat('KILL ',id,';') from information_schema.processlist where user='root' into outfile '/tmp/a.txt';
Query OK, 2 rows affected (0.00 sec)
mysql>source /tmp/a.txt;
Query OK, 0 rows affected (0.00 sec)

2、
  
杀掉当前所有的MySQL连接

mysqladmin -uroot -p processlist|awk -F "|" '{print $2}'|xargs -n 1 mysqladmin -uroot -p kill

杀掉指定用户运行的连接,这里为Mike

mysqladmin -uroot -p processlist|awk -F "|" '{if($3 == "Mike")print $2}'|xargs -n 1 mysqladmin -uroot -p kill

 
3、通过SHEL脚本实现

#杀掉锁定的MySQL连接

for id in mysqladmin processlist|grep -i locked|awk '{print $1}'
do
mysqladmin kill ${id}
done

4、通过Maatkit工具集中提供的mk-kill命令进行

#杀掉超过60秒的sql
mk-kill -busy-time 60 -kill
#如果你想先不杀,先看看有哪些sql运行超过60秒
mk-kill -busy-time 60 -print
#如果你想杀掉,同时输出杀掉了哪些进程
mk-kill -busy-time 60 -print –kill

记一次MySQL删库的数据恢复

未分类

昨天因为不可描述的原因,数据库直接被 drop database删除。在第一时间停止数据库服务和Web服务,备份MySQL数据目录下的所有文件之后,开始走上数据恢复之路。

第一次干这种事,各种不得法。因为我们既没有备份,也没有开启binlog,连innodb_file_per_tabe_也没有。一番折腾后向万能的朋友圈求救,朋友给了两个链接,最终救了一下命。以下先按编号记下 URL,后续引用之。

  • http://dba.stackexchange.com/questions/23251/is-there-a-way-to-recover-a-dropped-mysql-database

  • https://github.com/chhabhaiya/undrop-for-innodb

  • Recover InnoDB dictionary

其中URL1和URL3的内容基本上相同,是整个恢复工作的蓝本。URL2是URL1中引用的一个twindb团队开发的一个工具,现在他们官方已经删除了,URL2是该工具的一个fork,或者说是备份。

恢复过程以URL3为蓝本,先去URL2 git clone一份代码下来,然后按其说明编译,我们在ubuntu server 14.04 64bit 版本的情况下,成功编译完成,编译中需要安装各种依赖不表。

然后用 stream_parser 处理ibdata1 文件,接下来恢复SYS_TABLES 和 SYS_INDEXES,建议此过程中严格遵守参考资料,比如把这些资料恢复到dumps/default 目录中,而不是随意起名,以免横生枝节。

这里还有一个坑,就是URL3里用的c_parser -4f 是会出错的,而URL1里用的是c_parser -4Df ,就不会出错,所以大家做的时候一定要把这个D加上。感叹一下,如果不细心的人真的没法做这事!摔!

接下来按URL3的说明把数据字典导入 MySQL。这一步可以不做,按URL1里高票答案的方法来获取索引ID,比较麻烦。URL3的方法应该会出这样的错:

ERROR 1148 (42000) at line 2: The used command is not allowed with this MySQL version

这是因为MySQL默认不启用LOAD DATA LOCAL INFILE 导致的,需要给mysql 命令加上–local-infile 参数。这是参考文献的一个坑。趟过这个坑以后,我可以告诉你一个捷径,就是URL2里的代码里其实有一个文件recover_dictionary.sh ,它干的就是恢复数据字典的事情,所以你只要把这个shell脚本里的mysql 都替换成mysql –local-infile -uroot -pxxxxx 就行,其中xxxx是指你的root账号密码,不过前提是你很听话的用了前面说的dumps/default 目录,不然就再多一轮替换。

接下来的内容,大部分是参考文献里没有的了。

恢复数据字典后,就可以用URL3介绍的方式找出你对应的所有数据库和表的索引ID了。这个时候就遇到为 c_parser 提供数据表建表语句的问题了,这个问题难就难在先有鸡还是先有蛋,一般来说,数据库都被删掉了,哪还有办法去搞出CREATE TABLE 这种建表语句呢?好就好在我们用的是django,它对数据迁移的完美支持救了我一命。在这里讲一句题外话,使用类似django/ror/laravel等有数据迁移框架在此就看出多么重要了。只要在根据原有项目做一次migrate,数据表就建好了,这时候只要用mysqldump导出对应表的建表语句即可:

mysqldump --add-drop-table=0 --add-lock=0 -d DBNAME TABLENAME -uroot -p > xxxx.sql

因为c_parser 非常弱,只处理CREATE TABLE 语句,多一点干扰都不行,所以上面的参数都是必要的。

接下来就是参考URL1把某一个表的数据恢复出来,这里有一个坑,URL1里说把数据恢复到dump.tsv里,其实是不对的,这里应该用dumps/default/TABLENAME,别问我为什么知道,我不会告诉你我找这个原因找瞎了眼,好吧,跟你说,因为生成的load_cmd.sql 里直接引用 dumps/default/TABLENAME,无法设置。所以最后我们这里可用的命令是:

./c_parser -6f pages-ibdata1/FIL_PAGE_INDEX/0000000000002410.page -t xxxx.sql > dumps/default/TABLENAME 2> load_cmd.sql

把数据恢复出来以后,执行

mysql --local-infile -uroot -p DBNAME < load_cmd.sql

就可以把数据导进去了,记得在数据库里查询一下有没有成功,如果没有数据恢复出来,应该是其中的某些环节出了问题。

这样就成功恢复了某一个表,只要按这里最后三条命令(导出建表语句、恢复数据、导入数据)重复地做下去,你就能把基本上所有的数据都恢复出来了。之所以说是“基本上”,原因是我系统中使用了utf8mb4 编码(为了兼容emoji),结果是如果数据中有emoji的内容就会在导入数据的环节出错,暂时没有找到办法恢复这个数据。

以上就是整个恢复过程,枯燥、压力山大,这种事情我不想再经历了。如果你也遇到这样的数据恢复需求,希望这篇笔记能够帮到你。但也不要指望我能帮到你更多了,我的经验也仅止于此,天大地大,就此别过,不要找我。谢谢!

记录一次失败的 Upgrade MySQL to MariaDB 经历

摘要

每次“折腾”其实都是有不少收获的,比如这次的折腾虽然以失败告终,但是至少也算是体验了一番Upgrade MySQL to MariaDB的过程,对MariaDB也算是有了一个初步的认识了。有条件还是要尽早将MySQL替换为MariaDB最好,至于说数据的导入、导出完全不用担心“转换”的,它们之间的兼容性那真的是“刚刚的”,毕竟是出自同一个创始人之手的开源数据库嘛!

其实这次升级 MySQL 是个很偶然的决定,主要就是看到了 wooCommerce 插件升级的时候联想到了最近总是发现在使用了 wooCommerce 插件后数据库总有不正常错误出现,从 wooCommerce 插件的支持情况来看可能是因为 MySQL 版本低于 5.6 造成的,所以就想升级 MySQL 的打算了,受制于服务器只有 1G 内存一直没有实现,还以为 MariaDB 对内存没有这个要求呢!

未分类

想到就要行动起来,因为使用的是军哥的 LNMP1.5 测试版,在 upgrade.sh 脚本里就自带了 Upgrade MySQL to MariaDB 的选项,就直接用脚本升级了,数据库太大了,编译安装耗时近一个多小时。结果是彻底失败,MariaDB 里竟然没有任何数据表,PhpMyAdmin 里也是彻底乱了套,界面错位,无法正常操作。折腾了两个多小时才发现是 ngx_lua_waf 拦截造成的,无奈暂时关闭 WAF。这时候站点已经都无法访问了。没有办法只能请出阿里云的镜像回滚恢复了。

恢复正常后还是不甘心呀!所以继续努力继续折腾,这次提前把数据库都导出来以备不时之需,关闭 WAF 防火墙重新来过,近一个小时的等待后终于成功了,这次很完美,数据表依然是丢失的,还好编译前有备份,立马导入数据,又发现 MariaDB 的 root 密码竟然无效了,只能重置数据库密码了。终于恢复网站访问了!么么哒!!!

未分类

等等,有点儿不对劲儿,服务器控制台终端好卡的感觉,一看负载,我去一直在“飙升”直至网站打开出现 503 错误,负载还在持续飙升一路到 50 多了!我去,这也太猛了吧!难道是因为 MariaDB 没有优化所致?于是又对 MariaDB 的配置文件进行了一番研究调整了一些参数优化了一番,重新载入 MariaDB 后,CPU 的负载依然是 90%以上,这时候突然想起来 MySQL 5.6 以后的版本对服务器内存有要求至少是 2G 以上,难道 MariaDB 也有这个要求,MariaDB 的版本我选的是 10.2.12 版,百度、谷姐一番后基本上可以确定就是服务器物理内存太小造成的了!哎,无语了,看来升级到 MariaDB 也是没有办法的,只能是镜像回滚恢复了。

至此,这次 Upgrade MySQL to MariaDB 的折腾还是以失败而告终了,服务器配置太低是主要原因,虽然 MariaDB 那么的诱人,但至少目前来看是无福消受了!我说为啥阿里云 ECS 1G1 核的卖的这么便宜,原来又是“套路”呀!唉,真的是彻底的服了!

不过,每次“折腾”其实都是有不少收获的,比如这次的折腾虽然以失败告终,但是至少也算是体验了一番 Upgrade MySQL to MariaDB 的过程,对 MariaDB 也算是有了一个初步的认识了。有条件还是要尽早将 MySQL 替换为 MariaDB 最好,至于说数据的导入、导出完全不用担心“转换”的,它们之间的兼容性那真的是“刚刚的”,毕竟是出自同一个创始人之手的开源数据库嘛!

MariaDB/MySQL配置文件my.cnf解读

MariaDB/MySQL的默认设置性能非常差,仅仅起一个功能测试的作用,不能用在生产环境中,因此要对一些参数进行调整优化。当然,对配置文件各参数的调整需要根据实际环境,不同时期不同数量级的数据进行性能优化。

未分类

MySQL/MariaDB 配置文件位于 /etc/my.cnf。 每次更改此文件后你需要重启 MySQL 服务,以使更改生效。本文的参数配置基于MariaDB 10.2,硬件内存4G。文中一些选项值的设置只是推荐值,不要盲目的接受这些建议。每个 MySQL 设置都是不同的,在进行任何更改之前需要慎重考虑。

基本结构

[client]
port        = 3306 #客户端默认连接端口
socket      = /tmp/mysql.sock  #用于本地连接的socket套接字

[mysqld]  # 服务端基本配置
port        = 3306 # mysql监听端口
socket      = /tmp/mysql.sock #为MySQL客户端程序和服务器之间的本地通讯指定一个套接字文件
user    = mariadb # mysql启动用户
basedir = /usr/local/mariadb # 安装目录
datadir = /data/mysql # 数据库数据文件存放目录
log_error = /data/mysql/mariadb.err #记录错误日志文件
pid-file = /data/mysql/mariadb.pid  #pid所在的目录
skip-external-locking  #不使用系统锁定,要使用myisamchk,必须关闭服务器
...

my.cnf配置文件以方括号如[client]区分模块作用域,其中[client]表示客户端配置,[mysqld]是服务端配置。以上几个选项是最基础的,每个选项有简单说明,其中有关路径的配置是基于本站文章:CentOS7下源码编译安装MariaDB 10.2和Linux下使用二进制格式安装MariaDB的安装路径来配置的,所以在配置前可以先按照两文先安装好MairaDB。

选项配置及说明

key_buffer_size = 32M 这个参数用来缓存MyISAM存储引擎的索引参数。MySQL5.5默认为InnoDB存储引擎,所以这个参数可以设置小点,64MB即可。

max_allowed_packet = 1M 允许最大接收数据包的大小,防止服务器发送过大的数据包。可以设置为16MB或者更大,但设置的太大也可能有危险。

table_open_cache = 128 #MySQL每打开一个表,都会读入一些数据到table_open_cache缓存中,当MySQL在这个缓存中找不到相应信息时,才会去磁盘上读取。默认值64,假定系统有200个并发连接,则需将此参数设置为200*N(N为每个连接所需的文件描述符数目);当把table_open_cache设置为很大时,如果系统处理不了那么多文件描述符,那么就会出现客户端失效,连接不上。

sort_buffer_size = 768K 在表进行order by和group by排序操作时,由于排序的字段没有索引,会出现Using filesort,为了提高性能,可用此参数增加每个线程分配的缓冲区大小。默认为256KB,这个参数不要设置过大,一般在128~256KB即可。另外,一般出现Using filesort的时候,要通过增加索引来解决。

net_buffer_length = 8K 包消息缓冲区初始化为net_buffer_length字节,但需要时可以增长到max_allowed_packet字节。

read_buffer_size = 768K 该参数用于表的顺序扫描,表示每个线程分配的缓冲区大小。比如在进行全表扫描时,MySQL会按照数据的存储顺序依次读取数据块,每次读取的数据块首先会暂存在read_buffer_size中,当buffer空间被写满或者全部数据读取结束后,再将buffer中的数据返回给上层调用者,以提高效率。默认为128K,这个参数不要设置过大,一般在128~256之间。

read_rnd_buffer_size = 512K 该参数用于表的随机读取,表示每个线程分配的缓冲区大小。比如,按照一个非索引字段做order by排序操作时,就会利用这个缓冲区来暂存读取的数据。默认为256KB,这个参数不要设置过大,一般在128~512KB。

myisam_sort_buffer_size = 8M 当对MyISAM表执行repair table或创建索引时,用以缓存排序索引;设置太小时可能会遇到” myisam_sort_buffer_size is too small”

thread_cache_size = 16 线程池,线程缓存。用来缓存空闲的线程,以至于不被销毁,如果线程缓存在的空闲线程,需要重新建立新连接,则会优先调用线程池中的缓存,很快就能响应连接请求。每建立一个连接,都需要一个线程与之匹配。

query_cache_size = 16M 缓存select语句和结果集大小的参数。查询缓存会存储一个select查询的文本与被传送到客户端的相应结果。如果之后接收到一个相同的查询,服务器会从查询缓存中检索结果,而不是再次分析和执行这个同样的查询。如果你的环境中写操作很少,读操作频繁,那么打开query_cache_type=1,会对性能有明显提升。如果写操作频繁,则应该关闭它(query_cache_type=0)。

tmp_table_size = 32M 临时HEAP数据表的最大长度(默认设置是32M); 超过这个长度的临时数据表将被转换为MyISAM数据表并存入一个临时文件。

explicit_defaults_for_timestamp = true 是否显示默认时间戳

#skip-networking

max_connections = 500 该参数用来设置最大连接数,告诉你当前你的服务器允许多少并发连接。默认为100,一般设置为512-1000即可。请记住,太多的连接会导致内存的使用量过高并且会锁住你的 MySQL 服务器。一般小网站需要 100-200 的连接数,而较大可能需要 500-800 甚至更多。这里的值很大程度上取决于你 MySQL/MariaDB 的使用情况。

max_connect_errors = 100 如果有时网络抽风,或者应用配置错误,或者其他原因导致客户端短时间内不断的尝试连接,客户端可能会被列入黑名单,然后将无法连接,直到再次刷新主机缓存。这个选项默认值太小了,可以考虑设的足够大(如果你的服务器配置够强大的话)。

open_files_limit = 65535 mysql打开最大文件数

log-bin=mysql-bin 这些路径相对于datadir

binlog_format=mixed 日志格式

server-id = 1 给服务器分配一个独一无二的ID编号; n的取值范围是1~2的32次方启用二进制日志功能。在复制数据同步的时候会用到,Helloweba后面会有文章介绍。

expire_logs_days = 10 启用二进制日志后,保留日志的天数。服务器会自动清理指定天数前的日志文件,如果不设置则会导致服务器空间耗尽。一般设置为7~14天。

default_storage_engine = InnoDB 新数据表的默认存储引擎(默认设置是MyISAM)。这项设置还可以通过–default-table-type选项来设置。

innodb_file_per_table = 1 InnoDB 提供了更灵活的方式,它把每个数据库的信息保存在一个 .ibd 数据文件中。每个 .idb 文件代表它自己的表空间。通过这样的方式可以更快地完成类似 “TRUNCATE” 的数据库操作,当删除或截断一个数据库表时,你也可以回收未使用的空间。这样配置的另一个好处是你可以将某些数据库表放在一个单独的存储设备。这可以大大提升你磁盘的 I/O 负载。

innodb_data_home_dir = /data/mysql InnoDB主目录,所有与InnoDB数据表有关的目录或文件路径都相对于这个路径。在默认的情况下,这个主目录就是MySQL的数据目录。

innodb_data_file_path = ibdata1:10M:autoextend 用来容纳InnoDB为数据表的表空间: 可能涉及一个以上的文件; 每一个表空间文件的最大长度都必须以字节(B)、兆字节(MB)或千兆字节(GB)为单位给出; 表空间文件的名字必须以分号隔开; 最后一个表空间文件还可以带一个autoextend属性和一个最大长度(max:n)。

innodb_log_group_home_dir = /data/mysql 用来存放InnoDB日志文件的目录路径(如ib_logfile0、ib_logfile1等)。在默认的情况下,InnoDB驱动程序将使用 MySQL数据目录作为自己保存日志文件的位置。

innodb_buffer_pool_size = 128M 这个参数是InnoDB存储引擎的核心参数,默认为128KB,这个参数要设置为物理内存的60%~70%。

innodb_log_file_size = 32M 事务日志文件写操作缓存区的最大长度(默认设置是1MB)。

innodb_log_buffer_size = 8M 事务日志所使用的缓存区。InnoDB在写事务日志的时候,为了提高性能,先将信息写入Innodb Log Buffer中,当满足innodb_flush_log_trx_commit参数所设置的相应条件(或者日志缓冲区写满)时,再将日志写到文件(或者同步到磁盘)中。可以通过innodb_log_buffer_size参数设置其可以使用的最大内存空间。默认是8MB,一般为16~64MB即可。

innodb_flush_log_at_trx_commit = 1 这个选项决定着什么时候把日志信息写入日志文件以及什么时候把这些文件物理地写(术语称为”同步”)到硬盘上。设置值0的意思是每隔一秒写一次日 志并进行 同步,这可以减少硬盘写操作次数,但可能造成数据丢失; 设置值1(设置设置)的意思是在每执行完一条COMMIT命令就写一次日志并进行同步,这可以防止数据丢失,但硬盘写操作可能会很频繁; 设置值2是一般折衷的办法,即每执行完一条COMMIT命令写一次日志,每隔一秒进行一次同步。

innodb_lock_wait_timeout = 50 如果某个事务在等待n秒(s)后还没有获得所需要的资源,就使用ROLLBACK命令放弃这个事务。这项设置对于发现和处理未能被InnoDB数据表驱动 程序识别出来的死锁条件有着重要的意义。这个选项的默认设置是50s。

示例:内存4G的my.cnf配置

[client]
port        = 3306
socket      = /tmp/mysql.sock

[mysqld]
port        = 3306
socket      = /tmp/mysql.sock
user    = mariadb
basedir = /usr/local/mariadb
datadir = /data/mysql
log_error = /data/mysql/mariadb.err
pid-file = /data/mysql/mariadb.pid
skip-external-locking
key_buffer_size = 64M
max_allowed_packet = 1M
table_open_cache = 256
sort_buffer_size = 1M
net_buffer_length = 8K
read_buffer_size = 1M
read_rnd_buffer_size = 512K
myisam_sort_buffer_size = 16M
thread_cache_size = 32
query_cache_size = 32M
tmp_table_size = 64M

explicit_defaults_for_timestamp = true
#skip-networking
max_connections = 500
max_connect_errors = 100
open_files_limit = 65535

log-bin=mysql-bin
binlog_format=mixed
server-id   = 1
expire_logs_days = 10

default_storage_engine = InnoDB
innodb_file_per_table = 1
innodb_data_home_dir = /data/mysql
innodb_data_file_path = ibdata1:10M:autoextend
innodb_log_group_home_dir = /data/mysql
innodb_buffer_pool_size = 256M
innodb_log_file_size = 64M
innodb_log_buffer_size = 8M
innodb_flush_log_at_trx_commit = 1
innodb_lock_wait_timeout = 50

[mysqldump]
quick
max_allowed_packet = 16M

[mysql]
no-auto-rehash

[myisamchk]
key_buffer_size = 64M
sort_buffer_size = 1M
read_buffer = 2M
write_buffer = 2M

[mysqlhotcopy]
interactive-timeout