MySQL 是一款最流行的开源关系型数据库,最初由瑞典的 MySQL AB 公司开发,目前已被 Oracle 收购,现在比较流行的分支包括了 MariaDB 和 Percona。
现在来看,MySQL 被收购之后,实际上添加了很多不错的特性,解掉了很多之前未解的问题,而现在 MariaDB 离主干的特性越来越远;而 Percona 据说为了保证质量是不接受社区提供的代码的,不过其提供的工具却是极好的^_^
在此,简单介绍,二进制安装、源码编译安装、单实例以及多实例的启动、常见的调试方法。
安装
对于 Ubuntu、CentOS 这样的发行版本可以直接通过命令行安装,从 CentOS 7 之后,实际安装的是 MariaDB ,也可以通过 Oracle 提供的官方 YUM repository ,然后安装 MySQL Community Server,下面以 CentOS 为例。
# yum install -y mariadb-server mariadb ← 安装MariaDB
# systemctl start mariadb ← 启动server
# systemctl enable mysqld ← 设置开机启动
# rpm -Uvh http://dev.mysql.com/get/mysql-community-release-el7-5.noarch.rpm ← 安装仓库
# yum install mysql-community-server ← 安裝社区版
# cat << EOF > /etc/my.cnf ← 设置配置文件
[client]
password = new_password
port = 5506
socket = /tmp/mysql-5506.sock
[mysqld]
user = mysql
port = 5506
socket = /tmp/mysql-5506.sock
basedir = /usr
datadir = /home/foobar/databases/data-5506
pid-file = /home/foobar/databases/data-5506/mysqld.pid
EOF
# /usr/sbin/mysqld --initialize-insecure --basedir=/usr --user=mysql \ ← 初始化数据,可通过空白密码登陆
--datadir=/home/foobar/databases/data-5506
# systemctl start mysqld ← 启动server
$ mysql -h 127.1 ← 直接登陆
mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'new_password'; ← 修改密码
mysql> FLUSH PRIVILEGES;
通过 RPM 包安装时,默认是保存到 /var/lib/mysql
目录下。另外,需要注意,需要保证上级目录权限为 755,否则可能会报 Permission denied 错误。
当然也可以从 MySQL 官网、MariaDB 官网 或者 Percona 官网 下载相应的安装包,或者源码。对于 CentOS 7 来说,可以从 MySQL Community Downloads 下载 server、client、common、libs 对应的 RPM 包,也可从 sohu 镜像 下载,然后安装即可。
密码配置
如果没有手动初始化数据直接启动,那么会将 root 密码打印到日志中,然后可以直接登陆;也可以修改配置文件跳过认证,也就是添加 skip-grant-tables
选项。
----- 不建议使用如下方式修改密码
mysql> SET PASSWORD=PASSWORD('Root1234@');
mysql> FLUSH PRIVILEGES;
----- 可以使用如下方式修改,且不需要FLUSH,建议时候后者
mysql> SET password='Root1234@';
mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'Your@123NewPassword';
在 8.X 版本之后会初始化一个默认的密码,可以通过 grep 'temporary password' /var/log/mysqld.log
命令查看,或者第一次启动 mysqld 服务时添加 --initialize-insecure
参数无密码登录。
登录后需要修改密码,否则执行其它 SQL 会报错,注意,对密码的复杂度是有要求的。
编译安装
还是直接从官网下载源码即可,假设直接解压到 /home/foobar/Workspace/mysql
并将安装目录设置为 /opt/mysql-5.7
。
下面介绍如何通过源码进行安装,最简单的是通过 BUILD/compile-ARCH
脚本进行编译,当然,可以选择使用 autotools 或者 CMake 指定相应的参数进行安装,在此通过 CMake 安装。
通过 CMake 编译时,有两种编译方式:A) 内部编译,即在源码内部编译,此时会有一些编译产生的临时文件,影响代码结构;B) 外部编译,不会影响原代码的结构,在此采用外部编译。
所谓的外部编译,就是在一个新的目录下进行编译,此时编译的中间文件不会影响到源码的目录结构。源码可以直接从官网下载,三个发行版本的源码编译方式都类似,在此以 MySQL 为例。
----- 安装依赖包,以及相关的开发库
# yum install gcc-c++ g++ ncurses-devel readline-devel zlib-devel
----- 源码安装
$ tar -xf mysql-boost-x.x.xx.tar.bz2
$ cd mysql-boost-x.x.xx && mkdir build && cd build ← 新建编译的目录
$ cmake .. \
-DCMAKE_INSTALL_PREFIX=/opt/mysql-5.7 \ ← 安装根目录
-DMYSQL_DATADIR=/opt/data \ ← 数据文件的默认路径
-DSYSCONFDIR=/etc \ ← 配置文件目录,默认/etc/my.cnf
\
-DWITH_INNOBASE_STORAGE_ENGINE=ON \ ← 使用InnoDB存储引擎
-DWITH_BLACKHOLE_STORAGE_ENGINE=ON \ ← 黑洞存储引擎
-DWITH_EXAMPLE_STORAGE_ENGINE=ON \ ← 使用存储示例
\
-DWITHOUT_FEDERATED_STORAGE_ENGINE=ON \ ← 取消一些不常用的存储引擎
-DWITHOUT_PARTITION_STORAGE_ENGINE=ON \
-DWITHOUT_ARCHIVE_STORAGE_ENGINE=ON \ ← 日志记录和聚合分析,不支持索引
\
-DMYSQL_TCP_PORT=3306 \ ← 默认使用的端口号
-DMYSQL_UNIX_ADDR=/tmp/mysql.sock \ ← 默认套接字文件路径
-DMYSQL_USER=mysql \ ← 默认使用的用户
\
-DEXTRA_CHARSETS=all \ ← 是否支持额外的字符集
-DDEFAULT_CHARSET=utf8 \ ← 默认编码机制
-DDEFAULT_COLLATION=utf8_general_ci \ ← 设定默认语言的排序规则
\
-DWITH_READLINE=ON \ ← 使用readline库,支持类shell的快捷键以及历史命令
-DENABLED_LOCAL_INFILE=ON \ ← 支持批量导入
-DWITH_LIBWRAP=OFF \ ← 是否可以基于WRAP实现访问控制
-DWITH_SSL=system \ ← 支持ssl会话,实现基于ssl的数据复制
-DWITH_ZLIB=system \ ← 压缩库
-DWITH_EMBEDDED_SERVER=OFF \ ← 取消embedded模式
-DENABLE_PROFILING=ON \ ← 启用性能分析功能
-DCMAKE_BUILD_TYPE=Debug \ ← 打开调试选项
-DWITH_SAFEMALLOC=OFF \ ← 关闭safemalloc,经常会报错误,5.7不需要
-DWITH_BOOST=../boost ← 5.7需要该boost库,直接下载含该库的包
----- 编译源码并安装
$ make -j`cat /proc/cpuinfo | grep 'processor' | wc -l` ← 可以简单使用make并行编译,指定并发
# make install ← 安装
----- 设置环境
$ export PATH=$PATH:/opt/mysql-5.7/bin ← 设置环境变量
$ vi /etc/ld.so.conf && sudo ldconfig ← 设置动态库目录
$ mysql_config ← 可用于查看环境配置,很多MySQL软件依赖该命令
----- 源码安装时最好将build目录中的如下文件保存下
# cat install_manifest.txt | xargs rm ← 直接手动删除
注意,除了上述列举的选项外,可通过 cmake .. -LH
查看当前版本所支持的选项,如要重新编译可以直接运行 make clean; rm CMakeCache.txt; cmake ..
即可。
另外,MariaDB 不支持使用 -DWITH_DEBUG=1
,应该使用 -DCMAKE_BUILD_TYPE=Debug
;更多 MySQL 编译选项可以参考 Source Configration Options,通过 make
编译时,可以通过 -j
选项多进程编译。
源码编译完成后,默认会将程序保存在 sql/mysqld
目录下,然后即可以通过 make install
将其安装在 /opt/mysql-5.7
目录下,为了方便运行,可以将 /opt/mysql-5.7/bin
添加到环境变量 PATH
中。
简单配置
MySQL 的配置文件保存在 /etc/my.cnf
,包括了 datadir
、pid-file
等的设置。另外,安装完老版本 root 密码为空,可以通过 mysql_secure_installation
来进行一些安全的配置,尤其是线上服务器,包括删除 test
数据库和默认创建的匿名用户。
为了方便登陆,可以设置 ~/.my.cnf
,仅为了本地方便登陆,线上生产环境一定不要配置。
[client]
user=root
password=YOUR_PASSWORD
socket=/tmp/mysql.sock
host=127.1
可以通过 mysqld --verbose --help | head -15
查看配置文件的默认加载顺序,当然,也可以直接通过 mysql --help | grep my.cnf
过滤进行查看;配置文件中通过 #
表示注释。
运行实例
如下,简单以源码安装时的路径为例,如果是通过类似 YUM 安装的,则可以直接替换可执行文件的路径即可,不再赘述。
数据初始化
第一次运行时需要做些初始化操作,主要是需要创建一些所必须的系统数据库以及相应的表,例如 mysql
、preformance_schema
、information_schema
等。
----- 5.6以及之前的版本
$ /opt/mysql-5.6/script/mysql_install_db --no-defaults --basedir=/opt/mysql-5.6 \
--datadir=/home/foobar/Workspace/mysql/data --user=mysql
----- 5.7以及之后的版本,使用--initialize时密码保存在~/.mysql_secret
$ /opt/mysql-5.7/bin/mysqld --initialize-insecure --basedir=/opt/mysql-5.7 \
--datadir=/home/foobar/Workspace/mysql/data --user=mysql
$ /opt/mysql-5.7/bin/mysql_install_db --no-defaults --basedir=/opt/mysql-5.7 \
--datadir=/home/andy/Workspace/databases/mysql/data-mysql
如果不通过 --user
参数指定用户名,则使用默认的当前用户,此时不需要设置 datadir
目录的权限,否则需要设置相应权限。
basedir
指定 MySQL 的安装目录;datadir
指定数据的存放位置;可以使用 --defaults-file=my.cnf
指定默认的配置文件,可以使用相对路径,默认相对于 datadir
。在 share
子目录下,包含了一些配置文件,以及初次安装运行需要的初始数据库文件比如 mysql_system_tables.sql
。
注意,如果要使用参数指定默认配置文件,则 --defaults-file
选项应该放置在第一个参数,而且 datadir
、basedir
必须使用绝对路径。
单实例运行
新建配置文件 data/my.cnf
(可以为空),并通过如下命令启动/停止/连接服务器。
----- 1. 切换到工作目录
$ cd /home/foobar/Workspace/mysql
----- 2. 启动单个MySQL实例,前台运行,如果要后台运行直接添加&即可
$ /opt/mysql-5.7/bin/mysqld --defaults-file=data/my.cnf \
--datadir=/home/foobar/Workspace/mysql/data \
--basedir=/opt/mysql-5.7 --skip-networking --debug
$ /opt/mysql-5.7/bin/mysqld_safe --defaults-file=data/my.cnf \
--datadir=/home/foobar/Workspace/mysql/data \
--basedir=/opt/mysql-5.7 --skip-networking --debug &
----- 3. 如下命令连接到数据库,5.6之前为密码为空,5.7密码保存在~/.mysql_secret
$ /opt/mysql-5.7/bin/mysql -uroot -p'init-password' -S /tmp/mysql.sock
----- 4. 可以通过如下命令关闭、查看状态
$ /opt/mysql-5.7/bin/mysqladmin -uroot -p'init-password' shutdown
$ /opt/mysql-5.7/bin/mysqladmin -uroot -p'init-password' status
在通过上述命令启动服务器时,添加了 skip-networking
参数,也就是不启动 TCP
监听端口,只能通过 sock
连接。
需要注意的是,如果不使用 --defaults-file
选项,mysqld
会自动读取 /etc/my.cnf
配置文件,如果默认值与期望值不符,从而可能会导致部分错误,当然可以删除该配置文件,不过不建议。
推荐 可以将对应的启动、关闭命令设置为 alias ,这样可以简化启动方式,同时仍然可以动态添加参数,如直接再在命令的末尾添加 --debug
。
多实例运行
多实例主要是端口以及保存的数据目录不同,通过简单设置这些参数,可以在同一台 server 上启动多个实例,下面启动一个端口号为 3307
的实例,其中配置文件 mysql3307.cnf
的内容如下。
$ cat mysql3307.cnf
[mysqld]
port = 3307
server-id = 3307
basedir = /opt/mysql-5.7
socket = /tmp/mysql3307.sock
pid-file = /home/foobar/Workspace/mysql/data3307/mysql3307.pid
datadir = /home/foobar/Workspace/mysql/data3307
然后,可以通过如下命令设置并启动一个新的 MySQL 实例。
----- 1. 创建目录
$ cd /home/foobar/Workspace/mysql && mkdir data3307
----- 2. 如上,初始化实例
$ /opt/mysql-5.7/bin/mysqld --initialize-insecure --basedir=/opt/mysql-5.7 \
--datadir=/home/foobar/Workspace/mysql/data3307 --user=mysql
----- 3. 启动实例
$ /opt/mariadb/bin/mysqld --defaults-file=data3307/mysql3307.cnf
----- 4. 连接数据库
$ mysql -uroot -h127.1 -P3307
----- 5. 关闭数据库
$ /opt/mariadb/bin/mysqladmin -uroot -S /tmp/mysql3307.sock shutdown
对于多实例,可以通过上述的方法创建实例,不过管理操作还是略微有点复杂,实际上可以直接通过 mysqld_multi
命令管理,通过 mysqld_multi --example
查看示例配置文件,或者使用 multi.cnf
。
$ cat multi.cnf
[mysqld_multi]
mysqld = /opt/mysql-5.7/bin/mysqld
mysqladmin = /opt/mysql-5.7/bin/mysqladmin
user = root
[mysqld3307]
socket = /tmp/mysql3307.sock
port = 3307
pid-file = /home/foobar/Workspace/mysql/data3307/mysql3307.pid
datadir = /home/foobar/Workspace/mysql/data3307
basedir = /opt/mysql-5.7
server-id=3307
[mysqld3308]
socket = /tmp/mysql3308.sock
port = 3308
pid-file = /home/foobar/Workspace/mysql/data3308/mysql3308.pid
datadir = /home/foobar/Workspace/mysql/data3308
basedir = /opt/mysql-5.7
server-id=3308
如下是一些常见的操作。
$ cd /home/foobar/Workspace/mysql
$ /opt/mysql-5.7/bin/mysqld_multi --defaults-file=multi.cnf report ← 查看多个实例状态
$ /opt/mysql-5.7/bin/mysqld_multi --defaults-file=multi.cnf start
$ /opt/mysql-5.7/bin/mysqld_multi --defaults-file=multi.cnf stop
调试程序
如果要调试需要在编译时添加 -DCMAKE_BUILD_TYPE=Debug
选项,可以通过 gdb
或者使用 dbug
打印调试信息。
使用 GDB
可以通过如下的方式加载程序,然后运行。
$ gdb -args /opt/mariadb/bin/mysqld --defaults-file=......
(gdb) run
如果 MySQL 已经启动,此时可以通过 gdb
的 attach PID
命令来调试,一般会阻塞在系统调用 poll()
处;调试结束通过 detach
命令退出。注意,要先 设置断点 。
如果通过 CMake 进行编译,往往会采用绝对路径,可以通过 readelf -p .debug_str
查看,此时设置/查看断点时应该使用绝对路径。可以修改/添加如下文件。
$ cat CMakeLists.txt # 添加如下内容
... ...
CONFIGURE_FILE(
"${PROJECT_SOURCE_DIR}/gcc_debug_fix.sh.in"
"${PROJECT_BINARY_DIR}/gcc_debug_fix.sh"
@ONLY)
... ...
$ cat cmake/mysql_add_executable.cmake # 添加如下内容
ADD_EXECUTABLE(... ...)
SET_TARGET_PROPERTIES(${target} PROPERTIES
RULE_LAUNCH_COMPILE "${PROJECT_BINARY_DIR}/gcc_debug_fix.sh")
... ...
$ cat gcc_debug_fix.sh.in # 添加如下文件,需要设置可执行
#!/bin/sh
PROJECT_BINARY_DIR="@PROJECT_BINARY_DIR@"
PROJECT_SOURCE_DIR="@PROJECT_SOURCE_DIR@"
# shell script invoked with the following arguments
# $(CXX) $(CXX_DEFINES) $(CXX_FLAGS) -o OBJECT_FILE -c SOURCE_FILE
# extract parameters
SOURCE_FILE="${@: -1:1}"
OBJECT_FILE="${@: -3:1}"
COMPILER_AND_FLAGS=${@:1:$#-4}
# make source file path relative to project source dir
SOURCE_FILE_RELATIVE="${SOURCE_FILE:${#PROJECT_SOURCE_DIR} + 1}"
# make object file path absolute
OBJECT_FILE_ABSOLUTE="$PROJECT_BINARY_DIR/$OBJECT_FILE"
cd "$PROJECT_SOURCE_DIR"
# invoke compiler
exec $COMPILER_AND_FLAGS -c "${SOURCE_FILE_RELATIVE}" -o "${OBJECT_FILE_ABSOLUTE}"
编译方式仍如上所示,相关内容可以参考 Make gcc put relative filenames in debug information 。
调试技巧
为了比较好的查看变量内容,可以设置如下。
(gdb) set print vtbl on ← 用比较规整的格式来显示虚函数表
(gdb) ptype obj/class/struct ← 查看obj/class/struct的成员,但是会把基类指针指向的派生类识别为基类
(gdb) set print object on ← 查看派生对象的真实类名
(gdb) set print pretty on ← 以树形打印对象的成员,可以清晰展示继承关系
链接到 mysqld
后,会阻塞在 poll()
,然后设置调试入口,在此简单列举一下常见的调试入口点。
handle_connections_sockets() @ mysqld.cc
等待接收处理新的链接。
do_handle_one_connection() @ sql_connect.cc
接下来的处理过程为处理链接,注意该处理函数与链接的处理方式有关。
do_command() @ sql_parse.cc; dispatch_command() @ sql_parse.cc
接着是处理接收到的 SQL,其中有一个变量 THD thd @ sql_class.h 会经常使用,该结构体中包含了当前线程的相关信息。
如下是简单的在 dispatch_command()
断点处打印的信息,用 @
简单标示断点信息。
# @ dispatch_command()
(gdb) p thd.net ← 查看网络的信息
(gdb) p packet ← 请求的命令
使用 DBUG
对于 MySQL 需要在编译时添加调试选项 -DCMAKE_BUILD_TYPE=Debug
,然后在启动时使用 --debug
参数,默认会启动所有的调试选项,调试的信息会保存在 /tmp/mysqld.trace
文件中。
可以在启动时使用 --debug[=debug_options]
添加调试选项,默认值是 d:t:i:o,/tmp/mysqld.trace
,选项的格式为 [field1]:[field2]...
每个 field
之间用冒号分割,各个 field
的内容为 flag[,modifier,modifier...]
。
常用的标记有:
d
允许对当前状态从DBUG_<N>宏输出。可能跟着一列关键词,这些关键词仅对那些带有关键词的DBUG宏选择输出。
一个空的关键词列意味着对所有宏输出。
t
允许函数调用/退出跟踪行。可能跟着一个给出最大跟踪级别的数字列(只含一个修改量),超过这个数字,
调试中或跟踪中的宏不能产生任何输出。 默认为一个编译时间选项。
i
对调试或跟踪输出的每一行用PID或线程ID识别进程。
o
重定向调试器输出流到指定文件,默认输出是stderr 文件。
注意:调试输出选项是在 mysqld_main()
中的 handle_options()
返回后开始输出的,之前应该是还没有初始化,另外,在运行的时候也可以通过,如下的方式修改,日志的保存位置可以查看该变量。
mysql> SHOW VARIABLES LIKE 'debug';
mysql> SET GLOBAL debug = 'd:t:i:o,/tmp/mysqld.trace';
mysql> SET SESSION debug = 'd:t:i:o,/tmp/mysqld.trace';
其中,DBUG_RETURN()
后面的数字对应的是行号。
与 dbug
相关内容还可以参考 dbug 源码,其中有 example.c
文件,可以将其复制到 src
目录下,最简单的方式是直接通过 gcc example.c dbug.c
编译,编译后运行将直接输出到终端上;当要取消调试选项时只需要添加宏 #define DBUG_OFF
。
注意:MySQL 的 dbug
库是经过修改的,会有稍微的差别。
打印执行的SQL
通常在测试某些功能时,希望可以直接输出所执行的 SQL,通常可以使用如下的两种方式。
general log
可以通过 general_log
打开日志,记录所有的执行日志,当然只用于测试,生产环境不要打开。
mysql> show global variables like 'general%';
mysql> set global general_log=1; # 打开查询日志
默认日志保存在 $datadir/$general_log_file
文件中,另外,slow query log
用于记录执行时间超过 long_query_time
的 SQL 。
tcpdump
可以通过 tcpdump
截取 MySQL 报文,假设使用的时 lo
接口;需要注意的是:使用本地连接可能会直接用 Sock 链接,通过客户端创建连接时需要指定 -h 127.1
。
# tcpdump -i lo -s 0 -l -w - dst port 3306 | strings
其中的选项为:
-s 0 将截取报文的长度设置为默认值 65536 bytes
-i lo 指定监听的网络接口
-l 输出变为缓冲行形式
-w 直接将包写入文件中,并不分析和打印出来,在此输出到标准输入
# tcpdump -i lo -s 0 -l -w - dst port 3306 | strings | perl -e '
while(<>) { chomp; next if /^[^ ]+[ ]*$/;
if(/^(SELECT|UPDATE|DELETE|INSERT|SET|COMMIT|ROLLBACK|CREATE|DROP|ALTER)/i) {
if (defined $q) { print "$q\n"; }
$q=$_;
} else {
$_ =~ s/^[ \t]+//; $q.=" $_";
}
}'
参考
其中调试时的相对路径设置可以参考 stackflow 或者 [本地文档](/reference/databases/mysql/make gcc put relative filenames in debug information.mht) 。 –>