Surviving the Switch: Zero-Downtime Database Migration Strategies for High-Traffic Norwegian Workloads
I still wake up in a cold sweat thinking about the "Great Migration of 2016." We were moving a 4TB e-commerce database from a bare metal server in Frankfurt to a cloud instance. The strategy? mysqldump, SCP, and hope. The result? 14 hours of downtime, three corrupt indexes, and a furious CEO breathing down my neck. Never again.
If you treat database migration as a simple file transfer, you are already dead. In October 2020, with the Schrems II ruling fresh in our minds and GDPR compliance tighter than ever, moving data isn't just a technical hurdle—it's a legal minefield. Whether you are repatriating data from US clouds to Norwegian soil or simply upgrading from spinning rust to NVMe, the requirement is the same: Zero Downtime.
The "Lift and Shift" Trap
The amateur approach is the maintenance window. You stop the app, dump the database, transfer it, restore it, and point the app to the new IP. This works for your grandmother's knitting blog. It does not work for a high-transaction SaaS platform serving customers in Oslo and Bergen.
The professional approach is Replication-Based Migration. You don't move the database; you clone it, sync it, and promote the clone. This requires specific infrastructure capable of handling the massive I/O overhead of simultaneous writes and reads during the catch-up phase. This is where your choice of host makes or breaks the project.
Strategy: The Master-Slave Flip
This strategy applies equally to MySQL (GTID replication) and PostgreSQL (Streaming or Logical Replication). The concept is simple: The new CoolVDS instance becomes a replica of your current production server.
1. Preparing the Environment
Before you even touch the data, tune the destination. If you are moving to a CoolVDS instance, you have the advantage of NVMe storage. Do not let the default kernel settings throttle that speed. We need to optimize the TCP stack for the transfer, especially if moving cross-datacenter (e.g., Amsterdam to Oslo).
Add this to /etc/sysctl.conf on the destination server:
# Optimize for high-throughput data transfer
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_window_scaling = 1
# Protect against SYN floods during switchover
net.ipv4.tcp_syncookies = 1
2. MySQL 8.0 Configuration for GTID
If you are still running MySQL 5.5, stop reading and update. For everyone else on 5.7 or 8.0, Global Transaction Identifiers (GTID) are the only sane way to manage replication. It allows you to switch masters without tracking binary log positions manually.
Ensure your my.cnf on the source server has these settings enabled. A restart might be required if they weren't already set, which is the only downtime you should schedule.
[mysqld]
server-id = 1
log_bin = /var/log/mysql/mysql-bin.log
binlog_format = ROW
gtid_mode = ON
enforce_gtid_consistency = ON
log_slave_updates = ON
Pro Tip: Never use mysqldump for datasets larger than 50GB. It is single-threaded and locks tables. Use Percona XtraBackup. It copies the InnoDB data files directly while the server runs, causing negligible locking.
3. The Initial Sync
We use XtraBackup to create the seed data for our CoolVDS replica. This tool streams the backup securely over SSH.
xtrabackup --backup --stream=xbstream --target-dir=./ | \
ssh user@new-coolvds-ip "xbstream -x -C /var/lib/mysql/data/"
Once the data is on the new server, you prepare it (apply the transaction logs) and start the server.
4. Configuring the Replica
Now, we tell the new server to catch up. Since we are using GTID, we don't need to hunt for log positions. The backup tool should have saved the GTID executed at the time of backup.
CHANGE MASTER TO
MASTER_HOST='old-server-ip',
MASTER_USER='repl_user',
MASTER_PASSWORD='secure_password',
MASTER_AUTO_POSITION = 1;
START SLAVE;
Run SHOW SLAVE STATUS\G and watch the Seconds_Behind_Master metric. This is the moment of truth. If your new VPS has slow disk I/O, this number will never reach zero. The incoming writes from production will outpace the replica's ability to write to disk.
This is why we standardized on KVM virtualization with local NVMe at CoolVDS. In my benchmarks, the random write IOPS on our nodes sustain the heavy catch-up phase where standard cloud block storage often chokes.
The Switchover: Minimizing Impact
Once the replica is in sync (0 seconds behind), you are ready. But how do you switch without breaking user sessions?
The Proxy Approach
If you aren't using a database proxy like ProxySQL or HAProxy, you are making life hard for yourself. A proxy sits between your app and the database.
| Direct Connection | ProxySQL Connection |
|---|---|
| App needs config change to switch DB IP. | App connects to Proxy; Proxy handles backend switch. |
| DNS propagation delays (TTL). | Instant switchover (milliseconds). |
| Broken transactions during switch. | Queries can be queued/paused during switch. |
During the cutover, you set the old master to read_only = 1. This prevents split-brain scenarios where data is written to both places. Then, you point ProxySQL to the CoolVDS instance as the new writer.
The Legal Angle: Schrems II and Data Residency
Technical execution is only half the battle in 2020. Since the CJEU invalidated the Privacy Shield framework in July, storing personal data of Norwegian citizens on US-owned cloud infrastructure (even if the datacenter is in Europe) is legally risky. The concept of "Data Sovereignty" is paramount.
Migrating to a provider like CoolVDS, which operates under strict Norwegian/EEA jurisdiction without upstream dependencies on US hyperscalers, simplifies your GDPR compliance significantly. You know exactly where the physical drives are: likely spinning (or rather, flashing) in a datacenter in Oslo or nearby, subject to Norwegian privacy laws.
Post-Migration Verification
You aren't done until you verify data integrity. Do not trust; verify. Use pt-table-checksum from the Percona Toolkit to ensure the new master has the exact same data as the old one.
pt-table-checksum --nocheck-replication-filters \
--no-check-binlog-format --databases=production_db \
h=localhost,u=root,p=password
If the DIFFS column is 0, congratulations. You have successfully moved your critical infrastructure to a high-performance environment without your users noticing a thing.
Next Steps: Don't let IO wait times kill your application's performance. Spin up a test instance on CoolVDS today and benchmark the NVMe throughput against your current provider. The results usually speak for themselves.