Skip to content

Commit 7285a50

Browse files
author
Debian
committed
cachedb_redis: add dynamic cluster topology management and observability
Replace the static cluster topology (built once at startup, never refreshed) with runtime discovery and automatic refresh: Topology discovery and refresh: - Probe CLUSTER SHARDS (Redis 7+) with fallback to CLUSTER SLOTS (Redis 3+) for backward compatibility - O(1) slot_table[16384] lookup replaces per-query linked-list scan - Automatic topology refresh on MOVED redirect, connection failure, or query targeting an unmapped slot (rate-limited to 1/sec) - Dynamic node creation when MOVED points to an unknown endpoint - Stale node pruning during refresh with safe connection cleanup - Cap redirect loop at 5 max redirects to prevent worker hang on pathological cluster state Cluster observability via MI commands: - redis_cluster_info: full topology dump including per-node connection status, slot assignments, query/error/moved/ask counters, and last activity timestamp - redis_cluster_refresh: trigger manual topology refresh (bypasses rate limit) - redis_ping_nodes: per-node PING with microsecond latency reporting - All MI commands support optional group filter parameter Statistics: - redis_queries, redis_queries_failed, redis_moved, redis_ask, redis_topology_refreshes (module-level stat counters) - Per-node query, error, moved, ask counters in redis_cluster_info Hash slot correctness: - Hash tag {…} extraction per Redis Cluster specification - CRC16 modulo 16384 replaces bitwise AND with slots_assigned ASK redirect handling: - Detect ASK responses alongside existing MOVED handling - Send ASKING command to target node before retrying original query - Do not update slot map (ASK is a temporary mid-migration redirect) - Refactor parse_moved_reply into parse_redirect_reply with prefix parameter; inline wrappers for backward compatibility Connection reliability: - TCP keepalive via redis_keepalive parameter (default 10s) - Stack allocation for redis_moved structs (eliminates OOM paths) - NULL guards on malformed CLUSTER SHARDS/SLOTS reply elements - Integer overflow protection in slot and port parsing - NULL guards in MI command handlers for group_name/initial_url Documentation: - New section: Redis Cluster Support (topology discovery, automatic refresh, MOVED/ASK handling, hash tags) - MI command reference: redis_cluster_info, redis_cluster_refresh, redis_ping_nodes - Authentication URL format documentation (classic, ACL, no-auth) - New parameter: redis_keepalive Test suite (186 tests): - C unit tests: hash slot calculation (37), MI counter helpers (41) - Integration: topology startup (12), ASK redirect (16), topology refresh (13), MI commands (50), edge cases (16) - Trap EXIT handlers for safe cluster state restoration - python3 preflight checks for JSON-dependent tests Depends on: OpenSIPS#3815 (hash tag + modulo fix), OpenSIPS#3852 (ASK redirect)
1 parent edee7da commit 7285a50

21 files changed

Lines changed: 5638 additions & 340 deletions

modules/cachedb_redis/README

Lines changed: 286 additions & 38 deletions
Large diffs are not rendered by default.

modules/cachedb_redis/cachedb_redis.c

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,14 @@
3939
#include "../../cachedb/cachedb.h"
4040

4141
#include "cachedb_redis_dbase.h"
42+
#include "cachedb_redis_mi.h"
43+
#include "../../statistics.h"
4244

4345
static int mod_init(void);
4446
static int child_init(int);
4547
static void destroy(void);
4648

47-
static str cache_mod_name = str_init("redis");
49+
str cache_mod_name = str_init("redis");
4850
struct cachedb_url *redis_script_urls = NULL;
4951

5052
int set_connection(unsigned int type, void *val)
@@ -62,6 +64,7 @@ static const param_export_t params[]={
6264
{ "ftsearch_json_prefix", STR_PARAM, &fts_json_prefix.s},
6365
{ "ftsearch_max_results", INT_PARAM, &fts_max_results},
6466
{ "ftsearch_json_mset_expire", INT_PARAM, &fts_json_mset_expire},
67+
{ "redis_keepalive", INT_PARAM, &redis_keepalive},
6568
{0,0,0}
6669
};
6770

@@ -92,6 +95,33 @@ static const dep_export_t deps = {
9295
},
9396
};
9497

98+
static const stat_export_t mod_stats[] = {
99+
{"redis_queries", 0, &redis_stat_queries },
100+
{"redis_queries_failed", 0, &redis_stat_queries_failed },
101+
{"redis_moved", 0, &redis_stat_moved },
102+
{"redis_topology_refreshes", 0, &redis_stat_topology_refreshes},
103+
{0, 0, 0}
104+
};
105+
106+
static const mi_export_t mi_cmds[] = {
107+
{ MI_REDIS_CLUSTER_INFO, 0, MI_NAMED_PARAMS_ONLY, 0, {
108+
{mi_redis_cluster_info, {0}},
109+
{mi_redis_cluster_info_1, {"group", 0}},
110+
{EMPTY_MI_RECIPE}}, {0}
111+
},
112+
{ MI_REDIS_CLUSTER_REFRESH, 0, MI_NAMED_PARAMS_ONLY, 0, {
113+
{mi_redis_cluster_refresh, {0}},
114+
{mi_redis_cluster_refresh_1, {"group", 0}},
115+
{EMPTY_MI_RECIPE}}, {0}
116+
},
117+
{ MI_REDIS_PING_NODES, 0, MI_NAMED_PARAMS_ONLY, 0, {
118+
{mi_redis_ping_nodes, {0}},
119+
{mi_redis_ping_nodes_1, {"group", 0}},
120+
{EMPTY_MI_RECIPE}}, {0}
121+
},
122+
{EMPTY_MI_EXPORT}
123+
};
124+
95125
/** module exports */
96126
struct module_exports exports= {
97127
"cachedb_redis", /* module name */
@@ -103,8 +133,8 @@ struct module_exports exports= {
103133
0, /* exported functions */
104134
0, /* exported async functions */
105135
params, /* exported parameters */
106-
0, /* exported statistics */
107-
0, /* exported MI functions */
136+
mod_stats, /* exported statistics */
137+
mi_cmds, /* exported MI functions */
108138
0, /* exported pseudo-variables */
109139
0, /* exported transformations */
110140
0, /* extra processes */

0 commit comments

Comments
 (0)