first commit

This commit is contained in:
iProbe 2022-10-18 16:59:37 +08:00
commit ba848e218d
1001 changed files with 152333 additions and 0 deletions

View file

@ -0,0 +1,5 @@
B树的非叶子节点也存储数据而每层节点有16k大小(mysql),所以存储的数据会比较少
B+树的非叶子节点上不存储数据叶子节点包含所有索引字段每层节点就会多存很多索引8b索引+6b下级分叉的地址
查询innodb的分页大小
show gloobal status like 'innodb_page_size';

View file

@ -0,0 +1,9 @@
mha在所有mysql节点上安装mha node还需要安装mha managermha manager定时监控主节点的状态
从宕机崩溃的master保存二进制日志事件binlog events
识别含有最新更新的slave
应用差异的中继日志relay log到其他slave
应用从master保存的二进制日志事件binlog events
提升一个slave为新master
使用其他的slave连接新的master进行复制。

7
数据库/mysql/MVCC.md Normal file
View file

@ -0,0 +1,7 @@
在Mysql的InnoDB引擎中就是指在已提交读(READ COMMITTD)和可重复读(REPEATABLE READ)这两种隔离级别下的事务对于SELECT操作会访问版本链中的记录的过程。即对数据做了快照。
快照读 (snapshot read):读取的是记录的可见版本 (有可能是历史版本)不用加锁共享读锁s锁也不加所以不会阻塞其他事务的写
当前读 (current read):读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录
InnoDB的MVCC是通过在每行纪录后面保存两个隐藏的列来实现的。这两个列一个保存了行的创建时间一个保存了行的过期时间或删除时间当然存储的并不是实际的时间值而是系统版本号。每开始一个新的事务系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号用来和查询到的每行纪录的版本号进行比较

View file

@ -0,0 +1,866 @@
MySQL 5.6引入的GTID(Global Transaction IDs)使得其复制功能的配置、监控及管理变得更加易于实现,且更加健壮。
要在MySQL 5.6中使用复制功能,其服务配置段[mysqld]中至少应该定义如下选项:
binlog-format二进制日志的格式有row、statement和mixed几种类型
需要注意的是当设置隔离级别为READ-COMMITED必须设置二进制日志格式为ROW现在MySQL官方认为STATEMENT这个已经不再适合继续使用但mixed类型在默认的事务隔离级别下可能会导致主从数据不一致
log-slave-updates、gtid-mode、enforce-gtid-consistency、report-port和report-host用于启动GTID及满足附属的其它需求
master-info-repository和relay-log-info-repository启用此两项可用于实现在崩溃时保证二进制及从服务器安全的功能
sync-master-info启用之可确保无信息丢失
slave-paralles-workers设定从服务器的SQL线程数0表示关闭多线程复制功能
binlog-checksum、master-verify-checksum和slave-sql-verify-checksum启用复制有关的所有校验功能
binlog-rows-query-log-events启用之可用于在二进制日志记录事件相关的信息可降低故障排除的复杂度
log-bin启用二进制日志这是保证复制功能的基本前提
server-id同一个复制拓扑中的所有服务器的id号必须惟一
report-host
The host name or IP address of the slave to be reported to the master during slave registration. This value appears in the output of SHOW SLAVE HOSTS on the master server.
report-port:
The TCP/IP port number for connecting to the slave, to be reported to the master during slave registration.
master-info-repository:
The setting of this variable determines whether the slave logs master status and connection information to a FILE (master.info), or to a TABLE (mysql.slave_master_info)
relay-log-info-repository
This option causes the server to log its relay log info to a file or a table.
log_slave_updates
Whether updates received by a slave server from a master server should be logged to the slave's own binary log. Binary logging must be enabled on the slave for this variable to have any effect.
enforce_gtid_consistency
### 一、简单主从模式配置步骤
#### 1、配置主从节点的服务配置文件
1.1、配置master节点
```
[mysqld]
binlog-format=ROW
log-bin=master-bin
log-slave-updates=true
gtid-mode=on
enforce-gtid-consistency=true
master-info-repository=TABLE
relay-log-info-repository=TABLE
sync-master-info=1
slave-parallel-workers=2
binlog-checksum=CRC32
master-verify-checksum=1
slave-sql-verify-checksum=1
binlog-rows-query-log_events=1
server-id=1
report-port=3306
port=3306
datadir=/mydata/data
socket=/tmp/mysql.sock
report-host=master.magedu.com
```
1.2、配置slave节点
```
[mysqld]
binlog-format=ROW
log-slave-updates=true
gtid-mode=on
enforce-gtid-consistency=true
master-info-repository=TABLE
relay-log-info-repository=TABLE
sync-master-info=1
slave-parallel-workers=2
binlog-checksum=CRC32
master-verify-checksum=1
slave-sql-verify-checksum=1
binlog-rows-query-log_events=1
server-id=11
report-port=3306
port=3306
log-bin=mysql-bin.log
datadir=/mydata/data
socket=/tmp/mysql.sock
report-host=slave.magedu.com
```
#### 2、创建复制用户
```
mysql> GRANT REPLICATION SLAVE ON *.* TO repluser@172.16.100.7 IDENTIFIED BY 'replpass';
```
说明172.16.100.7是从节点服务器;如果想一次性授权更多的节点,可以自行根据需要修改;
#### 3、为备节点提供初始数据集
锁定主表备份主节点上的数据将其还原至从节点如果没有启用GTID在备份时需要在master上使用show master status命令查看二进制日志文件名称及事件位置以便后面启动slave节点时使用。
#### 4、启动从节点的复制线程
如果启用了GTID功能则使用如下命令
```
mysql> CHANGE MASTER TO MASTER_HOST='master.magedu.com', MASTER_USER='repluser', MASTER_PASSWORD='replpass', MASTER_AUTO_POSITION=1;
```
没启用GTID需要使用如下命令
```
slave> CHANGE MASTER TO MASTER_HOST='172.16.100.6',
-> MASTER_USER='repluser',
-> MASTER_PASSWORD='replpass',
-> MASTER_LOG_FILE='master-bin.000003',
-> MASTER_LOG_POS=1174;
```
### 二、半同步复制
#### 1、分别在主从节点上安装相关的插件
```
master> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
slave> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
```
#### 2、启用半同步复制
在master上的配置文件中添加
```
rpl_semi_sync_master_enabled=ON
```
在至少一个slave节点的配置文件中添加
```
rpl_semi_sync_slave_enabled=ON
```
而后重新启动mysql服务即可生效。
或者也可以mysql服务上动态启动其相关功能
```
master> SET GLOBAL rpl_semi_sync_master_enabled = ON;
slave> SET GLOBAL rpl_semi_sync_slave_enabled = ON;
slave> STOP SLAVE IO_THREAD; START SLAVE IO_THREAD;
```
#### 3、确认半同步功能已经启用
```
master> CREATE DATABASE magedudb;
master> SHOW STATUS LIKE 'Rpl_semi_sync_master_yes_tx';
slave> SHOW DATABASES;
```
### 三、MySQL Proxy
#### 1、源码安装时MySQL proxy的依赖关系
```
libevent 1.x or higher (1.3b or later is preferred).
lua 5.1.x or higher.
glib2 2.6.0 or higher.
pkg-config.
libtool 1.5 or higher.
MySQL 5.0.x or higher developer files.
```
#### 2、安装
```
# tar zxf mysql-proxy-0.8.2.tar.gz
# cd mysql-proxy-0.8.2
# ./configure
# make
# make check
```
如果管理员有密码,上面的步骤则需要使用如下格式进行:
```
# MYSQL_PASSWORD=root_pwd make check
# make install
```
默认情况下, mysql-proxy安装在/usr/local/sbin/mysql-proxy而Lua示例脚本安装在/usr/local/share目录中。
3、配置指令
mysql proxy的各配置参数请参见官方文档http://dev.mysql.com/doc/refman/5.6/en/mysql-proxy-configuration.html
使用rpm包在rhel6上安装mysql-proxy-0.8.2,其会提供配置文件及服务脚本,但没有提供读写分享的脚本。
/etc/sysconfig/mysql-proxy文件用于定义mysql-proxy的启动参数。
ADMIN_USER the user for the proxy's admin interface. You can leave the default admin user.
ADMIN_PASSWORD the password for the admin user in clear text. Change the default password for better security.
ADMIN_LUA_SCRIPT the admin script in the Lua programming language. Without this script the admin interface cannot work. You can leave the default value.
PROXY_USER the system user under which the proxy will work. By default it is mysql-proxy, and it's safe to leave it as is.
PROXY_OPTIONS proxy options such as logging level, plugins, and Lua scripts to be loaded.
其中PROXY_OPTIONS是最常用的一个选项用于定义mysql-proxy工作时的重要参数例如
PROXY_OPTIONS="--daemon --log-level=info --log-use-syslog --plugins=proxy --plugins=admin --proxy-backend-addresses=192.168.1.102:3306 --proxy-read-only-backend-addresses=192.168.1.105:3306 --proxy-lua-script=/usr/lib/mysql-proxy/lua/proxy/rw-splitting.lua"
### 四、安装配置mysql-proxy:
#### 4.1 下载所需要的版本这里的系统平台为rhel6.4 32位系统因此就以mysql-proxy-0.8.3-linux-glibc2.3-x86-32bit.tar.gz为例。
```
# tar xf mysql-proxy-0.8.3-linux-glibc2.3-x86-32bit.tar.gz -C /usr/local
# cd /usr/local
# ln -sv mysql-proxy-0.8.3-linux-glibc2.3-x86-32bit mysql-proxy
```
添加代理用户
```
# useradd mysql-proxy
```
4.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
```
将上述内容保存为/etc/rc.d/init.d/mysql-proxy给予执行权限而后加入到服务列表。
```
# chmod +x /etc/rc.d/init.d/mysql-proxy
# chkconfig --add mysql-proxy
```
#### 4.3 为服务脚本提供配置文件/etc/sysconfig/mysql-proxy内容如下所示
```
# Options for mysql-proxy
ADMIN_USER="admin"
ADMIN_PASSWORD="admin"
ADMIN_ADDRESS=""
ADMIN_LUA_SCRIPT="/usr/local/mysql-proxy/share/doc/mysql-proxy/admin.lua"
PROXY_ADDRESS=""
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=172.16.100.6:3306 --proxy-read-only-backend-addresses=172.16.100.7:3306 --proxy-lua-script=/usr/local/mysql-proxy/share/doc/mysql-proxy/rw-splitting.lua"
```
其中的proxy-backend-addresses选项和proxy-read-only-backend-addresses选项均可重复使用多次以实现指定多个读写服务器或只读服务器。
#### 4.4 mysql-proxy的配置选项
mysql-proxy的配置选项大致可分为帮助选项、管理选项、代理选项及应用程序选项几类下面一起去介绍它们。
```
--help
--help-admin
--help-proxy
--help-all ———— 以上四个选项均用于获取帮助信息;
--proxy-address=host:port ———— 代理服务监听的地址和端口;
--admin-address=host:port ———— 管理模块监听的地址和端口;
--proxy-backend-addresses=host:port ———— 后端mysql服务器的地址和端口
--proxy-read-only-backend-addresses=host:port ———— 后端只读mysql服务器的地址和端口
--proxy-lua-script=file_name ———— 完成mysql代理功能的Lua脚本
--daemon ———— 以守护进程模式启动mysql-proxy
--keepalive ———— 在mysql-proxy崩溃时尝试重启之
--log-file=/path/to/log_file_name ———— 日志文件名称;
--log-level=level ———— 日志级别;
--log-use-syslog ———— 基于syslog记录日志
--plugins=plugin,.. ———— 在mysql-proxy启动时加载的插件
--user=user_name ———— 运行mysql-proxy进程的用户
--defaults-file=/path/to/conf_file_name ———— 默认使用的配置文件路径;其配置段使用[mysql-proxy]标识;
--proxy-skip-profiling ———— 禁用profile
--pid-file=/path/to/pid_file_name ———— 进程文件名;
```
5、复制如下内容建立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
```
#### 6、测试
6.1 管理功能测试
```
# mysql -uadmin -padmin -h172.16.100.107 --port=4041
```
```
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.0.99-agent-admin
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql> SELECT * FROM backends;
+-------------+-------------------+-------+------+------+-------------------+
| backend_ndx | address | state | type | uuid | connected_clients |
+-------------+-------------------+-------+------+------+-------------------+
| 1 | 172.16.100.6:3306 | up | rw | NULL | 0 |
| 2 | 172.16.100.7:3306 | up | ro | NULL | 0 |
+-------------+-------------------+-------+------+------+-------------------+
2 rows in set (0.00 sec)
```
6.2 读写分离测试
```
# mysql -uroot -pmagedu.com -h172.16.100.107 --port=4040
```
下面的读写分享脚本是由mysql-proxy-0.8.3提供,将其复制保存为/usr/lib/mysql-proxy/lua/proxy/rw-splitting.lua就可以启动服务了。
```
--[[ $%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%$ --]]
---
-- a flexible statement based load balancer with connection pooling
--
-- * build a connection pool of min_idle_connections for each backend and maintain
-- its size
-- *
--
--
local commands = require("proxy.commands")
local tokenizer = require("proxy.tokenizer")
local lb = require("proxy.balance")
local auto_config = require("proxy.auto-config")
--- config
--
-- connection pool
if not proxy.global.config.rwsplit then
proxy.global.config.rwsplit = {
min_idle_connections = 4,
max_idle_connections = 8,
is_debug = false
}
end
---
-- read/write splitting sends all non-transactional SELECTs to the slaves
--
-- is_in_transaction tracks the state of the transactions
local is_in_transaction = false
-- if this was a SELECT SQL_CALC_FOUND_ROWS ... stay on the same connections
local is_in_select_calc_found_rows = false
---
-- get a connection to a backend
--
-- as long as we don't have enough connections in the pool, create new connections
--
function connect_server()
local is_debug = proxy.global.config.rwsplit.is_debug
-- make sure that we connect to each backend at least ones to
-- keep the connections to the servers alive
--
-- on read_query we can switch the backends again to another backend
if is_debug then
print()
print("[connect_server] " .. proxy.connection.client.src.name)
end
local rw_ndx = 0
-- init all backends
for i = 1, #proxy.global.backends do
local s = proxy.global.backends[i]
local pool = s.pool -- we don't have a username yet, try to find a connections which is idling
local cur_idle = pool.users[""].cur_idle_connections
pool.min_idle_connections = proxy.global.config.rwsplit.min_idle_connections
pool.max_idle_connections = proxy.global.config.rwsplit.max_idle_connections
if is_debug then
print(" [".. i .."].connected_clients = " .. s.connected_clients)
print(" [".. i .."].pool.cur_idle = " .. cur_idle)
print(" [".. i .."].pool.max_idle = " .. pool.max_idle_connections)
print(" [".. i .."].pool.min_idle = " .. pool.min_idle_connections)
print(" [".. i .."].type = " .. s.type)
print(" [".. i .."].state = " .. s.state)
end
-- prefer connections to the master
if s.type == proxy.BACKEND_TYPE_RW and
s.state ~= proxy.BACKEND_STATE_DOWN and
cur_idle < pool.min_idle_connections then
proxy.connection.backend_ndx = i
break
elseif s.type == proxy.BACKEND_TYPE_RO and
s.state ~= proxy.BACKEND_STATE_DOWN and
cur_idle < pool.min_idle_connections then
proxy.connection.backend_ndx = i
break
elseif s.type == proxy.BACKEND_TYPE_RW and
s.state ~= proxy.BACKEND_STATE_DOWN and
rw_ndx == 0 then
rw_ndx = i
end
end
if proxy.connection.backend_ndx == 0 then
if is_debug then
print(" [" .. rw_ndx .. "] taking master as default")
end
proxy.connection.backend_ndx = rw_ndx
end
-- pick a random backend
--
-- we someone have to skip DOWN backends
-- ok, did we got a backend ?
if proxy.connection.server then
if is_debug then
print(" using pooled connection from: " .. proxy.connection.backend_ndx)
end
-- stay with it
return proxy.PROXY_IGNORE_RESULT
end
if is_debug then
print(" [" .. proxy.connection.backend_ndx .. "] idle-conns below min-idle")
end
-- open a new connection
end
---
-- put the successfully authed connection into the connection pool
--
-- @param auth the context information for the auth
--
-- auth.packet is the packet
function read_auth_result( auth )
if is_debug then
print("[read_auth_result] " .. proxy.connection.client.src.name)
end
if auth.packet:byte() == proxy.MYSQLD_PACKET_OK then
-- auth was fine, disconnect from the server
proxy.connection.backend_ndx = 0
elseif auth.packet:byte() == proxy.MYSQLD_PACKET_EOF then
-- we received either a
--
-- * MYSQLD_PACKET_ERR and the auth failed or
-- * MYSQLD_PACKET_EOF which means a OLD PASSWORD (4.0) was sent
print("(read_auth_result) ... not ok yet");
elseif auth.packet:byte() == proxy.MYSQLD_PACKET_ERR then
-- auth failed
end
end
---
-- read/write splitting
function read_query( packet )
local is_debug = proxy.global.config.rwsplit.is_debug
local cmd = commands.parse(packet)
local c = proxy.connection.client
local r = auto_config.handle(cmd)
if r then return r end
local tokens
local norm_query
-- looks like we have to forward this statement to a backend
if is_debug then
print("[read_query] " .. proxy.connection.client.src.name)
print(" current backend = " .. proxy.connection.backend_ndx)
print(" client default db = " .. c.default_db)
print(" client username = " .. c.username)
if cmd.type == proxy.COM_QUERY then
print(" query = " .. cmd.query)
end
end
if cmd.type == proxy.COM_QUIT then
-- don't send COM_QUIT to the backend. We manage the connection
-- in all aspects.
proxy.response = {
type = proxy.MYSQLD_PACKET_OK,
}
if is_debug then
print(" (QUIT) current backend = " .. proxy.connection.backend_ndx)
end
return proxy.PROXY_SEND_RESULT
end
-- COM_BINLOG_DUMP packet can't be balanced
--
-- so we must send it always to the master
if cmd.type == proxy.COM_BINLOG_DUMP then
-- if we don't have a backend selected, let's pick the master
--
if proxy.connection.backend_ndx == 0 then
proxy.connection.backend_ndx = lb.idle_failsafe_rw()
end
return
end
proxy.queries:append(1, packet, { resultset_is_needed = true })
-- read/write splitting
--
-- send all non-transactional SELECTs to a slave
if not is_in_transaction and
cmd.type == proxy.COM_QUERY then
tokens = tokens or assert(tokenizer.tokenize(cmd.query))
local stmt = tokenizer.first_stmt_token(tokens)
if stmt.token_name == "TK_SQL_SELECT" then
is_in_select_calc_found_rows = false
local is_insert_id = false
for i = 1, #tokens do
local token = tokens[i]
-- SQL_CALC_FOUND_ROWS + FOUND_ROWS() have to be executed
-- on the same connection
-- print("token: " .. token.token_name)
-- print(" val: " .. token.text)
if not is_in_select_calc_found_rows and token.token_name == "TK_SQL_SQL_CALC_FOUND_ROWS" then
is_in_select_calc_found_rows = true
elseif not is_insert_id and token.token_name == "TK_LITERAL" then
local utext = token.text:upper()
if utext == "LAST_INSERT_ID" or
utext == "@@INSERT_ID" then
is_insert_id = true
end
end
-- we found the two special token, we can't find more
if is_insert_id and is_in_select_calc_found_rows then
break
end
end
-- if we ask for the last-insert-id we have to ask it on the original
-- connection
if not is_insert_id then
local backend_ndx = lb.idle_ro()
if backend_ndx > 0 then
proxy.connection.backend_ndx = backend_ndx
end
else
print(" found a SELECT LAST_INSERT_ID(), staying on the same backend")
end
end
end
-- no backend selected yet, pick a master
if proxy.connection.backend_ndx == 0 then
-- we don't have a backend right now
--
-- let's pick a master as a good default
--
proxy.connection.backend_ndx = lb.idle_failsafe_rw()
end
-- by now we should have a backend
--
-- in case the master is down, we have to close the client connections
-- otherwise we can go on
if proxy.connection.backend_ndx == 0 then
return proxy.PROXY_SEND_QUERY
end
local s = proxy.connection.server
-- if client and server db don't match, adjust the server-side
--
-- skip it if we send a INIT_DB anyway
if cmd.type ~= proxy.COM_INIT_DB and
c.default_db and c.default_db ~= s.default_db then
print(" server default db: " .. s.default_db)
print(" client default db: " .. c.default_db)
print(" syncronizing")
proxy.queries:prepend(2, string.char(proxy.COM_INIT_DB) .. c.default_db, { resultset_is_needed = true })
end
-- send to master
if is_debug then
if proxy.connection.backend_ndx > 0 then
local b = proxy.global.backends[proxy.connection.backend_ndx]
print(" sending to backend : " .. b.dst.name);
print(" is_slave : " .. tostring(b.type == proxy.BACKEND_TYPE_RO));
print(" server default db: " .. s.default_db)
print(" server username : " .. s.username)
end
print(" in_trans : " .. tostring(is_in_transaction))
print(" in_calc_found : " .. tostring(is_in_select_calc_found_rows))
print(" COM_QUERY : " .. tostring(cmd.type == proxy.COM_QUERY))
end
return proxy.PROXY_SEND_QUERY
end
---
-- as long as we are in a transaction keep the connection
-- otherwise release it so another client can use it
function read_query_result( inj )
local is_debug = proxy.global.config.rwsplit.is_debug
local res = assert(inj.resultset)
local flags = res.flags
if inj.id ~= 1 then
-- ignore the result of the USE <default_db>
-- the DB might not exist on the backend, what do do ?
--
if inj.id == 2 then
-- the injected INIT_DB failed as the slave doesn't have this DB
-- or doesn't have permissions to read from it
if res.query_status == proxy.MYSQLD_PACKET_ERR then
proxy.queries:reset()
proxy.response = {
type = proxy.MYSQLD_PACKET_ERR,
errmsg = "can't change DB ".. proxy.connection.client.default_db ..
" to on slave " .. proxy.global.backends[proxy.connection.backend_ndx].dst.name
}
return proxy.PROXY_SEND_RESULT
end
end
return proxy.PROXY_IGNORE_RESULT
end
is_in_transaction = flags.in_trans
local have_last_insert_id = (res.insert_id and (res.insert_id > 0))
if not is_in_transaction and
not is_in_select_calc_found_rows and
not have_last_insert_id then
-- release the backend
proxy.connection.backend_ndx = 0
elseif is_debug then
print("(read_query_result) staying on the same backend")
print(" in_trans : " .. tostring(is_in_transaction))
print(" in_calc_found : " .. tostring(is_in_select_calc_found_rows))
print(" have_insert_id : " .. tostring(have_last_insert_id))
end
end
---
-- close the connections if we have enough connections in the pool
--
-- @return nil - close connection
-- IGNORE_RESULT - store connection in the pool
function disconnect_client()
local is_debug = proxy.global.config.rwsplit.is_debug
if is_debug then
print("[disconnect_client] " .. proxy.connection.client.src.name)
end
-- make sure we are disconnection from the connection
-- to move the connection into the pool
proxy.connection.backend_ndx = 0
end
```

View file

@ -0,0 +1,7 @@
Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
Repeatable read (可重复读):可避免脏读、不可重复读的发生。
Read committed (读已提交):可避免脏读的发生。
Read uncommitted (读未提交):最低级别,任何情况都无法保证

View file

@ -0,0 +1,20 @@
### 查看数据库的隔离级别
```
mysql> select @@tx_isolation;
```
### 去查看先当前库的线程情况
```
mysql> show processlist;
```
没有看到正在执行的慢SQL记录线程再去查看innodb的事务表INNODB_TRX看下里面是否有正在锁定的事务线程看看ID是否在show full processlist里面的sleep线程中如果是就证明这个sleep的线程事务一直没有commit或者rollback而是卡住了我们需要手动kill掉。
```
mysql> SELECT * FROM information_schema.INNODB_TRX;
```
如果有记录,则找到trx_mysql_thread_id这个字段对应的id, 将其kill掉。假如id=100
```
mysql->kill 100
SELECT CONCAT_WS('','kill',' ',t.trx_mysql_thread_id,';')a FROM information_schema.INNODB_TRX t;
```

View file

@ -0,0 +1,37 @@
### InnoDB
```
InnoDB是一个事务型的存储引擎有行级锁定和外键约束
Innodb引擎提供了对数据库ACID事务的支持并且实现了SQL标准的四种隔离级别关于数据库事务与其隔离级别的内容请见数据库事务与其隔离级别这类型的文章。该引擎还提供了行级锁和外键约束它的设计目标是处理大容量数据库系统它本身其实就是基于MySQL后台的完整数据库系统MySQL运行时Innodb会在内存中建立缓冲池用于缓冲数据和索引。但是该引擎不支持FULLTEXT类型的索引而且它没有保存表的行数当SELECT COUNT(*) FROM TABLE时需要扫描全表。当需要使用数据库事务时该引擎当然是首选。由于锁的粒度更小写操作不会锁定全表所以在并发较高时使用Innodb引擎会提升效率。但是使用行级锁也不是绝对的如果在执行一个SQL语句时MySQL不能确定要扫描的范围InnoDB表同样会锁全表。
```
#### 适用场景
```
1经常更新的表适合处理多重并发的更新请求。
2支持事务。
3可以从灾难中恢复通过bin-log日志等
4外键约束。只有他支持外键。
5支持自动增加列属性auto_increment。
```
#### 其他
```
1InnoDB给MySQL提供了具有提交、回滚和崩溃恢复能力的事务安全ACID兼容存储引擎。
2InnoDB锁定在行级并且也在SELECT语句提供一个Oracle风格一致的非锁定读这些特色增加了多用户部署和性能。没有在InnoDB中扩大锁定的需要因为在InnoDB中行级锁定适合非常小的空间。
3InnoDB也支持FOREIGN KEY强制。在SQL查询中你可以自由地将InnoDB类型的表与其它MySQL的表的类型混合起来甚至在同一个查询中也可以混合。
4InnoDB是为处理巨大数据量时的最大性能设计它的CPU效率可能是任何其它基于磁盘的关系数据库引擎所不能匹敌的。
5InnoDB被用来在众多需要高性能的大型数据库站点上产生。
```
### MyISAM
```
MyIASM是MySQL默认的引擎但是它没有提供对数据库事务的支持也不支持行级锁和外键因此当INSERT(插入)或UPDATE(更新)数据时即写操作需要锁定整个表,效率便会低一些。
MyIsam 存储引擎独立于操作系统也就是可以在windows上使用也可以比较简单的将数据转移到linux操作系统上去。
意味着:引擎在创建表的时候,会创建三个文件,一个是.frm文件用于存储表的定义一个是.MYD文件用于存储表的数据另一个是.MYI文件存储的是索引。操作系统对大文件的操作是比较慢的这样将表分为三个文件那么.MYD这个文件单独来存放数据自然可以优化数据库的查询等操作。有索引管理和字段管理。MyISAM还使用一种表格锁定的机制来优化多个并发的读写操作其代价是你需要经常运行OPTIMIZE TABLE命令来恢复被更新机制所浪费的空间。
```
#### 适用场景
```
1不支持事务的设计但是并不代表着有事务操作的项目不能用MyIsam存储引擎可以在service层进行根据自己的业务需求进行相应的控制。
2不支持外键的表设计。
3查询速度很快如果数据库insert和update的操作比较多的话比较适用。
4整天 对表进行加锁的场景。
5MyISAM极度强调快速读取操作。
6MyIASM中存储了表的行数于是SELECT COUNT(*) FROM TABLE时只需要直接读取已经保存好的值而不需要进行全表扫描。如果表的读操作远远多于写操作且不需要数据库事务的支持那么MyIASM也是很好的选择。
```

View file

@ -0,0 +1,186 @@
使用Xtrabackup进行MySQL备份
一、安装
1、简介
Xtrabackup是由percona提供的mysql数据库备份工具据官方介绍这也是世界上惟一一款开源的能够对innodb和xtradb数据库进行热备的工具。特点
(1)备份过程快速、可靠;
(2)备份过程不会打断正在执行的事务;
(3)能够基于压缩等功能节约磁盘空间和流量;
(4)自动实现备份检验;
(5)还原速度快;
2、安装
其最新版的软件可从 http://www.percona.com/software/percona-xtrabackup/ 获得。本文基于RHEL5.8的系统因此直接下载相应版本的rpm包安装即可这里不再演示其过程。
二、备份的实现
1、完全备份
# innobackupex --user=DBUSER --password=DBUSERPASS /path/to/BACKUP-DIR/
如果要使用一个最小权限的用户进行备份,则可基于如下命令创建此类用户:
mysql> CREATE USER bkpuser@localhost IDENTIFIED BY s3cret;
mysql> REVOKE ALL PRIVILEGES, GRANT OPTION FROM bkpuser;
mysql> GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO bkpuser@localhost;
mysql> FLUSH PRIVILEGES;
使用innobakupex备份时其会调用xtrabackup备份所有的InnoDB表复制所有关于表结构定义的相关文件(.frm)、以及MyISAM、MERGE、CSV和ARCHIVE表的相关文件同时还会备份触发器和数据库配置信息相关的文件。这些文件会被保存至一个以时间命令的目录中。
在备份的同时innobackupex还会在备份目录中创建如下文件
(1)xtrabackup_checkpoints —— 备份类型如完全或增量、备份状态如是否已经为prepared状态和LSN(日志序列号)范围信息;
每个InnoDB页(通常为16k大小)都会包含一个日志序列号即LSN。LSN是整个数据库系统的系统版本号每个页面相关的LSN能够表明此页面最近是如何发生改变的。
(2)xtrabackup_binlog_info —— mysql服务器当前正在使用的二进制日志文件及至备份这一刻为止二进制日志事件的位置。
(3)xtrabackup_binlog_pos_innodb —— 二进制日志文件及用于InnoDB或XtraDB表的二进制日志文件的当前position。
(4)xtrabackup_binary —— 备份中用到的xtrabackup的可执行文件
(5)backup-my.cnf —— 备份命令用到的配置选项信息;
在使用innobackupex进行备份时还可以使用--no-timestamp选项来阻止命令自动创建一个以时间命名的目录如此一来innobackupex命令将会创建一个BACKUP-DIR目录来存储备份数据。
2、准备(prepare)一个完全备份
一般情况下,在备份完成后,数据尚且不能用于恢复操作,因为备份的数据中可能会包含尚未提交的事务或已经提交但尚未同步至数据文件中的事务。因此,此时数据文件仍处理不一致状态。“准备”的主要作用正是通过回滚未提交的事务及同步已经提交的事务至数据文件也使得数据文件处于一致性状态。
innobakupex命令的--apply-log选项可用于实现上述功能。如下面的命令
# innobackupex --apply-log /path/to/BACKUP-DIR
如果执行正确,其最后输出的几行信息通常如下:
xtrabackup: starting shutdown with innodb_fast_shutdown = 1
120407 9:01:36 InnoDB: Starting shutdown...
120407 9:01:40 InnoDB: Shutdown completed; log sequence number 92036620
120407 09:01:40 innobackupex: completed OK!
在实现“准备”的过程中innobackupex通常还可以使用--use-memory选项来指定其可以使用的内存的大小默认通常为100M。如果有足够的内存可用可以多划分一些内存给prepare的过程以提高其完成速度。
3、从一个完全备份中恢复数据
注意恢复不用启动MySQL
innobackupex命令的--copy-back选项用于执行恢复操作其通过复制所有数据相关的文件至mysql服务器DATADIR目录中来执行恢复过程。innobackupex通过backup-my.cnf来获取DATADIR目录的相关信息。
# innobackupex --copy-back /path/to/BACKUP-DIR
如果执行正确,其输出信息的最后几行通常如下:
innobackupex: Starting to copy InnoDB log files
innobackupex: in '/backup/2012-04-07_08-17-03'
innobackupex: back to original InnoDB log directory '/mydata/data'
innobackupex: Finished copying back files.
120407 09:36:10 innobackupex: completed OK!
请确保如上信息的最行一行出现“innobackupex: completed OK!”。
当数据恢复至DATADIR目录以后还需要确保所有数据文件的属主和属组均为正确的用户如mysql否则在启动mysqld之前还需要事先修改数据文件的属主和属组。如
# chown -R mysql:mysql /mydata/data/
4、使用innobackupex进行增量备份
每个InnoDB的页面都会包含一个LSN信息每当相关的数据发生改变相关的页面的LSN就会自动增长。这正是InnoDB表可以进行增量备份的基础即innobackupex通过备份上次完全备份之后发生改变的页面来实现。
要实现第一次增量备份,可以使用下面的命令进行:
# innobackupex --incremental /backup --incremental-basedir=BASEDIR
其中BASEDIR指的是完全备份所在的目录此命令执行结束后innobackupex命令会在/backup目录中创建一个新的以时间命名的目录以存放所有的增量备份数据。另外在执行过增量备份之后再一次进行增量备份时其--incremental-basedir应该指向上一次的增量备份所在的目录。
需要注意的是增量备份仅能应用于InnoDB或XtraDB表对于MyISAM表而言执行增量备份时其实进行的是完全备份。
“准备”(prepare)增量备份与整理完全备份有着一些不同,尤其要注意的是:
(1)需要在每个备份(包括完全和各个增量备份)上,将已经提交的事务进行“重放”。“重放”之后,所有的备份数据将合并到完全备份上。
(2)基于所有的备份将未提交的事务进行“回滚”。
于是,操作就变成了:
# innobackupex --apply-log --redo-only BASE-DIR
接着执行:
# innobackupex --apply-log --redo-only BASE-DIR --incremental-dir=INCREMENTAL-DIR-1
而后是第二个增量:
# innobackupex --apply-log --redo-only BASE-DIR --incremental-dir=INCREMENTAL-DIR-2
其中BASE-DIR指的是完全备份所在的目录而INCREMENTAL-DIR-1指的是第一次增量备份的目录INCREMENTAL-DIR-2指的是第二次增量备份的目录其它依次类推即如果有多次增量备份每一次都要执行如上操作
5、Xtrabackup的“流”及“备份压缩”功能
Xtrabackup对备份的数据文件支持“流”功能即可以将备份的数据通过STDOUT传输给tar程序进行归档而不是默认的直接保存至某备份目录中。要使用此功能仅需要使用--stream选项即可。如
# innobackupex --stream=tar /backup | gzip > /backup/`date +%F_%H-%M-%S`.tar.gz
甚至也可以使用类似如下命令将数据备份至其它服务器:
# innobackupex --stream=tar /backup | ssh user@www.magedu.com "cat - > /backups/`date +%F_%H-%M-%S`.tar"
此外,在执行本地备份时,还可以使用--parallel选项对多个文件进行并行复制。此选项用于指定在复制时启动的线程数目。当然在实际进行备份时要利用此功能的便利性也需要启用innodb_file_per_table选项或共享的表空间通过innodb_data_file_path选项存储在多个ibdata文件中。对某一数据库的多个文件的复制无法利用到此功能。其简单使用方法如下
# innobackupex --parallel /path/to/backup
同时innobackupex备份的数据文件也可以存储至远程主机这可以使用--remote-host选项来实现
# innobackupex --remote-host=root@www.magedu.com /path/IN/REMOTE/HOST/to/backup
6、导入或导出单张表
默认情况下InnoDB表不能通过直接复制表文件的方式在mysql服务器之间进行移植即便使用了innodb_file_per_table选项。而使用Xtrabackup工具可以实现此种功能不过此时需要“导出”表的mysql服务器启用了innodb_file_per_table选项严格来说是要“导出”的表在其创建之前mysql服务器就启用了innodb_file_per_table选项并且“导入”表的服务器同时启用了innodb_file_per_table和innodb_expand_import选项。
(1)“导出”表
导出表是在备份的prepare阶段进行的因此一旦完全备份完成就可以在prepare过程中通过--export选项将某表导出了
# innobackupex --apply-log --export /path/to/backup
此命令会为每个innodb表的表空间创建一个以.exp结尾的文件这些以.exp结尾的文件则可以用于导入至其它服务器。
(2)“导入”表
要在mysql服务器上导入来自于其它服务器的某innodb表需要先在当前服务器上创建一个跟原表表结构一致的表而后才能实现将表导入
mysql> CREATE TABLE mytable (...) ENGINE=InnoDB;
然后将此表的表空间删除:
mysql> ALTER TABLE mydatabase.mytable DISCARD TABLESPACE;
接下来将来自于“导出”表的服务器的mytable表的mytable.ibd和mytable.exp文件复制到当前服务器的数据目录然后使用如下命令将其“导入”
mysql> ALTER TABLE mydatabase.mytable IMPORT TABLESPACE;
7、使用Xtrabackup对数据库进行部分备份
Xtrabackup也可以实现部分备份即只备份某个或某些指定的数据库或某数据库中的某个或某些表。但要使用此功能必须启用innodb_file_per_table选项即每张表保存为一个独立的文件。同时其也不支持--stream选项即不支持将数据通过管道传输给其它程序进行处理。
此外还原部分备份跟还原全部数据的备份也有所不同即你不能通过简单地将prepared的部分备份使用--copy-back选项直接复制回数据目录而是要通过导入表的方向来实现还原。当然有些情况下部分备份也可以直接通过--copy-back进行还原但这种方式还原而来的数据多数会产生数据不一致的问题因此无论如何不推荐使用这种方式。
(1)创建部分备份
创建部分备份的方式有三种:正则表达式(--include), 枚举表文件(--tables-file)和列出要备份的数据库(--databases)。
(a)使用--include
使用--include时要求为其指定要备份的表的完整名称即形如databasename.tablename
# innobackupex --include='^mageedu[.]tb1' /path/to/backup
(b)使用--tables-file
此选项的参数需要是一个文件名,此文件中每行包含一个要备份的表的完整名称;如:
# echo -e 'mageedu.tb1\nmageedu.tb2' > /tmp/tables.txt
# innobackupex --tables-file=/tmp/tables.txt /path/to/backup
(c)使用--databases
此选项接受的参数为数据名,如果要指定多个数据库,彼此间需要以空格隔开;同时,在指定某数据库时,也可以只指定其中的某张表。此外,此选项也可以接受一个文件为参数,文件中每一行为一个要备份的对象。如:
# innobackupex --databases="mageedu testdb" /path/to/backup
(2)整理(preparing)部分备份
prepare部分备份的过程类似于导出表的过程要使用--export选项进行
# innobackupex --apply-log --export /pat/to/partial/backup
此命令执行过程中innobackupex会调用xtrabackup命令从数据字典中移除缺失的表因此会显示出许多关于“表不存在”类的警告信息。同时也会显示出为备份文件中存在的表创建.exp文件的相关信息。
(3)还原部分备份
还原部分备份的过程跟导入表的过程相同。当然也可以通过直接复制prepared状态的备份直接至数据目录中实现还原不要此时要求数据目录处于一致状态。

165
数据库/mysql/mysql.html Normal file
View file

@ -0,0 +1,165 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="tool" content="leanote-desktop-app">
<title>mysql</title>
<style>
*{font-family:"lucida grande","lucida sans unicode",lucida,helvetica,"Hiragino Sans GB","Microsoft YaHei","WenQuanYi Micro Hei",sans-serif;}
body {
margin: 0;
}
/*公用文字样式*/
h1{font-size:30px}h2{font-size:24px}h3{font-size:18px}h4{font-size:14px}
.note-container{
width:850px;
margin:auto;
padding: 10px 20px;
box-shadow: 1px 1px 10px #eee;
}
#title {
margin: 0;
}
table {
margin-bottom: 16px;
border-collapse: collapse;
}
table th, table td {
padding: 6px 13px;
border: 1px solid #ddd;
}
table th {
font-weight: bold;
}
table tr {
background-color: none;
border-top: 1px solid #ccc;
}
table tr:nth-child(2n) {
background-color: rgb(247, 247, 249);
}
.mce-item-table, .mce-item-table td, .mce-item-table th, .mce-item-table caption {
border: 1px solid #ddd;
border-collapse: collapse;
padding: 6px 13px;
}
blockquote {
border-left-width:10px;
background-color:rgba(128,128,128,0.05);
border-top-right-radius:5px;
border-bottom-right-radius:5px;
padding:15px 20px;
border-left:5px solid rgba(128,128,128,0.075);
}
blockquote p {
margin-bottom:1.1em;
font-size:1em;
line-height:1.45
}
blockquote ul:last-child,blockquote ol:last-child {
margin-bottom:0
}
pre {
padding: 18px;
background-color: #f7f7f9;
border: 1px solid #e1e1e8;
border-radius: 3px;
display: block;
}
code {
padding: 2px 4px;
font-size: 90%;
color: #c7254e;
white-space: nowrap;
background-color: #f9f2f4;
border-radius: 4px;
}
.footnote {
vertical-align: top;
position: relative;
top: -0.5em;
font-size: .8em;
}
hr {
margin:2em 0
}
img {
max-width:100%
}
pre {
word-break:break-word
}
p,pre,pre.prettyprint,blockquote {
margin:0 0 1.1em
}
hr {
margin:2em 0
}
img {
max-width:100%
}
.sequence-diagram,.flow-chart {
text-align:center;
margin-bottom:1.1em
}
.sequence-diagram text,.flow-chart text {
font-size:15px !important;
font-family:"Source Sans Pro",sans-serif !important
}
.sequence-diagram [fill="#ffffff"],.flow-chart [fill="#ffffff"] {
fill:#f6f6f6
}
.sequence-diagram [stroke="#000000"],.flow-chart [stroke="#000000"] {
stroke:#3f3f3f
}
.sequence-diagram text[stroke="#000000"],.flow-chart text[stroke="#000000"] {
stroke:none
}
.sequence-diagram [fill="#000"],.flow-chart [fill="#000"],.sequence-diagram [fill="#000000"],.flow-chart [fill="#000000"],.sequence-diagram [fill="black"],.flow-chart [fill="black"] {
fill:#3f3f3f
}
ul,ol {
margin-bottom:1.1em
}
ul ul,ol ul,ul ol,ol ol {
margin-bottom:1.1em
}
kbd {
padding:.1em .6em;
border:1px solid rgba(63,63,63,0.25);
-webkit-box-shadow:0 1px 0 rgba(63,63,63,0.25);
box-shadow:0 1px 0 rgba(63,63,63,0.25);
font-size:.7em;
font-family:sans-serif;
background-color:#fff;
color:#333;
border-radius:3px;
display:inline-block;
margin:0 .1em;
white-space:nowrap
}
.toc ul {
list-style-type:none;
margin-bottom:15px
}
</style>
<!-- 该css供自定义样式 -->
<link href="../leanote-html.css" rel="stylesheet">
</head>
<body>
<div class="note-container">
<h1 class="title" id="leanote-title">mysql</h1>
<div class="content-html" id="leanote-content"><div>grant</div><div>show grants for "username"@"host"</div><div><br></div><div>flush&nbsp;privileges;</div><div><div>用mysqldump工具导出表数据</div><div>mysqldump&nbsp;-uiboxpaynew&nbsp;-p&nbsp;-h172.16.1.86&nbsp;-t&nbsp;--compact&nbsp;iboxpay&nbsp;sp_posts&nbsp;&gt;/tmp/sp_posts.sql</div></div><div>//-u用户-p密码-h主机-t表数据--compact去掉注释iboxpay数据库sp_posts表-d表结构</div><div><br></div><div><br></div><div>备库同步</div><div><div>mysql&nbsp;-e&nbsp;"show&nbsp;databases;"&nbsp;-uroot&nbsp;-p'password'&nbsp;|&nbsp;grep&nbsp;-Ev&nbsp;"Database|information_schema|mysql|sys|performance_schema|test"|&nbsp;xargs&nbsp;mysqldump&nbsp;-uroot&nbsp;-p'password'&nbsp;&nbsp;--databases&nbsp;-R&gt;&nbsp;/tmp/aaa.sql</div><p><br></p></div></div>
</div>
<!-- 该js供其它处理 -->
<script src="../leanote-html.js"></script>
</body>
</html>

View file

@ -0,0 +1,29 @@
mysqladmin工具
mysqladmin [options] command [arg] [command[arg]] .....
command
create DB_Name 创建空数据库
-e直接返回
drop DB_Name 删除数据库
debug 打开调试日志并记录与error log中
status输出简要状态信息
-sleep # 指定显示延迟
-count # 指定批次
extended-status:输出mysq的各状态变量及数值相当于执行“mysql> show global status”
flush-hosts:清空主机相关的缓存DNS解析缓存此前因为连接错误次数过多而被拒绝访问mysqld的主机列表
flush-logs日志滚动主要是二进制日志和中继日志
refresh相当于同时使用flush-logs和flush-hosts
flush-privileges通知服务器重读授权表
reload重载授权表
flush-status重置状态变量的值
flush-tables关闭当前打开的表文件句柄
flush-threads清空线程缓存
kill杀死指定的线程可以一次杀死多个线程以逗号分隔但不能有多余空格
password修改指定用户的密码
processlist 线程列表
shutdown关闭mysqld进程
start-slave 启动从服务器进程
stop-slave 关闭从服务器进程
variables显示mysql的各服务器进程

View file

@ -0,0 +1,48 @@
1、在两台服务器上各自建立一个具有复制权限的用户
2、修改配置文件
# 主服务器A上
[mysqld]
server-id = 10
log-bin = mysql-bin
relay-log = relay-mysql
auto-increment-offset = 2
auto-increment-increment = 1
# 主服务器B上
[mysqld]
server-id = 20
log-bin = mysql-bin
relay-log = relay-mysql
auto-increment-increment = 2 # 起始值
auto-increment-offset = 2 # 步长
3、如果此时两台服务器均为新建立且无其它写入操作各服务器只需记录当前自己二进制日志文件及事件位置以之作为另外的服务器复制起始位置即可
serverA|mysql> SHOW MASTER STATUS\G
************************** 1. row ***************************
File: mysql-bin.000001
Position: 710
Binlog_Do_DB:
Binlog_Ignore_DB:
1 row in set (0.00 sec)
server2|mysql> SHOW MASTER STATUS\G
mysql> SHOW MASTER STATUS\G
*************************** 1. row ***************************
File: mysql-bin.000003
Position: 811
Binlog_Do_DB:
Binlog_Ignore_DB:
1 row in set (0.00 sec)
4、各服务器接下来指定对另一台服务器为自己的主服务器即可
serverA|mysql> CHANGE MASTER TO ...,MASTER_LOG_FILE='mysql-bin.000003', MASTER_LOG_POS=811
serverB|mysql> CHANGE MASTER TO ...,MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=710
多主,且高可用的解决方案:
MMMMulti Master MySQL
MHAMySQL HA

View file

@ -0,0 +1,16 @@
二进制文件的字段说明
1、事件发生的日期和时间
2、服务器id
3、时间结束位置
4、事件类型
5、原服务器生成此事件时的线程id查看线程 [交互]show processlist
6、语句的时间戳和写入二进制文件的时间差
7、错误代码
8、事件内容
9、时间位置相当于下一个事件
查看二进制文件 mysqlbinlog binlogfile
查看日志偏移点 [交互]show master status;
二进制日志滚动 [交互]flush logs;
查看从指定偏移开始的日志 mysqlbinlog --start-position=偏移量 binlogfile
查看指定事件的日志 [交互]show binlog events in logfile

View file

@ -0,0 +1,5 @@
1、删除所有匿名用户 drop user ''@'localhost';
2、为所有root用户设定密码
[交互]set password for username@hosr = password('密码');
[交互]update mysql.user set password = password('密码') where user = 'root'; flush privileges;
mysqladmin -uusername -hhost password '密码' -p; mysqladmin -uusername -hhost -p flush-privileges

View file

@ -0,0 +1,56 @@
%:匹配任意长度任意字符
_:匹配任意单个字符
/*...*/:注释
数据库支持的所有服务器选项列表 mysqld --help --verbose
1、显示musqld使用配置文件的方式
2、显示mysqld启动时可用的选项通常为长选项
3、显示mysqld的配置文件中可用的配置变量
# 可以使用like子句
数据库变量 [交互]show variables;
数据库全局变量 [交互]show global variables;
数据库会话变量 [交互]show session variables;
数据库某个变量 [交互]select @@[global|session].variables_name;
查看全局变量 [交互]select * from information_schema.GLOBAL_VARIABLES where VARIABLE_NAME='SOME_VARIABLE_NAME';
查看会话变量 [交互]select * from information_schema.SESSION_VARIABLES where VARIABLE_NAME='SOME_VARIABLE_NAME';
修改变量值 [交互]set [global|session] variables_name="值"
数据库状态 [交互]show status;
数据库全局状态 [交互]show global status;
数据库状态 [交互]show session status;
查看数据库支持的引擎及引擎特性 [交互]show engines;
[交互]help contents 所有支持的帮助信息
[交互]help 关键字 获取特定的帮助信息
[交互]\. /path/to/sqlscript 执行sql脚本
[交互]\q 退出
[交互]\ help
[交互]\c 中断输入
[交互]\g 语句分隔符(无论是否是;
[交互]\G 以行形式显示执行结果
[交互]\! 执行shell命令
[交互]\s status
快捷键
ctrl+w删除光标前的单词
ctrl+u删除光标之前的所有字符
ctrl+y粘贴之前删除的内容
ctrl+a移动光标到行首
ctrl+e移动光标到行尾
mysql客户端连接进入服务器
-e sql不登陆数据库显示sql执行内容
--compress 压缩
-H或--html结果显示为html
-X或--xml结果显示xml
--safe-update拒绝使用无where子句的update或delete语句

View file

@ -0,0 +1,248 @@
MySQL有内置的SQL模型SQL_MODE用来定义字符超出的操作和模仿别的数据库的类型通过修改全局变量
常用的模式有:
TRADITIONAL 使用传统模式
STRICT_TRANS_TABLES 仅对支持事务的表的严格模式
STRICT_ALL_TABLES 对所有表使用严格模式
设定服务器变量的值:通常仅用于支持动态的变量
支持修改的服务器变量
动态变量可以在MySQL运行时修改
静态变量:与配置文件中修改其值,并重启后方能生效
服务器变量从其生效范围来讲,分两类
全局变量:服务器级别,修改之后仅对新建立的会话生效
回话变量:会话级别,仅对当前会话有效
会话建立时,从全局继承各变量
查看服务器变量
mysql> show [{global|session}] variables [like ''];
mysql> select @@{globa|session}.variable_name
mysql> mysql> select * from information_schema.GLOBAL_VARIABLES where VARIABLE_NAME='SOME_VARIABLE_NAME'; 查看全局变量
mysql> mysql> select * from information_schema.SESSION_VARIABLES where VARIABLE_NAME='SOME_VARIABLE_NAME'; 查看会话变量
修改变量:
前提:默认仅管理员有权限修改全局变量
mysql> set {global|session} variable_name='value';
注意无论是全局还是会话级别的动态变量修改在重启mysql后都会失效想永久有效可以定义在配置文件中的响应段中[mysqld]
数据库:
创建数据库
create database
CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name
[[DEFAULT] CHARACTER SET [=] charset_name 字符集
| [DEFAULT] COLLATE [=] collation_name 排序方式]
删除数据库
DROP {DATABASE | SCHEMA} [IF EXISTS] db_name
修改数据库的字符集和排序字符以及数据字典
ALTER {DATABASE | SCHEMA} [db_name]
[[DEFAULT] CHARACTER SET [=] charset_name 字符集
| [DEFAULT] COLLATE [=] collation_name 排序方式]
ALTER {DATABASE | SCHEMA} db_name
UPGRADE DATA DIRECTORY NAME
表:
创建表:第一种方式
CREATE [TEMPORARY临时表保存在内存中] TABLE [IF NOT EXISTS] tbl_name
(create_definition,...)
[table_options]
(create_definition,...)
字段的定义:字段名、类型和类型修饰符
键、索引和约束
primary keyunique keyforeign keycheck
{index|key}
[table_options]
engine [=] engine_name
AUTO_INCREMENT [=] value 指定AUTO_INCREMENT的起始值
[DEFAULT] CHARACTER SET [=] charset_name 指定默认字符集
CHECKSUM [=] {0 | 1} 是否使用校验值
[DEFAULT] COLLATE [=] collation_name 排序规则
COMMENT [=] 'string' 注释
DELAY_KEY_WRITE [=] {0 | 1} 是否启用键延迟写入
ROW_FORMAT [=] {DEFAULT默认|DYNAMIC动态|FIXED静态|COMPRESSED压缩|REDUNDANT冗余|COMPACT紧致} 表格式
TABLESPACE tablespace_name [STORAGE {DISK|MEMORY|DEFAULT}] 表空间
myISAM引擎每表有三个文件都位于数据库目录
tb_name.frm:表结构定义
tb_name.MYD:数据文件
tb_name.MYI:索引文件
InnoDB表有两种存储方式
1、默认每表有一个独立文件和一个多表共享的文件
tb_name.frm表结构的定义位于数据库目录中
ibdata#共享的表空间文件默认位于数据目录datadir指向的目录中
2、独立的表空间
tb_name.frm每表有一个表结构文件
tb_name.ibd:一个独有的表空间文件
应该修改innodb_file_per_table为ON
表创建:第二种方式(复制表数据)
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
[(create_definition,...)]
[table_options]
select_statement
表创建:第三种方式(复制表结构)
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
{ LIKE old_tbl_name | (LIKE old_tbl_name) }
查看表的状态信息
show table status like table_name
删除表
DROP [TEMPORARY] TABLE [IF EXISTS]
tbl_name [, tbl_name] ...
[RESTRICT | CASCADE]
修改表:
ALTER TABLE tbl_name
[alter_specification [, alter_specification] ...]
修改字段定义:
插入新字段:
ADD [COLUMN] col_name column_definition
[FIRST | AFTER col_name ]
删除字段
DROP [COLUMN] col_name
修改字段
修改字段名称
CHANGE [COLUMN] old_col_name new_col_name column_definition
[FIRST|AFTER col_name]
修改字段类型及属性等
MODIFY [COLUMN] col_name column_definition
[FIRST | AFTER col_name]
表改名:
rename to|as new tb_name
修改存储引擎
engine =
指定排序标准的字段
ORDER BY col_name [, col_name] ...
MySQL的查询操作
单表查询:简单查询
多表查询:连续查询
联合查询
选择和投影
投影:挑选要符合的字段
选择:挑选符合条件的行
投影select 字段1字段2... from tb_name
selcet * from tb_name
选择select 字段1字段2,.... from tb_name where 子句
布尔条件表达式
布尔条件表达式操作符
= 等值比较
<=>:跟空值比较不会产生额外信息
<>:不等值
<:
<=
>
>=
IS NULL:是否为空
IS NOT NULL是否不空
LIKE支持的通配符%(任意长度的任意字符) _任意单个字符
RLIKEREGEXP支持使用正则表达式作为条件
IN判断某行的某一字段的值是否在给定的列表中
BETWEEN...AND....:判断指定的值是否位于指定的范围之间
组合条件测试
NOT |
AND &&
OR ||
排序
order by ‘排序字段’
默认为升序ASC
降序DESC
内置的聚合函数
sum
AVG平均值
MAX最大值
MIN最小值
COUNT个数统计
分组
group by
对分组的条件过滤
having
只返回有用的行
LIMIT
一个数为显示的行数
两个数字为偏移第一个数字行,显示第二个数字
select语句的执行流程
from clause --> where clause --> group by --> having clause -->order by --> select -->limit
select语句
distinct 重复的只显示一次
SQL_CACHE 缓存查询结果
SQL_NO_CACHE 不缓存查询结果
MySQL多表查询和子查询
联结查询事先将两张或者多张表join根据join的结果进行查询
cross join交叉联结
自然联结
等值联结:把相同的字段进行等值连接
外联结:
左外联接:只保留出现在左外连接元算之前(左边)的关系中的元组(以左表为准,)
left_tb LEFT JOIN right_tb ON 条件
右外联接:只保留出现在右外连接元算之后(右边)的关系中的元组(以右表为准)
left_tb RIGHT JOIN right_tb ON 条件
全外联接:
自联结:
别名AS
表别名:
字段别名
子查询:在查询中嵌套的查询
用于WHERE中的子查询
1.用于比较表达式中的子查询
子查询的返回值只能有一个
2.用于EXISTS中的子查询
判断存在与否
3.用于IN中的子查询
判断存在于指定列表中
用于FROM中子查询
select alias.col,....FROM(SELECT CLUSE) alias WHERE condition
MYSQL不擅长于子查询应该避免使用子查询
总结mysql的连接查询与子查询
联结:
交叉联结:
内联结:
外联结:
左外
右外
自联结
子查询:
用于where中的子查询
用于条件比较:
用于exists
用于IN中
用于FROM
MYSQL的联合查询
把两个或多个查询语句的结果合并成一个结果进行输出
select clauase union select clause union.....
索引
show indexs from tb_name 查看索引
alter table tb_name add index(字段)
创建索引
explain 解释命令,查看命令的执行过程
MYSQL视图虚表
存储下来的select语句
创建:
create view 视图名 as select语句
删除:
drop view 视图名

View file

@ -0,0 +1,84 @@
备份对象:
数据
配置文件
代码:存储过程,存储函数,触发器
OS相关的配置文件如crontab及相关脚本等
跟复制相关的配置:二进制日志文件
备份工具:
mysqldump逻辑备份工具
InnoDB热备、MyISAM温备、Aria温备
备份和恢复过程慢
mysqldumper多线程的mysqldump
难实现差异或增量备份
lvm-snapshot:
接近于热备的工具,因为要先请求全局锁,而后创建快照,并在创建快照完成后释放全局锁
使用cp、tar等工具物理备份备份与恢复速度快
难以实现增量备份,并且请求全局锁需要等待一段时间,在繁忙的服务器上更慢
select clause into outfile '/path/to/somefile'(备份)
load data infile '/path/from/somefile' (恢复)
部分备份工具,不会备份关系定义,仅备份表中的数据
逻辑备份工具快于mysqldump
Innobase商业备份工具Innobackup
Xtrabackup开源备份工具
InnoDB热备增量备份
MyISAM温备不支持增量
物理备份,速度快
mysqldump适用于数据量较小的情况(注意备份前要加锁)
mysqldump [options] [db_name] [tb_name]
备份单个数据库mysqldump -u 用户名 -h 主机 -p 数据库 > 备份文件
恢复时,如果目标库不存在,需要事先手动备份 mysql -u 用户名 -h 主机名 -p 数据库名 < 备份文件
备份所有库mysqldump --all-database > 备份文件
备份指定多个库: mysqldump --databases db1 db2
--lock-all-tables请求锁定所有表之后再备份对InnoDBMyISAMAria做温备
--single-transaction能够对InnoDB存储引擎实现热备
备份代码:
--events备份事件调度器代码
--routines备份存储过程与存储函数
--triggers备份触发器
备份时滚动日志
--flush-logs备份前、请求到锁之后滚动日志
复制时的同步位置标记
--master-data=[0|1|2]
0:不记录
1:记录为change master语句
2、记录为注释的change master语句
备份InnoDB存储引擎的数据库mysqldump --database 数据库 --single-transaction -flush-logs --master-data=2 > 数据文件
备份MyISAM存储引擎的数据库mysqldump --database 数据库 --lock-all-tables -flush-logs --master-data=2 > 数据文件
恢复时,查看备份文件中记录的标记位置(--master-data=2参数实现mysqlbinlog文件中的位置
关闭其他连接然后使用mysqlbinlog --start-position=标记位置 --end-position=结束标记 binlog文件 > 恢复文件
关闭binlog日志记录[交互]set session sql_log_bin=0
执行全量备份脚本及binlog中抽出的数据文件
开启binlog日志记录[交互]set session sql_log_bin=1
滚动二进制文件mysqldump flush-logs
lvm-snapshot:
step1: 锁表保证数据的一致性。flush table with read lock;
step2滚动日志flush logs;
step3查看master二进制当前的状态以便slave的复制使用或者其他的恢复使用。show master status;
step4: 为mysql数据目录所在的lvm做快照-p r只读 lvcreate -s -n sqlbak_snap -L 100M -p r /dev/sqlbak/sqlbck_lv
step5: 解锁unlock tables;
step6: 挂载快照卷到一个目录下
就可以读取里面的数据。当然也可以mv到其他的目录下用来恢复。
step7: 卸载快照卷。删除快照卷 lvremove /dev/sqlbak/sqlbck_lv

View file

@ -0,0 +1,165 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="tool" content="leanote-desktop-app">
<title>mysql导入导出</title>
<style>
*{font-family:"lucida grande","lucida sans unicode",lucida,helvetica,"Hiragino Sans GB","Microsoft YaHei","WenQuanYi Micro Hei",sans-serif;}
body {
margin: 0;
}
/*公用文字样式*/
h1{font-size:30px}h2{font-size:24px}h3{font-size:18px}h4{font-size:14px}
.note-container{
width:850px;
margin:auto;
padding: 10px 20px;
box-shadow: 1px 1px 10px #eee;
}
#title {
margin: 0;
}
table {
margin-bottom: 16px;
border-collapse: collapse;
}
table th, table td {
padding: 6px 13px;
border: 1px solid #ddd;
}
table th {
font-weight: bold;
}
table tr {
background-color: none;
border-top: 1px solid #ccc;
}
table tr:nth-child(2n) {
background-color: rgb(247, 247, 249);
}
.mce-item-table, .mce-item-table td, .mce-item-table th, .mce-item-table caption {
border: 1px solid #ddd;
border-collapse: collapse;
padding: 6px 13px;
}
blockquote {
border-left-width:10px;
background-color:rgba(128,128,128,0.05);
border-top-right-radius:5px;
border-bottom-right-radius:5px;
padding:15px 20px;
border-left:5px solid rgba(128,128,128,0.075);
}
blockquote p {
margin-bottom:1.1em;
font-size:1em;
line-height:1.45
}
blockquote ul:last-child,blockquote ol:last-child {
margin-bottom:0
}
pre {
padding: 18px;
background-color: #f7f7f9;
border: 1px solid #e1e1e8;
border-radius: 3px;
display: block;
}
code {
padding: 2px 4px;
font-size: 90%;
color: #c7254e;
white-space: nowrap;
background-color: #f9f2f4;
border-radius: 4px;
}
.footnote {
vertical-align: top;
position: relative;
top: -0.5em;
font-size: .8em;
}
hr {
margin:2em 0
}
img {
max-width:100%
}
pre {
word-break:break-word
}
p,pre,pre.prettyprint,blockquote {
margin:0 0 1.1em
}
hr {
margin:2em 0
}
img {
max-width:100%
}
.sequence-diagram,.flow-chart {
text-align:center;
margin-bottom:1.1em
}
.sequence-diagram text,.flow-chart text {
font-size:15px !important;
font-family:"Source Sans Pro",sans-serif !important
}
.sequence-diagram [fill="#ffffff"],.flow-chart [fill="#ffffff"] {
fill:#f6f6f6
}
.sequence-diagram [stroke="#000000"],.flow-chart [stroke="#000000"] {
stroke:#3f3f3f
}
.sequence-diagram text[stroke="#000000"],.flow-chart text[stroke="#000000"] {
stroke:none
}
.sequence-diagram [fill="#000"],.flow-chart [fill="#000"],.sequence-diagram [fill="#000000"],.flow-chart [fill="#000000"],.sequence-diagram [fill="black"],.flow-chart [fill="black"] {
fill:#3f3f3f
}
ul,ol {
margin-bottom:1.1em
}
ul ul,ol ul,ul ol,ol ol {
margin-bottom:1.1em
}
kbd {
padding:.1em .6em;
border:1px solid rgba(63,63,63,0.25);
-webkit-box-shadow:0 1px 0 rgba(63,63,63,0.25);
box-shadow:0 1px 0 rgba(63,63,63,0.25);
font-size:.7em;
font-family:sans-serif;
background-color:#fff;
color:#333;
border-radius:3px;
display:inline-block;
margin:0 .1em;
white-space:nowrap
}
.toc ul {
list-style-type:none;
margin-bottom:15px
}
</style>
<!-- 该css供自定义样式 -->
<link href="../leanote-html.css" rel="stylesheet">
</head>
<body>
<div class="note-container">
<h1 class="title" id="leanote-title">mysql导入导出</h1>
<div class="content-html" id="leanote-content"><div><a href="http://www.cnblogs.com/jiunadianshi/articles/2022334.html" data-mce-href="http://www.cnblogs.com/jiunadianshi/articles/2022334.html">linux下导入、导出mysql数据库命令</a></div><div>一、导出数据库用mysqldump命令注意mysql的安装路径即此命令的路径</div><div>1、导出数据和表结构</div><div>mysqldump -u用户名 -p密码 数据库名 &gt; 数据库名.sql</div><div>#/usr/local/mysql/bin/&nbsp;&nbsp; mysqldump -uroot -p abc &gt; abc.sql</div><div>敲回车后会提示输入密码</div><div>2、只导出表结构</div><div>mysqldump -u用户名 -p密码 -d 数据库名 &gt; 数据库名.sql</div><div>#/usr/local/mysql/bin/&nbsp;&nbsp; mysqldump -uroot -p -d abc &gt; abc.sql</div><div>注:/usr/local/mysql/bin/&nbsp; ---&gt;&nbsp; mysql的data目录</div><div><br></div><div>二、导入数据库</div><div>1、首先建空数据库</div><div>mysql&gt;create database abc;</div><div>2、导入数据库</div><div>方法一:</div><div>1选择数据库</div><div>mysql&gt;use abc;</div><div>2设置数据库编码</div><div>mysql&gt;set names utf8;</div><div>3导入数据注意sql文件的路径</div><div>mysql&gt;source /home/abc/abc.sql;</div><div>方法二:</div><div>mysql -u用户名 -p密码 数据库名 &lt; 数据库名.sql</div><div>#mysql -uabc_f -p abc &lt; abc.sql</div><div>建议使用第二种方法导入。</div><div>注意有命令行模式有sql命令</div></div>
</div>
<!-- 该js供其它处理 -->
<script src="../leanote-html.js"></script>
</body>
</html>

View file

@ -0,0 +1,8 @@
### 原理
master节点将数据的改变记录到二进制binlog中slave会在一定时间间隔内对master二进制进行探测若发生改变那就开始一个io_thread请求master的二进制binlogmaster启动一个log dump线程发送二进制文件给slave并保存在slave节点的中继日志relay log中slave使用sql_thread从中继日志读取二进制文件在本地重放使得slave的数据与主节点保持一致最后io_thread和sql_thread休眠等待下次被唤醒
### 配置
1、主库my.cnf需要配置server_idbin_log(server_id唯一)
2、主节点创建一个具有复制权限的用户show master status查看master状态记录当前的log_bin文件和position
3、从节点my.cnf需要配置server_idread_only=true(防止在从节点执行update等操作但是对高权限的用户无效)
4、从节点执行change master to master_host=xxx,master_port=xxx,master_user=xxx,master_password=xxx,log_file='master-log-bin.xxxx',log_pos=xxx ,然后start slave可以通过show slave status\G查看状态

View file

@ -0,0 +1,55 @@
### 原因
2)1)、MySQL数据库主从同步延迟原理mysql主从同步原理主库针对写操作顺序写binlog从库单线程去主库顺序读”写操作的binlog”从库取到binlog在本地原样执行随机写来保证主从数据逻辑上一致。mysql的主从复制都是单线程的操作主库对所有DDL和DML产生binlogbinlog是顺序写所以效率很高slave的Slave_IO_Running线程到主库取日志效率比较高下一步问题来了slave的Slave_SQL_Running线程将主库的DDL和DML操作在slave实施。DML和DDL的IO操作是随即的不是顺序的成本高很多还可能slave上的其他查询产生lock争用由于Slave_SQL_Running也是单线程的所以一个DDL卡主了需要执行10分钟那么所有之后的DDL会等待这个DDL执行完才会继续执行这就导致了延时。有朋友会问“主库上那个相同的DDL也需要执行10分为什么slave会延时答案是master可以并发Slave_SQL_Running线程却不可以。
2)、MySQL数据库主从同步延迟是怎么产生的当主库的TPS并发较高时产生的DDL数量超过slave一个sql线程所能承受的范围那么延时就产生了当然还有就是可能与slave的大型query语句产生了锁等待。首要原因数据库在业务上读写压力太大CPU计算负荷大网卡负荷大硬盘随机IO太高次要原因读写binlog带来的性能影响网络传输延迟。
### 方案
1)、架构方面
1.业务的持久化层的实现采用分库架构mysql服务可平行扩展分散压力。
2.单个库读写分离,一主多从,主写从读,分散压力。这样从库压力比主库高,保护主库。
3.服务的基础架构在业务和mysql之间加入memcache或者redis的cache层。降低mysql的读压力。
4.不同业务的mysql物理上放在不同机器分散压力。
5.使用比主库更好的硬件设备作为slave总结mysql压力小延迟自然会变小。
2)、硬件方面
1.采用好服务器比如4u比2u性能明显好2u比1u性能明显好。
2.存储用ssd或者盘阵或者san提升随机写的性能。
3.主从间保证处在同一个交换机下面,并且是万兆环境。
总结,硬件强劲,延迟自然会变小。一句话,缩小延迟的解决方案就是花钱和花时间。
3)、mysql主从同步加速
1、sync_binlog在slave端设置为0
2、logs-slave-updates 从服务器从主服务器接收到的更新不记入它的二进制日志。
3、直接禁用slave端的binlog
4、slave端如果使用的存储引擎是innodbinnodb_flush_log_at_trx_commit =2
4)、从文件系统本身属性角度优化
master端修改linux、Unix文件系统中文件的etime属性 由于每当读文件时OS都会将读取操作发生的时间回写到磁盘上对于读操作频繁的数据库文件来说这是没必要的只会增加磁盘系统的负担影响I/O性能。可以通过设置文件系统的mount属性组织操作系统写atime信息在linux上的操作为打开/etc/fstab加上noatime参数/dev/sdb1 /data reiserfs noatime 1 2然后重新mount文件系统#mount -oremount /data
5)、同步参数调整主库是写对数据安全性较高比如sync_binlog=1innodb_flush_log_at_trx_commit = 1 之类的设置是需要的而slave则不需要这么高的数据安全完全可以讲sync_binlog设置为0或者关闭binloginnodb_flushlog也可以设置为0来提高sql的执行效率
1、sync_binlog=1 oMySQL提供一个sync_binlog参数来控制数据库的binlog刷到磁盘上去。默认sync_binlog=0表示MySQL不控制binlog的刷新由文件系统自己控制它的缓存的刷新。这时候的性能是最好的但是风险也是最大的。一旦系统Crash在binlog_cache中的所有binlog信息都会被丢失。
如果sync_binlog>0表示每sync_binlog次事务提交MySQL调用文件系统的刷新操作将缓存刷下去。最安全的就是sync_binlog=1了表示每次事务提交MySQL都会把binlog刷下去是最安全但是性能损耗最大的设置。这样的话在数据库所在的主机操作系统损坏或者突然掉电的情况下系统才有可能丢失1个事务的数据。但是binlog虽然是顺序IO但是设置sync_binlog=1多个事务同时提交同样很大的影响MySQL和IO性能。虽然可以通过group commit的补丁缓解但是刷新的频率过高对IO的影响也非常大。
对于高并发事务的系统来说“sync_binlog”设置为0和设置为1的系统写入性能差距可能高达5倍甚至更多。所以很多MySQL DBA设置的sync_binlog并不是最安全的1而是2或者是0。这样牺牲一定的一致性可以获得更高的并发和性能。默认情况下并不是每次写入时都将binlog与硬盘同步。因此如果操作系统或机器(不仅仅是MySQL服务器)崩溃有可能binlog中最后的语句丢失了。要想防止这种情况你可以使用sync_binlog全局变量(1是最安全的值但也是最慢的)使binlog在每N次binlog写入后与硬盘同步。即使sync_binlog设置为1,出现崩溃时也有可能表内容和binlog内容之间存在不一致性。
2、innodb_flush_log_at_trx_commit 这个很管用抱怨Innodb比MyISAM慢 100倍那么你大概是忘了调整这个值。默认值1的意思是每一次事务提交或事务外的指令都需要把日志写入flush硬盘这是很费时的。特别是使用电池供电缓存Battery backed up cache时。设成2对于很多运用特别是从MyISAM表转过来的是可以的它的意思是不写入硬盘而是写入系统缓存。日志仍然会每秒flush到硬 盘所以你一般不会丢失超过1-2秒的更新。设成0会更快一点但安全方面比较差即使MySQL挂了也可能会丢失事务的数据。而值2只会在整个操作系统 挂了时才可能丢数据。
3、ls(1) 命令可用来列出文件的 atime、ctime 和 mtime。
atime 文件的access time 在读取文件或者执行文件时更改的ctime 文件的create time 在写入文件更改所有者权限或链接设置时随inode的内容更改而更改mtime 文件的modified time 在写入文件时随文件内容的更改而更改ls -lc filename 列出文件的 ctimels -lu filename 列出文件的 atimels -l filename 列出文件的 mtimestat filename 列出atimemtimectimeatime不一定在访问文件之后被修改因为使用ext3文件系统的时候如果在mount的时候使用了noatime参数那么就不会更新atime信息。这三个time stamp都放在 inode 中.如果mtime,atime 修改,inode 就一定会改, 既然 inode 改了,那ctime也就跟着改了.之所以在 mount option 中使用 noatime, 就是不想file system 做太多的修改, 而改善读取效能

View file

@ -0,0 +1,13 @@
备库B和主库A之间维持了一个长连接。主库A内部有一个线程专门用于服务备库B的这个长连接。一个事务日志同步的完整过程如下
1.在备库B上通过change master命令设置主库A的IP、端口、用户名、密码以及要从哪个位置开始请求binlog这个位置包含文件名和日志偏移量
2.在备库B上执行start slave命令这时备库会启动两个线程io_thread和sql_thread。其中io_thread负责与主库建立连接
3.主库A校验完用户名、密码后开始按照备库B传过来的位置从本地读取binlog发给B
4.备库B拿到binlog后写到本地文件称为中转日志
5.sql_thread读取中转日志解析出日志里的命令并执行
由于多线程复制方案的引入sql_thread演化成了多个线程

View file

@ -0,0 +1,45 @@
#### 背景说明如下
为了安全mysql数据库安装在内网环境外网无法直连只能通过与数据库在同一个内网的、可以与外网通信的服务器连接即使用ssh隧道连接。
一般的第三方可视化客户端连接工具都可以配置ssh隧道。若使用命令行连接就需要使用命令建立隧道。
##### 建立隧道命令如下:
```
# 需要连接数据库的外网环境,执行下列命令
ssh -p {ssh_port} -i {rsa_file} -fNL {local_port}:{mysql_ip}:{mysql_port} {ssh_user}@{ssh_ip}
```
###### 命令详解:
* -p {ssh_port}: 指定跳板机器的ssh服务的端口也就是B服务器
* -i {rsa_file}:指定连接跳板机的ssh公钥由跳板机的ssh服务端生成如果不指定公钥或者公钥验证失败则会弹出密码进行登录。如果需要密码登录可以不填-i
* -f:告诉SSH客户端在后台运行也就是执行命令之后在进程监听需要关闭直接kill
* -N:只进行端口转发,不执行命令
* -L:指定连接服务的格式 [bind_address:]port:host:hostport
* {local_port}:本地监听的端口
* {mysql_ip}转发到的mysql的ip或域名远程mysql主机地址
* {mysql_port}转发到的mysql的端口
* {ssh_port}:跳板机的
* {ssh_user}跳板机的ssh用户名(如果为rsa登录则ras对应的用户名和ssh_user一致)
* {ssh_ip}跳板机的ip或域名
##### 连接数据库命令:
```
mysql -h127.0.0.1 -P {local_port} -u{mysql_user} -p
```
#### 举例说明
A需要连接数据库的外网服务器centos 8
B只有内网地址或只能被特定主机连接的数据库服务器。数据库连接为172.16.0.35:3306
C可以被A直连与B在同一个内网中/或可以连接B。公网地址为3.3.3.3连接公钥为rsa_pub.pem
###### 1、建立隧道
*A执行*
```
ssh -p 22 -i rsa_pub.pem -fNL 3320:172.16.0.35:3306 root@3.3.3.3
```
###### 2、查看本地监听端口
```
ss -anltp | grep 3320
```
###### 3、连接数据库
```
mysql -h 127.0.0.1 -P 3320 -u admin -p
```

View file

@ -0,0 +1,8 @@
#### 异步复制Asynchronous replication
MySQL默认的复制即是异步的主库在执行完客户端提交的事务后会立即将结果返给给客户端并不关心从库是否已经接收并处理这样就会有一个问题主如果crash掉了此时主上已经提交的事务可能并没有传到从上如果此时强行将从提升为主可能导致新主上的数据不完整。
#### 全同步复制Fully synchronous replication
指当主库执行完一个事务,所有的从库都执行了该事务才返回给客户端。因为需要等待所有从库执行完该事务才能返回,所以全同步复制的性能必然会收到严重的影响。
#### 半同步复制Semisynchronous replication
介于异步复制和全同步复制之间主库在执行完客户端提交的事务后不是立刻返回给客户端而是等待至少一个从库接收到并写到relay log中才返回给客户端。相对于异步复制半同步复制提高了数据的安全性同时它也造成了一定程度的延迟这个延迟最少是一个TCP/IP往返的时间。所以半同步复制最好在低延时的网络中使用。

View file

@ -0,0 +1,31 @@
要求:
1、主从mysql版本要一致
2、若版本不一致主版本要低于从
3、从头开始或主服务器数据备份从服务器恢复数据并从主备份所在位置进行服务
注意(都需要启动):
1、时间需要同步
2、配置文件
my.cnf
修改二进制日志存放位置安全log-bin=目录/文件
修改二进制文件的格式为binlog_format=mixed
修改服务id server-id=1
my.cnf
要从主服务器复制二进制日志所以从的二进制文件要关闭log-bin=OFF或注释掉
修改服务id与主服务器不同如 server-id=11
添加复制日志relay-log=目录/文件
只读read-only=on(仅限制不具备super权限用户无法执行的写操作)
3、主从复制的事务安全
在主服务器上配置sync_binlog=1(事务提交即同步)
1、主服务器执行创建一个有复制权限的用户并授权
grant replication slave, replication client on *.* to 'rep'@'从ip地址' identified by 'reppass';
flush plivileges;
2、备份主服务器上数据需要包含position信息在导出的数据文件头部
备份InnoDB存储引擎的数据库mysqldump --all-database --single-transaction -flush-logs --master-data=2 > 数据文件
备份MyISAM存储引擎的数据库mysqldump --all-database --lock-all-tables -flush-logs --master-data=2 > 数据文件
3、从服务器执行连接主服务器
change master to MASTER_HOST='主服务器ip' MASTER_USER='主服务器用户' MASTER_PASSWORD='密码' MASTER_PORT='端口' MASTER_LOG_FILE='主服务器二进制文件' MASTER_LOG_POS=从主服务器二进制文件位置读取
4、从服务器启动slave执行
start slave

View file

@ -0,0 +1,3 @@
索引是帮助数据库高效获取数据的*排好序*的*数据结构*
聚簇索引(聚集索引),索引与数据放在一起,索引结构的叶子节点保存了行数据
非聚簇索引,索引与数据不放在一起,索引结构的叶子节点指向了数据对应的位置

7
数据库/mysql/锁.md Normal file
View file

@ -0,0 +1,7 @@
*读锁* 也叫共享锁、S锁若事务T对数据对象A加上S锁则事务T可以读A但不能修改A其他事务只能再对A加S锁而不能加X锁直到T释放A上的S 锁。这保证了其他事务可以读A但在T释放A上的S锁之前不能对A做任何修改。
*写锁* 又称排他锁、X锁。若事务T对数据对象A加上X锁事务T可以读A也可以修改A其他事务不能再对A加任何锁直到T释放A上的锁。这保证了其他事务在T释放A上的锁之前不能再读取和修改A。
*表锁* 操作对象是数据表。Mysql大多数锁策略都支持是系统开销最低但并发性最低的一个锁策略。事务t对整个表加读锁则其他事务可读不可写若加写锁则其他事务增删改都不行。
*行级锁* 操作对象是数据表中的一行。是MVCC技术用的比较多的。行级锁对系统开销较大但处理高并发较好。