先说个很多人问过我的问题:为什么放着好好的联网在线安装不用,非要折腾离线安装MariaDB?答案通常绕不开这几种场景——客户机房是纯内网环境,跟外网物理隔离;或者公司安全策略严格,生产服务器不允许接入公网;再就是内网源里的软件包版本太老,业务上又必须用特定版本的MariaDB。我在实施项目时就遇到过多次这种局面,与其到处找别人打包好的现成东西,不如自己掌握一套完整可靠的离线部署方法。这篇就基于我的实操经验,把Linux离线安装MariaDB的完整链路拆开揉碎讲清楚,从备包、传包、装包到初始化、调优、排障,一次讲透。
1. 离线安装的开局条件:为什么优先选二进制tar包
先明确一个问题——离线安装MariaDB有哪几条路可走?大概有三种:离线RPM(或deb)包安装、源码编译安装、通用二进制tar包安装。很多人一上来就去找RPM离线包,觉得跟yum安装最像,最省事。但实际动手后会发现,RPM方式最大的坑在于依赖关系极其繁琐,尤其MariaDB的server包会牵扯出一堆perl、libaio、ncurses等依赖包,在纯内网环境里挨个补齐依赖非常折磨人。
我推荐的做法是直接用官方提供的通用二进制tar包。这种包是官方在固定glibc版本下预编译好的,解压后不需要编译,改改配置就能初始化启动,对离线场景极其友好。跟源码编译相比,它省去了cmake、gcc等一整套编译工具链的依赖,也不用担心编译过程中缺某个开发库导致功亏一篑。
选择二进制tar包还有个额外好处:同一个包可以在多台同架构的服务器上反复使用。我在项目实施中拿到一台测试机验证完毕后,直接把整个包拷贝到其他几台服务器,重复同样的初始化步骤即可,效率比逐台编译或逐个装RPM高得多。当然前提是CPU架构要一致,x86_64的包不能用在ARM架构的机器上,这点第一章节强调一下。
需要说明的是,这不是说RPM离线包完全不能用。如果你能找到一套完整的、自洽的离线依赖包集合(比如用yumdownloader在内网同版本机器上提前拉取好),RPM方式也是可用的。但初次接触离线安装的朋友,我更建议用二进制包先打通流程,因为它的依赖问题最少,最容易成功,后面再根据时间决定要不要精研RPM方案。
2. 部署前的三件套检查:系统版本、依赖库与专用账号
拿到二进制包后别急着解压,先把部署环境的底细摸清楚。所谓三件套,就是操作系统版本与架构、glibc版本、必需的动态链接库。这三样如果没确认好,后面可能解压没问题,启动时报一堆奇怪的错。
2.1 系统版本和glibc版本怎么查
用以下命令快速确认:
cat /etc/os-release uname -m ldd --version | head -n1举例来说,我在一套欧拉系统上部署时,/etc/os-release显示的是openEuler 22.03,但架构和glibc与CentOS 7系列有明显差异。二进制tar包对glibc是向下兼容的,只要系统glibc版本不低于包要求的最低版本,基本都能跑。通常glibc 2.17以上的系统,跑官方通用包问题不大。如果系统太老,比如CentOS 6那批glibc 2.12的机器,就得考虑源码编译或者找对应旧版本的特殊包了。
2.2 依赖动态库是否齐全
虽然二进制包省去了编译依赖,但它依然依赖少数几个系统动态库。启动MariaDB前,最好手动检查一下libaio是否已安装。在CentOS/RHEL系列上,执行:
rpm -qa | grep libaio如果没装,可以从系统ISO镜像的packages目录里找到对应的rpm包,拷进去用rpm -ivh libaio-*.rpm安装。Ubuntu/Debian系则对应libaio1。另外,如果用tar包里的mysql_ssl_rsa_setup工具生成SSL证书,可能会用到openssl命令,一般系统自带,但内网精简版系统需要确认一下。
2.3 创建专用的mysql用户和目录
MariaDB官方和MySQL一样,强烈建议不要用root直接运行数据库服务。虽然你用root也能初始化成功,但后续运行日志里全是告警,更关键的是安全问题——数据库进程一旦被利用,攻击者获得的就是root权限。正确做法是创建专用系统用户:
groupadd mysql useradd -r -g mysql -s /sbin/nologin mysql-s /sbin/nologin的意思是这个用户不能登入shell,只用来跑服务,这是安全基线里比较标准的手法。随后规划数据目录。我的习惯是把二进制包放在/usr/local,数据目录独立放在/data/mysql,日志目录放在/data/mysql/log。把数据目录跟程序目录分开,将来升级、备份、迁移都方便,磁盘空间规划也更灵活。
3. 正式部署:从解压二进制包到systemd接管MySQL服务
环境检查完毕后,进入正式安装阶段。我会分四步走:解压与目录规整、初始化数据目录、配置文件准备、通过systemd托管启动。这四步环环相扣,任何一步出错都会导致后续流程异常。
3.1 解压与目录规整
把下载好的tar.gz包拷贝到目标服务器后,执行解压:
tar -zxvf mariadb-10.11.8-linux-systemd-x86_64.tar.gz -C /usr/local/ cd /usr/local/ ln -s mariadb-10.11.8-linux-systemd-x86_64 mariadb注意我在这里做了一个软链接。之所以这么做,是为了将来升级版本时只需要把新版本解压后替换软链接指向,再重启服务即可,不用改动任何路径配置。这是一个很实用的小习惯,尤其在多套环境需要保持目录路径一致时特别有用。
然后创建数据目录并授权:
mkdir -p /data/mysql/log chown -R mysql:mysql /data/mysql3.2 初始化系统库
初始化是离线安装中最容易出状况的一步。MariaDB的初始化工具是mariadb-install-db(老版本叫mysql_install_db),它负责创建系统表、默认数据库和默认账号。执行命令:
/usr/local/mariadb/scripts/mariadb-install-db \ --user=mysql \ --basedir=/usr/local/mariadb \ --datadir=/data/mysql这里强调一个最常见的坑:如果你之前用root执行过初始化,或者/data/mysql目录属主不对,初始化会报Cannot find file ./mysql/plugin.frm之类的错误,实际上就是目录权限或者残留文件导致。处理办法是先确保目录为空且属主正确,再重新执行:
rm -rf /data/mysql/* chown mysql:mysql /data/mysql chown mysql:mysql /usr/local/mariadb -R另外一个容易忽略的点:解压出来的二进制包默认属主可能是root,虽然init脚本会用mysql用户执行操作,但basedir下的部分文件需要可读可执行。稳妥起见,把整个安装目录的属主也改成mysql,然后再次执行初始化。
初始化成功后,/data/mysql下会出现mysql、test等目录,以及aria_log_control等文件。看到这些基本就可以放心进入下一步了。
3.3 配置my.cnf
很多人会跳过配置文件直接启动,想着先跑起来再说。对于实验环境可以,但生产环境千万别这么干。默认配置的字符集、缓冲池大小、日志策略都可能不符合你的场景,等发现问题再改配置还要重启服务,徒增一次中断。
我的基础配置模板如下(按8G内存的机器估算):
[client] port = 3306 socket = /data/mysql/mysql.sock [mysqld] user = mysql basedir = /usr/local/mariadb datadir = /data/mysql socket = /data/mysql/mysql.sock pid-file = /data/mysql/mariadb.pid log_error = /data/mysql/log/mariadb.err port = 3306 server-id = 1 log_bin = /data/mysql/log/mariadb-bin binlog_format = row expire_logs_days = 7 character-set-server = utf8mb4 collation-server = utf8mb4_general_ci innodb_buffer_pool_size = 2G innodb_log_file_size = 256M innodb_flush_log_at_trx_commit = 2 skip-name-resolve max_connections = 500逐个说明关键项。log_error指向错误日志,排障时必看。skip-name-resolve是跳过反向DNS解析,它能让远程连接速度变快,避免因为内网没有DNS导致的连接超时问题。innodb_flush_log_at_trx_commit = 2适合对性能要求高于极端安全性的业务,如果业务允许丢失最后一秒以内的数据,这个参数能显著降低写压力。binlog_format = row配合server-id是后面的主从复制基础,即使现在暂时用不到,先把binlog开好,以后要搭从库就不需要重启了。
3.4 systemd服务编排
官方二进制包通常自带systemd服务文件,文件名类似mariadb.service,在/usr/local/mariadb/support-files/目录下。如果没有,就自己编写一个。把服务文件拷贝到systemd目录:
cp /usr/local/mariadb/support-files/mariadb.service /usr/lib/systemd/system/ systemctl daemon-reload systemctl enable --now mariadb注意查看自带服务文件里的路径是否正确。有些包版本默认写/usr/local/mysql,如果你的basedir是/usr/local/mariadb,就要先修改服务文件里的路径,再拷贝过去。如果启动后报错说找不到mysqld_safe,八成就是路径问题。
启动完成后,检查状态:
systemctl status mariadb看到active (running)后,再用客户端连一下验证:
/usr/local/mariadb/bin/mariadb -u root能进入命令行就说明基础安装已经成功。
4. 初始化的后续三件事:改密码、开远程、设字符集
服务起来只是第一步,一个裸安装的MariaDB还不能直接交给业务,需要完成初始化后的安全配置。这里有三个动作必须执行,否则后续遇到问题概率极高。
4.1 设置root密码与清理匿名账户
执行官方自带的安全初始化脚本:
/usr/local/mariadb/bin/mariadb-secure-installation按提示依次设置root密码、删除匿名用户、禁止root远程登录、删除test库。这些交互式问题照着回答即可。如果你希望全程脚本化执行,也可以用mysql命令行直接操作:
ALTER USER 'root'@'localhost' IDENTIFIED BY 'YourStrongPass'; DELETE FROM mysql.global_priv WHERE User=''; DELETE FROM mysql.global_priv WHERE User='root' AND Host NOT IN ('localhost','127.0.0.1','::1'); DROP DATABASE IF EXISTS test; FLUSH PRIVILEGES;这里说个细节,MariaDB 10.4以后的版本把用户权限信息统一挪到了mysql.global_priv表,不再用老版本的mysql.user表的Password字段。所以网上一堆老教程里直接UPDATE mysql.user SET Password=PASSWORD('xxx')的写法已经过时了,在新版本里执行会报字段不存在的错误。这也是为什么建议优先用官方脚本来改密码。
4.2 开远程访问的两个必要条件
业务应用通常不会跟数据库在同一台机器上,所以需要root以外的账号能远程连接。很多人会直接授权root远程登录,图省事,但这是非常危险的做法。我一般建议创建专用业务账号,只授予业务库的权限:
CREATE USER 'appuser'@'192.168.1.%' IDENTIFIED BY 'AppPass123'; GRANT SELECT, INSERT, UPDATE, DELETE ON appdb.* TO 'appuser'@'192.168.1.%'; FLUSH PRIVILEGES;注意授权时主机范围写得精确一些,能用网段就用网段,别用'%'通配。有特殊需求要跨网段访问,再单独建账号授权,这样后续审计也清晰。
远程连接的第二个必要条件是bind-address。如果my.cnf里没写这个参数,MariaDB默认监听所有网卡。但有些系统默认配置里写了bind-address = 127.0.0.1,也就是说只允许本机访问,外网IP连3306端口直接拒绝。排查远程连不上的问题时,第一眼看防火墙,第二眼就要看配置文件里有没有这行。如果需要监听某张特定网卡,可以写:
bind-address = 0.0.0.0意思是监听所有IPv4地址。如果只想监听内网网卡,就写具体IP。
4.3 字符集统一与验证
字符集问题在离线环境中尤为常见,因为很多内网系统的默认locale可能是POSIX或C,这会间接影响数据库端的字符集表现。我把字符集配置放在全局层,而不是每个库建库时手动指定:
SET GLOBAL character_set_server = utf8mb4; SET GLOBAL collation_server = utf8mb4_general_ci;但SET GLOBAL只在当前实例生效,重启后还是会回到配置文件的值。因此务必在my.cnf里写死,然后再初始化、再启动。验证已经生效:
SHOW VARIABLES LIKE 'character_set%'; SHOW VARIABLES LIKE 'collation%';输出中character_set_server和collation_server都应该是utf8mb4系,并且character_set_database和character_set_client也建议统一成utf8mb4。如果character_set_client因为是SSH终端字符集不同导致显示异常,不需要担心,客户端连接的字符集由客户端工具指定,比如连接字符串里加useUnicode=true&characterEncoding=utf8(Java侧)或SET NAMES utf8mb4。
5. 踩坑记录:离线环境下最常见的五类报错与处理
离线安装的排障跟在线安装有些不同,很多错误提示不够直观,而且内网环境无从搜索。我把实操中遇到的高频问题集中整理出来,方便你按图索骥。
5.1 初始化时报"Cannot find file ./mysql/plugin.frm"
这个问题基本都出在数据目录不干净或权限不对。要么是之前初始化失败残留了文件,要么是datadir目录属主不是mysql。另外,如果你把二进制包解压到了root用户占有的目录,初始化脚本执行时没有权限读取share和scripts目录下的文件,也会出现怪异报错。解决路径很固定:清空datadir,确保datadir和basedir的属主都是mysql,重新初始化。
5.2 启动失败但systemctl状态没给有效信息
有时systemctl start mariadb后,status显示的是inactive (dead),没有明确报错。原因是systemd对服务输出的捕获有限,真实错误会写到log_error指定的错误日志里。我排障的第一步永远是:
tail -100 /data/mysql/log/mariadb.err比如我遇到过一次启动失败,错误日志里写着Can't start server: Bind on TCP/IP port: Address already in use,一查是另一个残留的mysqld进程还在跑。先ps -ef | grep mysqld找到残留进程杀掉,再启动就正常了。还有一次是Permission denied,原因是/data/mysql/log目录属主不是mysql,mysqld没法写错误日志,直接启动失败。
5.3 我在源码安装时吃过亏的“DIRECTORY”问题
网络上流传的很多教程会让人在[mysqld]里写innodb_data_home_dir或innodb_log_group_home_dir等路径参数,但很多参数在不同版本里行为有差异甚至废弃了。比如早期MySQL里innodb_log_group_home_dir控制redo log路径,MariaDB里如果不写,默认就在datadir下,问题不大。写错了反而可能导致启动时找不到日志文件。建议不是非常确定用途的参数不要写进配置,低版本兼容性往往就在这里出现差异。
5.4 远程连接极其慢或者被拒
慢的问题大概率是反向DNS解析导致。前面配置里提到的skip-name-resolve能直接解决,但它有个副作用:以后在授权表里写'appuser'@'localhost'或'appuser'@'192.168.1.%'时,MariaDB不再尝试解析主机名,所以任何通过主机名授权的条目(如'appuser'@'webserver')会失效。解决方案很简单:统一用IP段来授权。
被拒的问题基本集中在两个点,一是防火墙没放行3306端口,先检查firewall-cmd --list-ports(CentOS系)或iptables -L -n;二是bind-address写死导致没监听外部网卡。把这两处排查完,大部分连接问题都能解决。顺便提一句,用telnet测试端口通不通是最直接的:
telnet 192.168.1.10 3306如果通了会看到Connected to字样,此时端口层面没问题,然后才去排查账号授权。
5.5 root密码忘了怎么办
离线环境里经常发生的事:测试机放了一段时间,root密码找不到了。处理办法是跳过授权表启动,但注意只能用于本机维护,不能暴露在网络可访问的机器上操作。步骤是先停服务,再用跳过授权表的方式启动:
systemctl stop mariadb /usr/local/mariadb/bin/mysqld_safe --skip-grant-tables --skip-networking &--skip-networking是我特别强调的一个参数,它确保其他机器无法通过网络连接上来,避免在跳过认证期间被外人趁虚而入。然后进入客户端直接改密码:
ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewStrongPass';改完密码后,把临时启动的mysqld_safe进程杀掉,再用systemctl正常启动服务。
6. 从能跑到跑得好:补充调优思路与目录结构备忘
安装和基本配置搞定了,最后聊聊怎么把这套环境从"能用"变成"好用"。离线部署最忌讳的就是装完就扔,因为一旦业务上线,再想调整就涉及停机窗口。所以有些优化最好在业务接入前就做好。
6.1 数据目录、日志目录与备份规划
我习惯在部署时就把目录结构固化下来,方便后续维护和排查。以/data/mysql为根目录:
/data/mysql/ # datadir,存放系统库、业务库、binlog /data/mysql/log/ # 错误日志、慢查询日志 /data/backup/mysql/ # 备份目录,可以配合crontab做定时备份备份我推荐用mariabackup(即官方备份工具),它基于物理备份,支持在线备份,尤其适合InnoDB/Aria引擎。通过一条crontab定时任务,比如每天凌晨2点执行一次全量备份:
0 2 * * * /usr/local/mariadb/bin/mariabackup --backup --target-dir=/data/backup/mysql/$(date +\%Y\%m\%d) --user=backupuser --password=xxx备份账号需要RELOAD, LOCK TABLES, REPLICATION CLIENT等权限,我一般单独建一个只用于备份的账号,不用root去备份。
6.2 性能参数快速估算法
innodb_buffer_pool_size是InnoDB最重要的内存参数。经验值通常是物理内存的50%到70%,但前提是这台机器只跑数据库。如果机器上还跑了其他服务,建议先给50%再观察。比如16G内存的数据库机,设8G比较稳妥。设置太大不仅浪费内存,还会因为swap产生严重的性能抖动。
max_connections不要盲目调到几千,每次连接至少会占用几MB内存。连接数从100调到1000,单连接内存开销会直接吃掉几个G。估算方式是用SHOW STATUS LIKE 'Threads_connected'观察业务高峰期的实际并发数,再留有30%-50%的余量。
6.3 其他值得记录的运维习惯
第一,开启慢查询日志并定期分析。在my.cnf里写入:
slow_query_log = 1 slow_query_log_file = /data/mysql/log/mariadb-slow.log long_query_time = 2这样超过2秒的SQL会被记录,业务上线后定期扫一眼,能发现很多索引缺失或写法糟糕的查询。
第二,binlog的保留时间要结合磁盘容量。expire_logs_days对MariaDB 10.6以上版本已弃用,改用binlog_expire_logs_seconds,比如设置成7天就是604800秒。如果你在主从架构里,要确保从库追得上主库的binlog删除速度,否则会断链。
第三,尽量关闭或限制performance_schema在低配机器上的开销。它默认开启,但会消耗约10%-20%的性能资源。对很多内网业务系统来说,默认配置已经够用,不需要强制开启额外审计功能。如果你确实关心性能,可以对比开启前后的负载再做决定。
7. 一套通用的离线安装检查清单
最后我把自己每次离线安装时用来核对流程的检查清单附上。虽然每一步在前面都展开讲过,但实际运维时容易被各种突发情况打断,有一张清单在手,可以减少漏项。
| 阶段 | 检查项 | 验证操作 |
|---|---|---|
| 环境检查 | 系统架构匹配 | uname -m与 tar包名一致 |
| 环境检查 | glibc版本满足 | ldd --version |
| 环境检查 | libaio已安装 | rpm -qa | grep libaio |
| 环境准备 | mysql用户存在 | id mysql |
| 目录规划 | datadir权限正确 | ls -ld /data/mysql |
| 初始化 | 系统库生成成功 | ls /data/mysql出现mysql子目录 |
| 配置文件 | key参数已写入 | grep -E 'datadir|log_error|port' /etc/my.cnf |
| 服务启动 | systemd状态为running | systemctl status mariadb |
| 本地连接 | 无密码能进客户端(初始化后) | mariadb -u root |
| 安全配置 | root密码已设置 | mariadb -u root -p输入新密码 |
| 远程连接 | 端口监听在0.0.0.0 | ss -lntp | grep 3306 |
| 远程连接 | 业务账号可连 | 从应用服务器执行mariadb -h 目标IP -u appuser -p |
| 备份策略 | crontab已配置 | crontab -l |
这份清单不一定适用于所有环境,但覆盖了从掏包到业务可用的全部关键节点。按着列表逐项核验,离线安装基本一趟过。