如何在两个MySQL实例间搭建复制并同步Laravel存储实现应用断网可用
方案整体思路
你需要实现双向数据同步 + 本地离线环境自动切换两个核心能力,两边的MySQL、存储目录都要支持双向增量同步,同时Laravel要适配断网时自动走本地资源,恢复网络后自动合并两边的变更。
1. MySQL双向同步配置
不要用默认的单向主从复制,你的场景里本地和远端都可能产生数据(断网时本地写入、联网时远端可能有其他端写入),所以用**MySQL主主复制(双主模式)**最合适,配置步骤如下:
- 两边的MySQL都开启binlog,选择
ROW模式的binlog,避免SQL语句执行的上下文差异导致同步出错 - 分别给两边设置不冲突的自增ID偏移量,避免两边同时写入同一张表时主键冲突:
远端DigitalOcean Droplet的MySQL配置新增:
本地的MySQL配置新增:auto_increment_offset = 1 auto_increment_increment = 2
这样远端生成的ID都是奇数,本地生成的ID都是偶数,永远不会出现主键冲突auto_increment_offset = 2 auto_increment_increment = 2 - 两边互相创建同步账号,配置对方为自己的主库,开启同步进程即可
- 如果你的数据里有软删除、唯一索引字段,建议额外加简单的数据冲突校验脚本,每天凌晨跑一次对比两边的数据差异,避免极端场景下的同步中断
2. public/storage目录双向同步
用rsync+inotifywait做增量同步就足够满足小型企业的需求,不需要额外部署复杂的分布式存储:
- 两边服务器先安装依赖工具,Debian/Ubuntu系系统直接执行:
apt install rsync inotify-tools - 配置SSH免密登录,让两边服务器可以互相访问对方的rsync端口
- 编写同步脚本,监控本地
public/storage目录的变更,只要有新增、修改、删除操作,就自动推送到对端的对应目录,脚本示例:#!/bin/bash MONITOR_DIR="/path/to/your/laravel/public/storage/" TARGET_DIR="root@[对端服务器IP]:/path/to/laravel/public/storage/" inotifywait -mrq -e modify,create,delete,move $MONITOR_DIR | while read event do rsync -avz --delete $MONITOR_DIR $TARGET_DIR done - 把脚本设置为开机自启,同时再加一个定时任务,每30分钟全量同步一次,避免监控漏触发导致的文件不一致
- 注意Laravel里存储文件的路径全部用相对路径,不要写死远端域名,这样断网时访问本地路径也能正常加载资源
3. Laravel端离线适配
- 首先在企业本地也部署一份和远端版本完全一致的Laravel应用
- 配置企业内网的DNS或者本地hosts,让内网用户访问应用域名时优先解析到本地的Laravel服务,如果本地服务不可用才走远端公网IP
- 可以新增一个简单的网络检测中间件,当检测到公网连通时,用户上传的文件和数据可以同时写入两边,也可以等待同步进程自动同步,不影响用户正常使用
4. 校验和兜底方案
- 第一次上线前先全量同步一次两边的MySQL数据和存储文件,确保初始状态完全一致
- 每周跑一次全量校验,对比两边的数据库行数、存储目录的文件数量和哈希值,有差异及时修复
- 如果后续企业体量变大、数据量上涨,可以换成Maxwell、Canal这类专门的双向同步工具处理MySQL同步,存储换成MinIO做分布式对象存储,目前小体量场景下上述方案足够稳定使用
内容的提问来源于stack exchange,提问作者youss
相关产品推荐
相关产品推荐

