Nextcloud 私有云部署教程 / 04 - 数据库管理
04 - 数据库管理
深入了解 Nextcloud 的数据库选型、配置优化、高可用架构以及备份恢复策略。
4.1 数据库选型概览
Nextcloud 支持三种数据库后端,选择直接影响性能与可扩展性:
| 特性 | SQLite | MySQL / MariaDB | PostgreSQL |
|---|---|---|---|
| 适用规模 | 开发测试 / 单用户 | 中小到大型部署 | 中大型到企业级 |
| 并发性能 | 差 | 优秀 | 优秀 |
| 全文搜索 | 基础 | 支持 | 支持(更强) |
| JSON 支持 | 无 | 基础 | 原生支持 |
| 安装复杂度 | 零配置 | 中等 | 中等 |
| 复制 / HA | 不支持 | 主从复制 / Galera | 流复制 / Patroni |
| Nextcloud 推荐 | ❌ 仅测试 | ✅ 推荐 | ✅ 推荐 |
| 资源占用 | 低 | 中等 | 中等偏高 |
建议: 生产环境必须使用 MySQL/MariaDB 或 PostgreSQL。SQLite 仅用于快速体验或单元测试。
4.2 MySQL / MariaDB 配置
推荐版本
| 数据库 | 推荐版本 | 说明 |
|---|---|---|
| MySQL | 8.0+ | 推荐 8.0 或 8.4 |
| MariaDB | 10.6+ | 推荐 10.11 LTS |
安装
# Ubuntu / Debian
sudo apt install -y mariadb-server mariadb-client
# 启动并设置开机自启
sudo systemctl enable --now mariadb
# 安全初始化
sudo mysql_secure_installation
创建数据库和用户
-- 登录
sudo mysql -u root -p
-- 创建数据库
CREATE DATABASE IF NOT EXISTS nextcloud
CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci;
-- 创建专用用户
CREATE USER IF NOT EXISTS 'ncuser'@'localhost'
IDENTIFIED BY 'StrongPassword123!';
-- 授权
GRANT ALL PRIVILEGES ON nextcloud.* TO 'ncuser'@'localhost';
-- 如果使用 MySQL 8.0+,需要指定认证插件
ALTER USER 'ncuser'@'localhost'
IDENTIFIED WITH mysql_native_password BY 'StrongPassword123!';
FLUSH PRIVILEGES;
MariaDB / MySQL 推荐配置
编辑 /etc/mysql/mariadb.conf.d/90-nextcloud.cnf(MariaDB)或 /etc/mysql/mysql.conf.d/nextcloud.cnf(MySQL):
[mysqld]
# ======== 存储引擎 ========
default_storage_engine = InnoDB
innodb_file_per_table = ON
innodb_large_prefix = ON
innodb_file_format = Barracuda
# ======== 字符集 ========
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
# ======== InnoDB 调优 ========
innodb_buffer_pool_size = 1G # 建议为可用内存的 50-70%
innodb_buffer_pool_instances = 1 # buffer_pool_size > 1G 时设为多个
innodb_log_file_size = 256M
innodb_log_buffer_size = 64M
innodb_flush_log_at_trx_commit = 2 # 1=最安全 2=性能更好
innodb_flush_method = O_DIRECT
innodb_io_capacity = 2000 # SSD 建议 2000-4000
innodb_io_capacity_max = 4000
innodb_read_io_threads = 4
innodb_write_io_threads = 4
# ======== 连接数 ========
max_connections = 200
max_allowed_packet = 64M
# ======== 查询缓存(MySQL 8.0 已移除) ========
# query_cache_type = 0 # MariaDB 可用,MySQL 8.0 无效
# query_cache_size = 0
# ======== 临时表与排序 ========
tmp_table_size = 64M
max_heap_table_size = 64M
sort_buffer_size = 4M
join_buffer_size = 4M
# ======== 慢查询日志 ========
slow_query_log = ON
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
# ======== 二进制日志(用于复制) ========
# log_bin = /var/log/mysql/mysql-bin
# binlog_format = ROW
# expire_logs_days = 7
重启数据库:
sudo systemctl restart mariadb
验证配置:
-- 检查 InnoDB 配置
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
SHOW VARIABLES LIKE 'innodb_file_per_table';
-- 检查字符集
SHOW VARIABLES LIKE 'character_set_server';
SHOW VARIABLES LIKE 'collation_server';
4.3 PostgreSQL 配置
安装
# Ubuntu / Debian
sudo apt install -y postgresql postgresql-contrib
# 启动
sudo systemctl enable --now postgresql
创建数据库和用户
sudo -u postgres psql
-- 创建用户
CREATE USER ncuser WITH PASSWORD 'StrongPassword123!';
-- 创建数据库
CREATE DATABASE nextcloud
OWNER ncuser
ENCODING 'UTF8'
LC_COLLATE = 'en_US.UTF-8'
LC_CTYPE = 'en_US.UTF-8'
TEMPLATE = template0;
-- 授权
GRANT ALL PRIVILEGES ON DATABASE nextcloud TO ncuser;
-- 启用扩展(可选)
\c nextcloud
CREATE EXTENSION IF NOT EXISTS pg_trgm; -- 模糊搜索加速
\q
PostgreSQL 推荐配置
编辑 /etc/postgresql/15/main/postgresql.conf:
# ======== 内存 ========
shared_buffers = 256MB # 总内存的 25%
effective_cache_size = 768MB # 总内存的 75%
work_mem = 16MB
maintenance_work_mem = 128MB
# ======== WAL ========
wal_buffers = 16MB
checkpoint_completion_target = 0.9
max_wal_size = 1GB
min_wal_size = 256MB
# ======== 连接 ========
max_connections = 200
# ======== 查询优化 ========
random_page_cost = 1.1 # SSD 设为 1.1,HDD 设为 4
effective_io_concurrency = 200 # SSD 设为 200
default_statistics_target = 100
# ======== 日志 ========
log_min_duration_statement = 2000 # 慢查询阈值(毫秒)
log_checkpoints = ON
log_connections = ON
log_disconnections = ON
# ======== JIT ========
jit = on
jit_above_cost = 100000
编辑 /etc/postgresql/15/main/pg_hba.conf 添加:
# 允许本地 Nextcloud 连接
local nextcloud ncuser md5
host nextcloud ncuser 127.0.0.1/32 md5
host nextcloud ncuser ::1/128 md5
sudo systemctl restart postgresql
4.4 数据库迁移
SQLite → MySQL
# 1. 安装 MySQL 并创建数据库(见 4.2 节)
# 2. 导出 SQLite 数据
sudo -u www-data php /var/www/nextcloud/occ db:convert-type \
--all-apps \
mysql \
ncuser \
localhost \
nextcloud
# 3. 确认迁移成功
sudo -u www-data php /var/www/nextcloud/occ db:add-missing-indices
sudo -u www-data php /var/www/nextcloud/occ db:add-missing-columns
sudo -u www-data php /var/www/nextcloud/occ db:add-missing-primary-keys
MySQL → PostgreSQL
# 1. 安装 PostgreSQL 并创建数据库
# 2. 使用 occ 迁移
sudo -u www-data php /var/www/nextcloud/occ db:convert-type \
--all-apps \
pgsql \
ncuser \
localhost \
nextcloud
# 3. 验证
sudo -u www-data php /var/www/nextcloud/occ maintenance:repair
迁移注意事项
| 步骤 | 操作 | 说明 |
|---|---|---|
| 1 | 开启维护模式 | occ maintenance:mode --on |
| 2 | 完整备份 | 备份 data 目录 + 数据库 + config.php |
| 3 | 执行迁移 | occ db:convert-type |
| 4 | 修复数据库 | occ maintenance:repair |
| 5 | 关闭维护模式 | occ maintenance:mode --off |
| 6 | 验证功能 | 登录、上传、分享等 |
4.5 数据库维护
日常维护命令
# 添加缺失的索引
sudo -u www-data php /var/www/nextcloud/occ db:add-missing-indices
# 添加缺失的列
sudo -u www-data php /var/www/nextcloud/occ db:add-missing-columns
# 添加缺失的主键
sudo -u www-data php /var/www/nextcloud/occ db:add-missing-primary-keys
# 转换字符集为 utf8mb4
sudo -u www-data php /var/www/nextcloud/occ db:convert-filecache-bigint
表优化
-- MySQL: 优化所有表
USE nextcloud;
SELECT CONCAT('OPTIMIZE TABLE `', TABLE_NAME, '`;')
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'nextcloud' AND ENGINE = 'InnoDB';
-- 批量执行优化
OPTIMIZE TABLE oc_filecache;
OPTIMIZE TABLE oc_activity;
OPTIMIZE TABLE oc_storages;
-- PostgreSQL: 清理与重建
VACUUM FULL ANALYZE;
REINDEX DATABASE nextcloud;
数据库状态监控
-- MySQL: 查看连接状态
SHOW STATUS LIKE 'Threads_connected';
SHOW STATUS LIKE 'Threads_running';
SHOW PROCESSLIST;
-- 查看 InnoDB 缓冲池命中率
SHOW STATUS LIKE 'Innodb_buffer_pool_read%';
-- 命中率 = 1 - (Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests)
-- PostgreSQL: 查看连接数
SELECT count(*) FROM pg_stat_activity;
-- 查看慢查询
SELECT pid, now() - pg_stat_activity.query_start AS duration, query
FROM pg_stat_activity
WHERE (now() - pg_stat_activity.query_start) > interval '5 minutes';
4.6 高可用与集群
MySQL 主从复制
┌──────────┐ binlog ┌──────────┐
│ Master │ ──────────────→│ Slave │
│ (写入) │ │ (只读) │
└──────────┘ └──────────┘
Master 配置 (/etc/mysql/mariadb.conf.d/91-master.cnf):
[mysqld]
server-id = 1
log_bin = /var/log/mysql/mysql-bin
binlog_format = ROW
expire_logs_days = 7
Slave 配置:
[mysqld]
server-id = 2
relay_log = /var/log/mysql/relay-bin
read_only = ON
-- Master: 创建复制用户
CREATE USER 'repl'@'%' IDENTIFIED BY 'ReplPassword!';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
-- Slave: 配置主从关系
CHANGE MASTER TO
MASTER_HOST='192.168.1.10',
MASTER_USER='repl',
MASTER_PASSWORD='ReplPassword!',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=0;
START SLAVE;
SHOW SLAVE STATUS\G
注意: Nextcloud 目前不原生支持数据库读写分离。需要通过 ProxySQL 或 HAProxy 等中间件实现。
Galera Cluster(MariaDB)
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Node 1 │◄──►│ Node 2 │◄──►│ Node 3 │
│ (读写) │ │ (读写) │ │ (读写) │
└──────────┘ └──────────┘ └──────────┘
Galera 配置要点:
[mysqld]
wsrep_on = ON
wsrep_provider = /usr/lib/galera/libgalera_smm.so
wsrep_cluster_name = "nextcloud_cluster"
wsrep_cluster_address = "gcomm://192.168.1.10,192.168.1.11,192.168.1.12"
wsrep_node_address = "192.168.1.10"
wsrep_node_name = "node1"
wsrep_sst_method = rsync
binlog_format = ROW
default_storage_engine = InnoDB
innodb_autoinc_lock_mode = 2
4.7 数据库备份
MySQL 备份脚本
#!/bin/bash
# nextcloud-db-backup.sh
BACKUP_DIR="/backup/mysql"
DATE=$(date +%Y%m%d_%H%M%S)
DB_NAME="nextcloud"
DB_USER="ncuser"
DB_PASS="StrongPassword123!"
RETENTION_DAYS=30
# 全量备份
mysqldump \
--single-transaction \
--routines \
--triggers \
--quick \
--lock-tables=false \
-u "$DB_USER" \
-p"$DB_PASS" \
"$DB_NAME" | gzip > "$BACKUP_DIR/nextcloud_${DATE}.sql.gz"
# 清理旧备份
find "$BACKUP_DIR" -name "nextcloud_*.sql.gz" -mtime +$RETENTION_DAYS -delete
echo "[$(date)] Backup completed: nextcloud_${DATE}.sql.gz"
PostgreSQL 备份脚本
#!/bin/bash
# nextcloud-pg-backup.sh
BACKUP_DIR="/backup/postgresql"
DATE=$(date +%Y%m%d_%H%M%S)
# 使用 pg_dump 自定义格式(支持并行恢复)
pg_dump -U ncuser -Fc nextcloud > "$BACKUP_DIR/nextcloud_${DATE}.dump"
# 或 SQL 格式
pg_dump -U ncuser nextcloud | gzip > "$BACKUP_DIR/nextcloud_${DATE}.sql.gz"
# 清理 30 天前的备份
find "$BACKUP_DIR" -mtime +30 -delete
自动定时备份
# 添加 crontab
sudo crontab -e
# 每天凌晨 3:00 备份
0 3 * * * /usr/local/bin/nextcloud-db-backup.sh >> /var/log/nextcloud-backup.log 2>&1
4.8 注意事项
- utf8mb4: MySQL 必须使用 utf8mb4 字符集,否则 emoji 和部分中文会存储失败
- InnoDB: 必须使用 InnoDB 引擎,MyISAM 不支持事务和行级锁
- buffer_pool_size: InnoDB 缓冲池是 MySQL 最重要的性能参数,建议设为可用内存的 50-70%
- 连接数: 不要设置过大的 max_connections,PHP-FPM 进程数 × 数据库连接 = 总连接需求
- 定期优化: 每月对大表(如 oc_filecache)执行 OPTIMIZE TABLE
- 慢查询日志: 开启慢查询日志有助于发现性能瓶颈