多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

MariaDB服务器部署实战:从安装到安全加固与性能调优

MariaDB服务器部署实战:从安装到安全加固与性能调优 1. 为什么我坚持在服务器上选MariaDB而不是MySQL先交代一下背景。我最早接触的是MySQL那时候还是5.5、5.6的天下后来因为工作原因换到了MariaDB一用就是好几年。身边不少朋友问我MariaDB和MySQL到底有什么区别不就是换了个名字吗说实话这个问题我一开始也说不清楚直到自己动手把一台业务服务器从MySQL迁移到MariaDB之后才真正理解了其中的门道。MariaDB是MySQL的一个分支由MySQL的创始人Michael Widenius在MySQL被收购后主导开发目标是保持开源、社区驱动的发展路线。所以从血统上讲MariaDB和MySQL是同源的SQL语法基本兼容存储引擎、主从复制、权限系统这些核心机制一脉相承。但对于我们这些真正拿它跑业务的运维人员来说光兼容还不够我更关心的是它在实际服务器环境中的稳定性、性能表现和运维便利性。我自己在服务器上部署MariaDB的切身体会是安装简单、默认配置直白、和MySQL的迁移成本极低。如果你手头的项目之前用的是MySQL把连接串的驱动和端口改一下数据导过来几乎不需要大改代码。而且MariaDB在几个特定场合表现明显更好比如复杂查询的优化器、临时表处理、以及JSON字段的支持后面我会细说。这篇文章不是给高端玩家看的源码分析而是面向在Linux服务器上真正要部署、配置、维护MariaDB的人。我会把从零安装到日常运维的全过程讲清楚包括那些官方文档里不会写、但实际踩坑踩出来的经验。无论你是在本地虚拟机练手还是在云服务器上跑生产业务照着这套思路走基本不会出大问题。2. 部署前的关键认知MariaDB不是MySQL换皮很多人把MariaDB当成MySQL的免费替代品这种理解不算全错但如果带着这个想法去生产环境部署大概率会在某些特性上栽跟头。我建议你在动服务器之前先花十分钟搞清楚几个核心差异这会直接影响你后面的配置决策。2.1 版本演进路径与兼容性边界MariaDB的版本号是独立的目前主流的是10.x系列比如10.5、10.6、10.11。这个版本号看起来比MySQL的8.0大很多但本质上对应的是一个长期演进的分支。需要注意的一点是MariaDB 10.x的某些行为并不完全等同于同期的MySQL 8.x。比如MySQL 8.0默认的认证插件是caching_sha2_password而MariaDB用的是mysql_native_password和unix_socket的组合。这就导致一个很常见的问题从MySQL迁移过来的客户端工具如果只认caching_sha2_password连MariaDB时会报认证失败。我遇到过最典型的场景是公司有个老旧的PHP应用连接数据库的库版本比较老迁移到MariaDB 10.6之后连接直接报Access denied排查了一圈发现是认证插件不匹配。解决方式也很简单在创建用户时显式指定认证插件CREATE USER app_user% IDENTIFIED VIA mysql_native_password USING PASSWORD(your_password);或者用ALTER USER修改已有用户ALTER USER app_user% IDENTIFIED VIA mysql_native_password USING PASSWORD(new_password);这种坑不是技术难题但对第一次上手的人来讲确实容易懵。2.2 存储引擎的默认值差异MySQL 8.x默认的存储引擎是InnoDBMariaDB同样也是InnoDB但MariaDB自己还维护了一套Aria存储引擎还有ColumnStore这类分析型引擎的选项。对绝大多数应用来说直接用InnoDB就够了不需要折腾。但有一个点值得注意MariaDB对InnoDB的实现有自己的一套改进比如支持页面压缩Page Compression——这不是传统意义的表压缩而是更细粒度的物理页压缩能让磁盘占用明显下降。我在一台数据量超过200GB的服务器上开过页面压缩压缩比接近3比1这对磁盘紧张的场景非常友好。但页面压缩有个前提它依赖稀疏文件sparse file和hole punching技术底层文件系统要支持。ext4和XFS都支持但不建议在ZFS上叠加使用因为ZFS自己就有强大的压缩能力双重压缩反而浪费CPU。这属于典型的知道原理才能选好配置的例子。2.3 从MySQL迁移到MariaDB的成本评估如果你当前项目在用MySQL想切到MariaDB我的建议是先评估应用层是否用了MySQL特有的语法或函数。虽然MariaDB兼容面很广但有些MySQL 8.x新增的功能在MariaDB里是没有的例如窗口函数MariaDB 10.2之后补齐了大部分、CTE公共表表达式MariaDB 10.2之后也支持了等。主流功能基本不缺但务必做一次全量SQL的回归测试尤其是涉及JSON操作、加密函数这类细节的地方。具体迁移步骤可以这样走先在测试服务器装同版本MariaDB直接导入MySQL的逻辑备份文件mysqldump导出的.sql文件观察报错。跑一遍应用的全部接口测试重点看查询结果是否一致。用pt-query-digest或Performance Schema抓一段时间的生产慢查询在MariaDB上回放对比执行时间。我做过的最顺利的一次迁移是在一台CentOS 7服务器上MySQL 5.7迁到MariaDB 10.6除了几个存储过程写法有细微差异其余全量通过。整个过程验证下来只要SQL不是特别MySQL私有化迁移没有想象中痛苦。3. 全新服务器上部署MariaDB的完整流程聊完基础认知接下来是真正的实操环节。我以一台干净的Linux服务器为例CentOS 7/8或者Ubuntu 20.04/22.04皆可带你走一遍部署流程。下面这些步骤是我反复操作过很多遍的每一步都有明确目的不是随便敲的。3.1 环境准备检查系统与依赖动手前先确认三件事操作系统版本不同发行版对应的软件仓库不一样安装方式也不同。磁盘空间数据目录默认是/var/lib/mysql要有充足空间建议至少预留20GB以上生产环境则按数据增长量翻倍预估。内存大小MariaDB默认配置比较保守但如果有条件建议服务器内存不低于2GB之后再根据实际业务量调优。可以用下面命令快速检查cat /etc/os-release free -h df -h这里有个容易被忽略的点尽量别在容器里跑生产级MariaDB除非你非常熟悉数据卷和网络配置的坑。Docker跑开发环境图省事没问题但生产环境的数据卷权限、端口映射、日志收集都容易出幺蛾子。我见过不止一次因为Docker容器重建导致数据库数据丢失的案例教训很惨痛。3.2 安装MariaDB官方仓库优先Ubuntu/Debian系列的安装方式apt update apt install mariadb-server mariadb-clientCentOS/RHEL系列7和8都适用# CentOS 7 yum install mariadb-server # CentOS 8 / Rocky Linux 8 dnf install mariadb-server装完之后启动服务并设为开机自启systemctl start mariadb systemctl enable mariadb systemctl status mariadb这里我强烈建议一件很多人不做的事安装完成后立刻查看版本号并记录下来。别觉得多余后面排查兼容性问题、找官方文档时版本号是第一筛选条件。mariadb --version mysql --version你会发现mariadb命令和mysql命令都能用因为MariaDB把客户端工具做成了兼容模式这是故意为之的目的就是让老MySQL用户无缝切换。3.3 初始化配置跑一遍安全脚本安装完成并启动后第一件事是运行安全初始化脚本mysql_secure_installation这个脚本会引导你做几件事设置root密码如果没有设置过删除匿名用户禁止root远程登录删除test测试数据库重新加载权限表对新手来说这个脚本是新手村任务但很多人因为嫌麻烦直接跳过了。我的建议是无论如何都要跑一遍。它解决的不只是安全问题还会帮你确认root密码是否已经设置、权限表是否正常加载相当于一次环境体检。如果脚本运行时提示root密码已设置而你忘了密码别慌后面第4章有完整的找回方案。3.4 验证基础连接初始化完成后用root登录验证mariadb -u root -p输入密码后能进入数据库命令行说明部署成功。这时可以做几个基础查询确认系统表和引擎状态正常SELECT VERSION(); SHOW ENGINES; SHOW DATABASES;看到版本号、引擎列表和系统数据库information_schema、mysql、performance_schema都正常返回这台服务器的数据库基础就算搭好了。4. 安全配置实战从root密码到远程访问的全套加固热搜词里有一条给mariadb root设置密码这个需求太常见了。很多教程只会告诉你一个ALTER USER语句但实际工作中安全问题往往不是一条SQL能解决的。我把完整的安全加固流程整理在这里照着做比碎片化搜索强得多。4.1 root密码的三种设置方式方式一通过安全脚本设置最推荐install之后直接跑mysql_secure_installation按提示设置密码即可。好处是顺带把匿名用户、测试库一并清理了。方式二命令行直接修改mariadb -u root进入命令行后执行ALTER USER rootlocalhost IDENTIFIED BY new_strong_password; FLUSH PRIVILEGES;FLUSH PRIVILEGES的目的是让权限修改立即生效虽然ALTER USER本身会自动刷新但习惯性执行一下更稳妥。方式三忘记root密码时的重置这个情况更常见特别是接手别人的服务器时。操作步骤如下停止数据库服务systemctl stop mariadb使用跳过授权表的方式临时启动mysqld_safe --skip-grant-tables --skip-networking --skip-networking很关键防止在无密码状态下被远程连接这是安全底线。无密码登录并修改密码mariadb -u rootFLUSH PRIVILEGES; ALTER USER rootlocalhost IDENTIFIED BY new_strong_password; FLUSH PRIVILEGES;重启服务systemctl restart mariadb注意mysqld_safe可能不在PATH里如果提示命令不存在用绝对路径或找一下二进制位置。我踩过一次坑CentOS 8的MariaDB默认用systemd管理直接调mysqld_safe会报权限错误正确做法是先systemctl stop mariadb再用su - mysql -s /bin/bash切换到mysql用户执行。4.2 授权表里的隐藏风险匿名用户与空密码跑完安全脚本后建议再手动查一遍用户表看有没有漏网之鱼SELECT User, Host, plugin, password FROM mysql.user;正常情况应该只有root和mariadb.sys等系统账号。如果看到User为空的记录说明存在匿名用户删除DROP USER localhost; DROP USER hostname;空密码用户同理检查password字段是否为空的非系统账号一律清理。4.3 远程访问配置别直接给root开外网生产业务大概率需要远程连接数据库但给root开远程权限是最危险的操作之一。正确做法是创建业务专用账号授权最小化。创建用户的通用姿势CREATE USER app_user192.168.1.% IDENTIFIED BY secure_password; GRANT SELECT, INSERT, UPDATE, DELETE ON app_db.* TO app_user192.168.1.%; FLUSH PRIVILEGES;192.168.1.%表示只允许这个网段的机器连接大幅缩小暴露面。如果业务跑在Kubernetes集群或云环境里IP段经常变化可以退而求其次用%但务必配合防火墙做IP白名单。改完用户权限后还需要确认MariaDB监听地址。默认配置下MariaDB只监听127.0.0.1远程访问需要修改配置vim /etc/mysql/mariadb.conf.d/50-server.cnf找到bind-address这一行把127.0.0.1改为0.0.0.0表示监听所有网卡bind-address 0.0.0.0改完重启服务systemctl restart mariadb很多人在这一步卡住用户建了、权限也授权了远程还是连不上。原因就是bind-address默认值没有改。这属于最容易忽略但影响最大的细节。4.4 防火墙与端口管理确认MariaDB默认端口3306是否放行。CentOS 7/8用firewalldfirewall-cmd --permanent --add-port3306/tcp firewall-cmd --reloadUbuntu用ufwufw allow 3306/tcp安全加固到这个程度基本的服务器防护就到位了。但还有个细节得提如果是云服务器除了系统防火墙还要去云控制台的安全组规则里放行端口。因为云平台的安全组是独立于操作系统防火墙的一道关卡两处都得配好否则怎么测都连不上。5. 搭建过程中最常见的故障排查链路这一章我从一线运维视角梳理一下服务器装好但连不上的完整排查思路。这类问题占了数据库服务器故障的一大半按下面这个顺序查基本不会走弯路。5.1 连接失败排查从端口到权限的逐步定位当你执行mariadb -h 服务器IP -P 3306 -u app_user -p之后报错不要急着改配置。按这个顺序查第一层网络连通性ping 服务器IP telnet 服务器IP 3306telnet能通说明端口可达直接跳到第三层。如果telnet不通看防火墙和服务监听状态ss -tlnp | grep 3306看到类似0.0.0.0:3306的监听记录说明服务在监听。如果只有127.0.0.1:3306那就是bind-address没改。第二层防火墙拦截iptables -L -n | grep 3306 firewall-cmd --list-all云服务器用户记得检查安全组这一步经常被忽略。第三层账号权限与主机匹配如果端口通、防火墙放行但客户端报Access denied那就是授权问题。确认账号是否存在Host是否匹配客户端来源IP密码是否正确认证插件是否兼容第四层认证插件不兼容报错信息如果你看到Authentication plugin caching_sha2_password cannot be loaded说明客户端驱动太老而服务端要求新认证。MariaDB一般不默认用这个插件但如果你的库是从MySQL 8.0迁移来的可能出现插件残留。用下面的方式处理ALTER USER app_user% IDENTIFIED VIA mysql_native_password USING PASSWORD(your_password);5.2 忘记密码的完整恢复流程这个在4.1节已经写了操作步骤但我想再说一个真实遇到的场景有一次帮客户处理一台Windows Server上的MariaDB服务器systemctl命令根本不存在因为Windows下用服务方式管理。Windows环境重置密码的方式略有不同需要用mysql_install_db.exe或者手动跳过授权表mysqld --skip-grant-tables --skip-networking --console然后新开一个命令行窗口执行密码修改。Windows下的坑是mysqld进程要以管理员身份运行否则数据目录权限不够启动会直接失败。5.3 数据目录损坏的应急处理服务器突然断电、磁盘满了都可能造成数据文件损坏。MariaDB有崩溃恢复机制正常情况下启动时会自动回滚未完成的事务。但如果损害严重启动报错如Table ./db/table is marked as crashed and should be repaired可以尝试mariadb-check --repair --databases db_name更严重的情况需要启用InnoDB的强制恢复参数在配置文件[mysqld]区域加innodb_force_recovery 1从1开始尝试依次递增到6每次尝试启动一次能启动就立即导出数据备份。强推恢复模式启动后不要做任何写操作只做备份因为此时的引擎处于不完全状态一旦写入可能造成二次损坏。备完数据后马上改回0并重启。6. 系统服务与日常维护让MariaDB稳稳跑下去搭建好服务器只是开始运维才是长期工作。这部分讲几个我每天都会用到的维护技巧都是实打实的经验。6.1 systemd服务管理与开机自启的细节用systemd管理MariaDB非常方便常用命令systemctl start mariadb # 启动 systemctl stop mariadb # 停止 systemctl restart mariadb # 重启 systemctl reload mariadb # 重载配置不中断连接 systemctl enable mariadb # 开机自启我特别想提一下reload和restart的区别。reload只是重新读取配置文件对已有连接影响极小restart是彻底重启服务所有连接都会断开。日常改配置优先用reload需要加载新引擎或解决异常状态才用restart。6.2 日志系统错误日志、慢查询日志与通用日志MariaDB的日志是排查问题的重要抓手先看配置[mysqld] log_error /var/log/mysql/error.log slow_query_log 1 slow_query_log_file /var/log/mysql/mariadb-slow.log long_query_time 2关键参数说明log_error错误日志MySQL和MariaDB启动失败、数据损坏、磁盘满等严重问题都会记录在这里排查问题的第一入口。slow_query_log慢查询日志记录执行时间超过long_query_time秒的SQL是性能优化的源头数据。general_log通用查询日志默认关闭。开启后记录所有SQL语句影响性能只在调试时临时开。查看慢查询的典型方法tail -f /var/log/mysql/mariadb-slow.log分析慢查询日志里最常见的SQL模式用EXPLAIN看执行计划性能问题就能定位到八九成。6.3 数据备份策略不备份等于没运维备份这事我一直强调备份不是技术问题是习惯问题。很多小团队等到数据丢了才想起备份那时基本晚了。MariaDB最常用的备份方案分两种逻辑备份mysqldump适合中小库可读性好恢复灵活mysqldump -u root -p --single-transaction --routines --triggers --all-databases /backup/all_databases_$(date %F).sql--single-transaction参数很关键它基于InnoDB的MVCC机制做一致性快照备份过程中不影响线上写入不需要锁表。物理备份MariaDB Backup适合大库速度快恢复简单mariabackup --backup --target-dir/backup/mariadb_full/ --userroot --password******恢复流程也简单mariabackup --prepare --target-dir/backup/mariadb_full/ mariabackup --copy-back --target-dir/backup/mariadb_full/我自己的备份纪律如下每天凌晨做一次全量备份保留7天每6小时做一次增量binlog备份保留3天。这个节奏对大多中小业务够用了。自动化用crontab0 2 * * * mysqldump -u root -p密码 --single-transaction --all-databases | gzip /backup/db_$(date \%F).sql.gz还有一点要叮嘱备份文件必须异地保存。把备份放到另外一台机器或者对象存储里否则服务器硬盘坏了备份和数据一起没哭都来不及。7. 性能调优按实际业务调整的关键参数MariaDB装好默认配置能跑但跑得稳不稳、快不快完全取决于调优水平。我调过几十台服务器总结出几个影响面最大的参数。7.1 内存类参数缓冲池是最直接的加速器InnoDB缓冲池innodb_buffer_pool_size是数据库的内存数据仓库读取数据时优先从缓冲池里找命中率直接决定查询速度。设置经验值物理内存的60%到70%但不能超过总内存减去其他进程开销。假设服务器16GB内存可以这样设置[mysqld] innodb_buffer_pool_size 10G设太大反而引发内存交换swap导致性能雪崩。改完配置后通过以下SQL验证效果SHOW STATUS LIKE Innodb_buffer_pool_read%;如果Innodb_buffer_pool_read_requests远大于Innodb_buffer_pool_reads说明命中率高配置合理。7.2 连接数与大表优化max_connections默认是151对并发较大的业务来说可能不够。设太高又会造成资源浪费经验公式每个连接大约占用1MB到2MB内存按服务器内存总量来反推。max_connections 300同时看thread_cache_size这个参数控制线程复用的缓存数量调高可以显著减少线程频繁创建的开销thread_cache_size 64大表场景下临时表大小也是常见瓶颈。很多人遇到临时表满了的错误可以调整tmp_table_size 64M max_heap_table_size 64MMySQL和MariaDB的临时表既可能是内存表也可能是磁盘表上行两个参数配合调整能有效避免排序过多时频繁落盘。7.3 慢查询分析与索引优化实战慢查询日志里如果发现某条SQL反复出现基本就是索引没建对。用EXPLAIN查看执行计划EXPLAIN SELECT * FROM orders WHERE user_id 12345 AND status PAID;关注type字段如果是ALL说明是全表扫描必须优化。最直接的优化就是建联合索引ALTER TABLE orders ADD INDEX idx_user_status (user_id, status);索引不是越多越好每次写操作都要维护索引索引过多反而拖慢写入速度。我的原则是只给高频查询条件建索引一个表最多5到6个索引。7.4 事前防患认识连接数打满的危害连接数打满是最常见的生产事故类型之一。现象是应用报Too many connections表现是数据库卡死服务不可用。此时系统还是会保留2个额外连接给超级管理员super权限方便你登录排查。用root登录后立刻看SHOW PROCESSLIST;大部分情况是很多连接处于Sleep状态说明应用连接池有泄漏或者空闲连接没回收。短平快的处理是调大max_connections但根本上要优化应用连接池的配置否则只是推迟问题爆发的时间。8. 备份恢复演练一次真实的数据救回过程讲一个我实际经历的事。有一台业务服务器装着MariaDB 10.5存了几年的订单数据某个周末同事跑了个错误的批量更新脚本把一张核心表的数据状态全部改错了。当时我的备份策略虽然存在但恢复流程没演练过说实话心里也没底。当时的处理过程是这样的第一步止损。立刻停止应用服务防止继续写入导致问题扩大。第二步定位可恢复的时间点。因为binlog一直开着我可以把数据恢复到出问题前的某一刻。先查看binlog列表ls -lt /var/log/mysql/找到出问题时间点之前的binlog文件。第三步用全量备份恢复基础数据。把近期的mysqldump备份导入mysql -u root -p /backup/all_databases_上周日.sql第四步用binlog追加上周日至出问题前的数据变更。先找到两个时间点之间的binglog转成SQLmysqlbinlog --start-datetime2024-11-10 02:00:00 --stop-datetime2024-11-16 14:30:00 /var/log/mysql/mariadb-bin.000023 recover.sql第五步将恢复SQL导入mysql -u root -p recover.sql整个流程走完数据恢复到了出问题前几分钟的状态丢失的只是错误脚本执行后的那些变更。这个案例想说明几点备份必须有binlog必须开恢复流程必须事先演练过。尤其最后一点很多人备份做得勤但没有真正演练过恢复关键时刻手忙脚乱。我现在每季度会做一次完整的恢复演练恢复出来的数据校验无误后再删掉成本很低但给人的底气和保险完全不一样。如果一个服务器连binlog都没开恢复只能停留在全量备份那一刻中间的变故全部丢失。检查binlog是否开启SHOW VARIABLES LIKE log_bin;如果结果是OFF在配置文件[mysqld]区域加log_bin /var/log/mysql/mariadb-bin server_id 1重启服务生效。binlog还能用来做主从复制价值很大。9. 写给第一次搭MariaDB服务器的人最后分享一些个人经验不谈高深理论只讲实操中反复验证过的心得。第一版本选择要按长期维护版本走。MariaDB 10.6和10.11都是维护周期较长的版本适合生产环境新功能尝鲜版本比如11.x除非你有明确需求否则别在核心业务上用。稳定永远比新特性值钱。第二服务器系统的时区和时间同步也会影响数据库。如果服务器时间不对事务时间戳、定时任务、日志排查全部错乱而且主从复制还会因此出现莫名其妙的同步延迟。检查时区timedatectl set-timezone Asia/Shanghai启用NTP同步timedatectl set-ntp yes第三磁盘满是一票否决型故障。数据库数据目录所在分区写满服务会直接异常甚至启动不了。我的预防方法是定时监控df -h /var/lib/mysql配合告警阈值90%就该清理或扩容了。第四不要随手关掉慢查询日志。有些运维觉得慢查询日志占磁盘就把它关了。但慢查询日志是性能优化最直观的证据来源开着它、定期分析能帮你发现很多隐患。磁盘不够可以设置轮转别一关了之。第五任何时候改完配置先reload再观察不要直接restart。reload可以在不中断业务的情况下让配置生效只有配置语法有严重错误时reload才会失败这时再决定是否restart。MariaDB这东西真正摸熟了你会发现它没什么神秘的就是一套很扎实的数据库软件。但扎实建立在细节之上密码怎么设、权限怎么收、参数怎么调、备份怎么做、故障怎么查每一个环节都是经验堆出来的。希望这篇搭建实录能让你少走几个弯路。你在部署过程中如果遇到什么奇怪的问题评论区丢出来我尽力帮你分析。
返回列表