01 Why move a database that works
Monitoring history tables grow without limit and dominate everything: disk, backup windows, housekeeper run time, the speed of every graph. TimescaleDB gives Zabbix native compression and time-partitioned history, and it runs on PostgreSQL. The estate in question was on MariaDB.
Migrating a monitoring backend is uncomfortable because the monitoring is the thing that would tell you if the migration went wrong. So the plan is built around keeping a way back open at every step until the new database has been proven.
02 The migration, with the exit held open
- 2.08 million configuration rows moved with pgloader — 0 errors, and row counts matched table by table before anything else happened.
- 39.7 million history rows back-filled in 13 minutes 39 seconds, then TimescaleDB compression enabled on the history hypertables.
- A storage snapshot of the pre-migration server held as the fallback until the new backend had been verified serving live polling.
- The old database dumped, its checksum recorded, and only then dropped.
03 The gotchas, recorded
Four things bit during the migration and are now in the runbook you are handed: a schema-rename step the documentation glosses over; a TimescaleDB version flag the Zabbix release did not yet accept; the frontend needing a different database driver package than the server; and a macro edited in the leftover database that appeared to “not take” because it had been changed in the wrong backend.
04 Then the failover
With the backend settled, the server was clustered using Zabbix's native high availability across two hypervisors, with keepalived holding a floating address in front. Then the primary was stopped.
The active role moved in under ten seconds. The floating address followed. The proxy reconnected. Fail-back was clean. All 55 agents were re-pointed at the floating address, and both nodes were version-pinned so a package upgrade on one cannot split the pair.
- A proxy's server setting takes one address. Without the floating address, a perfectly healthy failover would have blinded roughly 70 proxy-monitored hosts — the server up, the proxy talking to the wrong node.
- keepalived's
nopreemptsilently breaks failover in this configuration. It reads as a sensible setting and produces a floating address that does not move.
05 What this high availability is, and is not
This is high availability across two hypervisors. The two nodes share one database, so the database remains a single point of failure, and it is written down as one. The architecture accommodates a second site, but the standby site has no hardware in it. It is not geo-redundant, and nothing here will call it that.
A failover that has been performed is a capability. A second site that has been designed is a plan. Both are useful; they are not the same thing, and we will not let a proposal blur them.
06 The scale it holds up
The server carried 112 hosts — 100 enabled, 0 unavailable — with 13,093 items and 5,008 triggers, having grown from 45 through 75. Changes are rehearsed on a staging instance first: a cloner refuses any destination that lacks an environment marker macro, and disables every action and media channel after import, so the copy cannot page anyone. The staging instance carried 7 templates, 9,266 items and 3,396 triggers with 0 enabled actions.