Migrating Redis databases
There are two templates examples in this repo:
redis
- basic non-persistent template. It is good for review-apps or staging or where no persistence is requiredredis2
- basic persistent template. Good for production where persistence is needed, but cluster is overkill.
Option 1: use SLAVEOF (easier way)
- create a redis workload that will accept data
- execute
SLAVEOF source_host source_port
, if needed usemasterauth
to provide auth details - wait for replication to pick up all changes (usually quickly), use
INFO
orDBSIZE
to check progress - stop app completely and ensure nothing is writing to any of redises
- execute
SLAVEOF no one
to disconnect replication - switch
REDIS_URL
in the app to point to new server - start the app
Option 2: use Redis-RIOT (harder way, where option 1 is not possible)
General considerations:
-
Heroku uses self-signed TLS certificates, which are not verifiable. It needs special handling by setting The tool that satisfies those criteria is Redis-RIOT
-
We are moving to private Redis that don't have a public URL, so have to do it from a Control Plane GVC container.
The tool that satisfies those criteria is Redis-RIOT
Heroku Redis:
As Redis-RIOT says, master redis should have keyspace-notifications set to KA
to be able to do live replication.
To do that:
heroku redis:keyspace-notifications -c KA -a my-app
Connect to heroku Redis CLI:
heroku redis:cli -a my-app
Control Plane Redis:
Connect to Control Plane Redis CLI:
# open cpflow interactive shell
cpflow run bash -a my-app
# install redis CLI if you don't have it in Docker
apt-get update
apt-get install redis -y
# connect to local cloud Redis
redis-cli -u MY_CONTROL_PLANE_REDIS_URL -p 6379
Useful Redis CLI commands:
Quick-check keys qty:
info keyspace
# Keyspace
db0:keys=9496,expires=2941,avg_ttl=77670114535
Create a Control Plane sync workload
name: riot-redis
suspend: true
min/max scale: 1/1
firewall: all firewalls off
image: fieldengineering/riot-redis
CPU: 1 Core
RAM: 1 GB
command args:
--info
-u
rediss://...your_heroku_redis_url...
--tls-verify=NONE
replicate
-h
...your_control_plane_redis_host...
--mode
live
Sync process
- open 1st terminal window with heroku redis CLI, check keys qty
- open 2nd terminal window with controlplane redis CLI, check keys qty
- start sync container
- open logs with
cpflow logs -a my-app -w riot-redis
- re-check keys sync qty again
- stop sync container
Result:
Setting commit interval to default value (1)
Setting commit interval to default value (1)
Job: [SimpleJob: [name=snapshot-replication]] launched with the following parameters: [{}]
Executing step: [snapshot-replication]
Scanning 0% ╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0/8891 (0:00:00 / ?)Job: [SimpleJob: [name=scan-reader]] launched with the following parameters: [{}]
Executing step: [scan-reader]
Scanning 61% ━━━━━━━━━━━━━━━━╸━━━━━━━━━━ 5460/8891 (0:00:07 / 0:00:04) 780.0/sStep: [scan-reader] executed in 7s918ms
Closing with items still in queue
Job: [SimpleJob: [name=scan-reader]] completed with the following parameters: [{}] and the following status: [COMPLETED] in 7s925ms
Scanning 100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 9482/9482 (0:00:11 / 0:00:00) 862.0/s
Step: [snapshot-replication] executed in 13s333ms
Executing step: [verification]
Verifying 0% ╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0/8942 (0:00:00 / ?)Job: [SimpleJob: [name=RedisItemReader]] launched with the following parameters: [{}]
Executing step: [RedisItemReader]
Verifying 2% ╺━━━━━━━━━━━━━━━━━ 220/8942 (0:00:00 / 0:00:19) ?/s >0 T0 ≠Step: [RedisItemReader] executed in 7s521ms
Closing with items still in queue
Job: [SimpleJob: [name=RedisItemReader]] completed with the following parameters: [{}] and the following status: [COMPLETED] in 7s522ms
Verification completed - all OK
Step: [verification] executed in 7s776ms
Job: [SimpleJob: [name=snapshot-replication]] completed with the following parameters: [{}] and the following status: [COMPLETED] in 21s320ms
Total sync time ~1min