Files
2026-05-24 11:42:38 +08:00

14 KiB
Raw Permalink Blame History

tags, create time
tags create time
MySQL
安装
Docker
配置
2026-05-16 00:00

MySQL 安装与初始化

概述

本文系统讲解 MySQL Community Edition 的安装部署和初始化配置,涵盖三种主流方式:Docker Compose(推荐开发环境)、YUM/RPM 包安装、通用二进制包安装。同时深入解析 my.cnf 配置文件的核心参数体系,以及 mysql_install_db 初始化时的底层行为。

[!TIP] 学习建议

  1. 初学者优先掌握 Docker Compose 方式,快速搭建可复现的开发环境;
  2. 运维/生产场景参考二进制安装流程,理解服务初始化的完整链条;
  3. my.cnf 参数部分按优先级阅读,先吃透 InnoDB 和网络两大块,日志和 Binlog 可在后续进阶时补充。

思考题:为什么 InnoDB Buffer Pool 通常建议设为物理内存的 50%~70%,而不是 90%?(答案见下文 InnoDB 参数段落的注释)

Docker Compose 方式(推荐开发环境)

这是最轻量且可复现的方案,适合日常开发和 CI 测试。

version: '3.8'
services:
  mysql:
    image: mysql:8.0
    container_name: mysql-dev
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword        # 首次启动自动创建 root 用户
      MYSQL_DATABASE: app_db                   # 自动创建初始数据库
      MYSQL_USER: app_user                     # 创建普通应用账户
      MYSQL_PASSWORD: app_password             # 该账户对 MYSQL_DATABASE 拥有完全权限
    ports:
      - "3306:3306"                            # 宿主机 3306 → 容器内 3306
    volumes:
      - ./init-db:/docker-entrypoint-initdb.d  # 首次启动自动执行 SQL
      - mysql-data:/var/lib/mysql              # 持久化数据(容器删除后不丢失)
      - ./my-custom.cnf:/etc/mysql/conf.d/my.cnf # 覆盖默认配置
    command: >
      --character-set-server=utf8mb4                    # 统一字符集
      --collation-server=utf8mb4_unicode_ci             # 排序规则(不区分大小写)
      --default-authentication-plugin=mysql_native_password  # 兼容旧版客户端认证
      --max-connections=500                             # 最大并发连接数
      --innodb-buffer-pool-size=256M                    # 开发机无需太大

volumes:
  mysql-data:

启动与常用操作

docker compose up -d       # 后台启动
docker compose down        # 停止并移除容器(保留 volume)
docker compose logs -f     # 查看实时日志
docker compose exec mysql mysql -u root -p  # 进入容器内客户端
docker compose ps          # 查看容器状态
docker compose restart     # 重启(配置变更后适用)

[!QUESTION] 生产环境应该硬编码密码吗? 当然不。上述 docker-compose.yml 中的明文密码仅适用于本地开发。 生产环境应使用 Docker Secrets、环境变量文件 .env 或密钥管理工具(如 HashiCorp Vault)来注入凭据。

# .env 文件示例(加入 .gitignore!)
MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASS}
MYSQL_DATABASE=myapp_prod

Docker Compose 会自动将 ${VAR} 替换为环境变量值。

init-db 目录妙用

docker-entrypoint-initdb.d/ 下只要是 .sql 或 .sh 脚本,会在数据库首次启动时按字母序自动执行:

文件类型 执行时机 典型用途
.sql 首次初始化 DDL建表、默认数据、权限分配
.sh 首次初始化 调用 mysql CLI 执行动态逻辑

[!WARNING] 注意

  • 容器已有数据时,init-db 脚本不会被重新执行。修改脚本后需删除 volume 重建:docker compose down -v && docker compose up -d
  • .sh 脚本中若需连接 MySQL,务必等待 ready(可通过 docker compose wait 或健康检查机制)

二进制安装(生产环境参考)

对于需要精细控制的场景,官方推荐的两种方式:YUM/RPM 包适合标准发行版;通用二进制包提供最大灵活性。

方式一:YUM/RPM(CentOS / RHEL / Amazon Linux)

# 1. 下载 YUM 仓库配置(以 EL9 为例)
sudo rpm -Uvh https://dev.mysql.com/get/mysql80-community-release-el9-3.noarch.rpm

# 2. 安装 MySQL Server
sudo yum install mysql-server -y

# 3. 启动服务并设置开机自启
sudo systemctl start mysqld
sudo systemctl enable mysqld

# 4. 获取临时 Root 密码(首次安装后打印到日志)
sudo grep 'temporary password' /var/log/mysqld.log

# 5. 安全加固(修改默认密码、移除匿名账户等)
sudo mysql_secure_installation

[!TIP] 临时密码在哪? MySQL 8.0 首次启动时会在 /var/log/mysqld.log 中生成一个随机临时密码。 找到类似 A temporary password is generated for root@localhost: xxxxxxxx 的行,使用该密码登录 mysql_secure_installation。

方式二:通用二进制包(跨发行版兼容)

适用于非标准发行版或需要自定义目录结构的场景:

# 1. 下载并解压(替换实际版本号)
wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.xx-linux-glibc2.28-x86_64.tar.xz
tar -xvf mysql-8.0.xx-linux-glibc2.28-x86_64.tar.xz
sudo mv mysql-8.0.xx-linux-glibc2.28-x86_64 /usr/local/mysql

# 2. 创建专用系统用户(不建议用 root 运行 MySQL)
cd /usr/local/mysql
sudo groupadd mysql
sudo useradd -r -g mysql -s /bin/false mysql

# 3. 设置权限 + 初始化数据目录
sudo chown -R mysql:mysql .
sudo bin/mysqld --initialize --user=mysql --datadir=/data/mysql

# 4. 配置文件(可选,放在 /etc/my.cnf)
#    指定 basedir=/usr/local/mysql 和 datadir=/data/mysql

# 5. 初始化 SSL 证书(MySQL 8.0 必需)
sudo bin/mysql_ssl_rsa_setup --datadir=/data/mysql

# 6. 启动服务
sudo bin/mysqld_safe --user=mysql &

# 7. 验证登录
sudo bin/mysql -u root -p

[!QUESTION] caching_sha2_password vs mysql_native_password? MySQL 8.0 将默认认证插件从 mysql_native_password 切换为 caching_sha2_password:

  • caching_sha2_password(新默认):更强的 SHA2 加密缓存机制,推荐所有新版客户端使用
  • mysql_native_password(旧版):兼容性最好,老旧语言驱动可能不支持 SHA2

如果你的连接报 client does not support authentication protocol 错误,临时解决方案是切换回旧版认证:

ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'new_password';

但长期方案应是升级客户端库。

配置文件 my.cnf

配置文件加载优先级

MySQL 按以下顺序查找配置文件,后读取的覆盖先读取的(命令行参数始终最高):

graph LR
    E["~/.my.cnf"] --> D["$MYSQL_HOME/my.cnf"]
    D --> C["/etc/mysql/my.cnf"]
    C --> B["/etc/my.cnf"]
    B --> A["--defaults-file=<指定路径>"]
    A --> F["命令行参数"]
    F -.->|"最终生效"| Z["生效配置"]

[!NOTE] 关键理解

  • /etc/my.cnf 通常是入口文件,内部可能 !include 其他目录;
  • --defaults-file 是唯一使用的配置文件,跳过所有默认路径(极少场景使用);
  • Docker 中常用 --config 或 conf.d/ 目录方式挂载自定义配置。

核心配置参数详解

MySQL 配置集中在 [mysqld] 段落下。按功能域分类如下:

网络

# ==================== 网络 ====================
port                            = 3306              # MySQL 默认端口
bind-address                    = 0.0.0.0           # 监听所有网卡(Docker 内用 127.0.0.1)
max_connections                 = 500               # 最大并发连接数
max_connect_errors              = 1000000           # 同一主机连续中断次数上限,超限将被 block_host

字符集

# ==================== 字符集 ====================
character-set-server            = utf8mb4           # 支持 emoji 的完整 UTF-8 实现
collation-server                = utf8mb4_unicode_ci # 不区分大小写的排序规则

为什么用 utf8mb4 而非 utf8? MySQL 的 utf8 只支持最多 3 字节,无法存储 emoji;utf8mb4 才是标准 UTF-8(最长 4 字节)。

InnoDB 存储引擎

# ==================== InnoDB ====================
innodb_buffer_pool_size         = 1G          # 缓存数据和索引的物理内存占比
innodb_log_file_size            = 512M        # Redo Log 文件大小
innodb_flush_log_at_trx_commit  = 1           # ACID 一致性级别控制
innodb_flush_method             = O_DIRECT    # 绕过 OS page cache,避免双重缓冲
innodb_file_per_table           = 1           # 每张表独立 .ibd 文件
innodb_io_capacity              = 2000        # SSD 建议调高,HDD 约 100~200

关键概念解释:

参数 原理 调整建议
innodb_buffer_pool_size InnoDB 的核心缓存区域,存放数据页和索引页 物理内存的 50%~70%——为 OS 和其他进程预留空间,占满 90% 反而导致性能下降
innodb_log_file_size Redo Log 保证持久性(WAL 机制) 越大容纳未刷盘事务越多,但重启恢复越慢;512M 是通用起点
O_DIRECT 直接 I/O 模式 启用后 MySQL 自己管理 Buffer Pool,不再经过 OS Cache(避免双重缓冲浪费)

慢查询日志

# ==================== 日志 ====================
slow_query_log                  = 1
slow_query_log_file             = /var/log/mysql/slow.log
long_query_time                 = 2
log_error                       = /var/log/mysql/error.log

使用方式: 启用后可以通过 mysqldumpslow 分析或直接用文本工具查看超时查询:

# 找出执行时间最长的 10 条
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log

# 实时追踪慢查询(运维调试利器)
tail -f /var/log/mysql/slow.log

Binlog(二进制日志)配置

Binlog 是 MySQL 最核心的日志类型,用于主从复制和数据恢复:

# ==================== Binlog ====================
server_id                       = 1              # 集群内唯一标识(1~2^32-1)
log_bin                         = /var/log/mysql/mysql-bin
binlog_format                   = ROW            # 记录每一行变更明细
binlog_expire_logs_seconds      = 604800         # 7 天后自动清理
max_binlog_size                 = 100M           # 单文件上限(实际可能略超)
gtid_mode                         = ON           # 全局事务 ID,简化主从切换
enforce_gtid_consistency        = ON             # 只允许 GTID 安全的事务

[!TIP] Binlog Format 对比

格式 内容 优点 缺点
STATEMENT 原始 SQL 文件小,审计直观 函数调用可能导致主从不一致
ROW(推荐) 每行变更前后值 数据一致性最强 文件较大
MIXED 混合模式 兼顾两者 逻辑复杂,难以预测

结论:生产环境统一用 ROW,现代磁盘成本已不再是瓶颈。

[!QUESTION] innodb_flush_log_at_trx_commit 怎么选?

值 行为 丢失数据风险 性能
1 每次事务 commit 都刷盘 零(ACID 完全符合) 最低
2 每次 commit 写入 OS 缓存,每秒刷盘 系统断电丢失 < 1 秒 高
0 每秒都写并刷盘,commit 仅写入缓冲区 可能丢多秒数据 最高

建议:金融/支付类业务必须用 1;内容类业务可以用 2 换取性能提升。

mysql_install_db 初始化原理

当首次启动 MySQL(或手动执行 mysql_install_db)时,底层会完成以下几件事:

flowchart TD
    S["mysqld 启动"] --> I["数据目录检查"]
    I -->|为空| D["执行 mysql_install_db"]
    I -->|非空| C["跳过初始化,直接加载现有数据"]

    D --> A["创建系统数据库"]
    A --> A1["mysql schema — 用户权限、角色、插件"]
    A --> A2["sys schema — 性能分析视图集合"]
    A --> A3["performance_schema — 运行时指标采集"]
    A --> A4["information_schema — SQL 元数据虚拟表"]

    A --> B["创建管理员账户"]
    B --> B1["root@localhost — 超级管理员"]
    B --> B2["使用 caching_sha2_password 认证"]

    A --> E["写入其他系统文件"]
    E --> E1["ibdata1 — InnoDB 系统表空间"]
    E --> E2["auto.cnf — Server UUID"]

    C --> F["加载 my.cnf 配置并监听端口"]

逐段拆解:

步骤 说明 常见关联问题
创建 system schemas mysql 存权限,performance_schema 供性能监控,information_schema 是 SQL 标准提供的元数据字典 删了这些库会导致实例无法正常运行
创建 root 账户 8.0 不再允许匿名访问 test 库;密码通过临时日志输出而非自动设为空 忘记临时密码 → 删除 data dir 重新初始化
初始化 InnoDB 表空间 ibdata1 存放系统表和 undo log;ib_logfile* 是 Redo Log(两份互为镜像) Redo Log 损坏 → 实例无法启动
写入 auto.cnf 包含唯一的 Server UUID,主从复制和 GTID 依赖此标识 克隆虚拟机未重置 UUID → 主从冲突

数据目录结构

初始化完成后,数据目录的组织方式如下:

/var/lib/mysql/  (datadir 根目录)
├── ibdata1              # InnoDB 系统表空间(存放系统表 + undo log)
├── ib_logfile0          # Redo Log 文件 1
├── ib_logfile1          # Redo Log 文件 2(与 1 互为镜像)
├── auto.cnf             # Server UUID(UUID 不变,主从复制不冲突)
├── mysql/               # 系统数据库(user, role, db, columns_priv 等 .ibd 文件)
├── performance_schema/  # 运行时性能数据采集
├── sys/                 # 基于 performance_schema 的友好视图
├── app_db/              # 每个用户数据库一个目录
│   ├── users.ibd        # 单表独立表空间(innodb_file_per_table=1)
│   └── orders.ibd
└── relay-log.index      # 主从复制的中继日志索引(仅作为 replica 时存在)

关联笔记