Cut over: migrate from DigitalOcean to KiviDB

Cut over. Migrate to KiviDB: Move from Redis, Valkey, ElastiCache, Redis Cloud, Aiven, Aerospike, Hazelcast and more: getting the data out, loading it, cuttin

  1. Rehearse. Copy into a test KiviDB, run your test suite against it, and run the verify script. Time the copy.

  2. Turn on keyspace notifications on the cluster. The copy tools follow changes through them, and CONFIG SET is disabled, so set valkey_notify_keyspace_events to KEA in Settings → Advanced Configurations, or:

    doctl databases configuration update <cluster-id> --engine valkey \
      --config-json '{"valkey_notify_keyspace_events":"KEA"}'
    
  3. Start the long copy. RedisShake with ksn = true, or RIOT with --mode LIVE (on Valkey 9, RIOT with --mode LIVE --struct). Leave it running. It copies every key, then applies the changes your application makes while it runs. RedisShake needs rdb_restore_command_behavior = "rewrite" here: a key that changes is copied again over the old copy, and with the default setting the first such key stops the copy with a BUSYKEY error. If the notifications are not on, neither tool says so: the copy simply misses every change made after the scan passed a key.

  4. Check it has caught up. Run the verify script against both sides. A few keys changing in flight is expected.

  5. Stop writes to DigitalOcean. Put the application in maintenance mode, or stop the writers.

  6. Let the last changes arrive (a few seconds), stop the copy, and run the verify script again. The key counts should now match.

  7. Switch the application to KiviDB (see below) and start it.

  8. Watch errors and latency. Keep the DigitalOcean cluster, untouched, until you are sure. It has no backups: once you destroy it, its data is gone.

Without keyspace notifications, the copy is a one-off: stop writes at step 3 and keep them stopped until step 7.

Rolling back. Until step 7 nothing points at KiviDB and nothing is lost. After it, writes go only to KiviDB, and copying them back is narrower than copying them in. KiviDB's DUMP payloads are in its own format, which Valkey refuses, so RedisShake and RIOT's default mode fail with ERR DUMP payload version or checksum are wrong. RIOT reads through Lua scripts, so it also needs Lua on the KiviDB it reads from. What works is RIOT with --struct, reading from a KiviDB that has Lua (the lua or full build, or the Lua add-on on Cloud):

riot-standalone-4.3.0-linux-x86_64/bin/riot replicate --struct \
  --source-tls --source-cacert kividb-ca.pem --source-user kividbapp --source-pass "$KIVIDB_PASSWORD" \
  --target-tls --target-user default --target-pass "$DO_PASSWORD" \
  --ttl-tolerance 10s \
  rediss://your-name.cloud.kividb.io:6380 \
  rediss://my-cache-do-user-1234567-0.db.ondigitalocean.com:25061

Rehearse it if you may need it. The simplest safety net needs no copy at all: for the first days after the switch, have the application write to both KiviDB and the DigitalOcean cluster (reads from KiviDB only), so the DigitalOcean cluster stays current and switching back is a change of address. Without that, and without Lua on KiviDB, the way back is to keep the DigitalOcean cluster untouched and accept losing the writes made since the switch.

For a cache your application can rebuild, there is a simpler way: point the application at an empty KiviDB and let it fill.