Limits and gotchas: migrate from Valkey to KiviDB

Limits and gotchas. Migrate to KiviDB: Move from Redis, Valkey, ElastiCache, Redis Cloud, Aiven, Aerospike, Hazelcast and more: getting the data out, loading

What does not come across

  • Valkey 9 snapshots, by any method that reads them directly. Use RedisShake sync_reader.
  • Search indexes and Bloom filters. Run FT.CREATE again; rebuild Bloom filters from the source data.
  • Sentinel. There is none in KiviDB.
  • Configuration and users, which are not in a snapshot. Set them on KiviDB.

Gotchas

  • Key names must be valid UTF-8. KiviDB refuses other key names in SET, RESTORE and the commands copy tools send (ERR key must be valid UTF-8), and RIOT stops at the first one. Check before you copy:

    python3 - "redis://:$PASSWORD@source.internal:6379" <<'EOF'
    import sys, redis
    bad = 0
    for db in range(16):  # the databases your source uses
        r = redis.Redis.from_url(sys.argv[1], db=db)
        for key in r.scan_iter(count=1000):
            try:
                key.decode("utf-8")
            except UnicodeDecodeError:
                bad += 1
                print(f"db{db} {key!r}")
    print(f"{bad} key names are not valid UTF-8")
    EOF
    

    Rename those keys at the source, or leave them out of the copy.

  • A KiviDB replica of a Valkey 9 primary keeps retrying the full sync and stays empty. Watch for not a Redis RDB file in KiviDB's log.

  • RedisShake stops at the first hash with field expiry (ERR Bad data format). Filter those keys out first.

  • Tested with Valkey 8.1.11 (replication, RDB file, --preload-file, MIGRATE, RedisShake sync_reader and scan_reader, RIOT) and Valkey 9.0.7 and 9.1.3 (RedisShake sync_reader with the field-expiry script, RIOT --struct), with every core data type, TTLs, hash field expiry, streams with consumer groups and a second logical database.