Skip to content

Redis keyspace notifications

allfro edited this page Jun 5, 2023 · 5 revisions

Overview

The Redis keyspace notifications can be used as a mean to synchronize session information among different rtpengine instances. This is especially useful if one needs to realize a redundant media relay setup. In such a setup, rtpengine machines can be configured to act, at the same time, both as:

  • active machine:
  • create calls via offer()/answer(), counted as OWN calls.
  • destroy calls either via delete(), TIMEOUT, SILENT_TIMEOUT, FINAL_TIMEOUT or cli commands
  • passive(backup) machine
  • create new calls via SADD notifications, counted as FOREIGN calls.
  • destroy calls via DEL notifications, FINAL_TIMEOUT or cli commands

rtpengine will always differentiate between:

  • OWN calls:
  • created via offer()/answer()
  • destroyed either via delete(), TIMEOUT, SILENT_TIMEOUT, FINAL_TIMEOUT or cli commands
  • FOREIGN calls:
  • created via SADD notifications
  • destroyed either via DEL notifications, FINAL_TIMEOUT or cli commands

How to configure

Suppose starting from repo's /etc/rtpengine/rtpengine.sample.conf file.

Must configure:

rtpengine1
interface=pub1/10.255.255.101;pub2/10.255.255.102;pub3/10.255.255.103
redis=10.255.1.200:6379/1
subscribe-keyspace=2;3
rtpengine2
interface=pub2/10.255.255.102;pub3/10.255.255.103;pub1/10.255.255.101
redis=10.255.1.200:6379/2
subscribe-keyspace=3;1
rtpengine3
interface=pub3/10.255.255.103;pub1/10.255.255.101;pub2/10.255.255.102
redis=10.255.1.200:6379/3
subscribe-keyspace=1;2

Optional configure:

final-timeout=10800

Configuring Redis

Keyspace notifications need to be explicitly enabled in Redis for this feature to work. See https://redis.io/docs/manual/keyspace-notifications/ for more information. To enable this feature from the cli for testing purposes, you can use the following command:

redis-cli CONFIG SET Notify-Keyspace-Events AKE

To ensure that this is working correctly, issue the following command from the Redis CLI:

redis-cli info keyspaces

You should see all of your keyspaces returned after you've made your first call.

The "pub" prefixes are essential for this concept to work! (see README.md -i parameter, logical interfaces for more info).

The first "pub/IP" in the interface list is used to bind OWN calls (calls created via offer()/answer()). The next "pub/IP" in the interface list are used to bind FOREIGN calls (calls created via redis notifications), for redundancy.

To make sure the configuration for the redundancy concept is in place, suppose one OWN call comes to each of the rtpengine1/2/3. Upon rtpengine-ctl list numsessions, one should get the following output on all rtpengine1/2/3:

Current sessions own: 1
Current sessions foreign: 2
Current sessions total: 3

Implementation details

The main implementation idea of this rtpengine feature is based on redis keyspace notifications: [1]

Added implementation parts:

  • redis_notify_loop thread:
  • alloc/free struct redis *redis_notify, struct redisAsyncContext *redis_notify_async_context and libevent struct event_base *redis_notify_event_base
  • attaches the libevent event base to the async context
  • subscribes to notifications for given redis kespaces (redis database numbers) and registers the onRedisNotification() callback to be called upon received notifications.
  • dispatches the event base which makes the tread block
  • upon redis connection lost, the thread unblocks and constantly checks redis connection by pinging it (1 second); this is done until connection re-established and event base is dispatched again which makes the thread block again
  • onRedisNotification() callback:
    • parses the received notification data and extracts keyspace number and callid
    • redis_restore_call() from redis keyspace number(database), on SADD notifications, if the callid is not already found in the hashtable of calls
    • call_destroy() on DEL notifications, if the callid is found in the hashtable of calls
  • rtpengine-ctl ksadd/ksrm/kslist: CLI commands that subscribe/unsubscribe/list keyspaces. Upon ksrm, all the foreign calls are destroyed for that keyspace.
  • rtpengine-ctl terminate all/own/foreign: CLI commands that destroys all/own/foreign calls
  • rtpengine-ctl list sessions all/own/foreign: CLI commands that lists all/own/foreign calls
  • subscribe-keyspace: rtpengine configuration parameter that sets the redis keyspace list to subscribe to
  • final-timeout: rtpengine configuration parameter that sets the number of seconds after ALL calls are destroyed no matter what.

The rtpengine machine can act, at the same time, both as:

  • active machine:
  • create calls via offer()/answer(), counted as OWN calls. Upon new calls, redis_update() is called to make them persistent. This results in all other machines subscribed to this REDIS_DB to receive DEL-SADD notifications. Why?! In order to keep the database "clean" and to guarantee, that there are no old, outdated or incomplete values stored, redis_update() will first delete the REDIS_DB content(for that call) and then add it again, causing this DEL-SADD notifications.
  • destroy calls via delete(), which cause a redis_delete() for the call in the own redis keyspace (REDIS_DB). This results in all other machines subscribed to this REDIS_DB to receive DEL notifications.
  • passive(backup) machine:
  • create calls via SADD notifications, counted as FOREIGN calls, which cause a redis_call_create() for the call with callid found in notifications.
  • destroy calls via DEL notifications, which cause a call_destroy() for the callid found in notifications.

The calls are either:

  • OWN calls: created via offer()/answer() and have struct call c->foreign_call set to 0
  • FOREIGN calls: created via SADD notifications and have struct call c->foreign_call set to 1

[1] http://redis.io/topics/notifications