Browse code

ndb_redis: adds support for sentinel

Julien Ammous authored on 03/04/2018 12:08:53
Showing 4 changed files
... ...
@@ -165,6 +165,15 @@ password")
165 165
 
166 166
 # Unix domain socket
167 167
 modparam("ndb_redis", "server", "name=srvY;unix=/tmp/redis.sock;db=3")
168
+
169
+# sentinel (for a redis slave)
170
+modparam("ndb_redis", "server", "name=srvZ;sentinel_group=group_name;sentinel_ma
171
+ster=0;sentinel=1.2.3.4:26379;sentinel=1.2.3.5:26379")
172
+
173
+# sentinel (for a redis master)
174
+modparam("ndb_redis", "server", "name=srvZ;sentinel_group=group_name;sentinel_ma
175
+ster=1;sentinel=1.2.3.4:26379;sentinel=1.2.3.5:26379")
176
+
168 177
 ...
169 178
 
170 179
 3.2. init_without_redis (integer)
... ...
@@ -89,6 +89,13 @@ modparam("ndb_redis", "server", "name=srvX;addr=127.0.0.2;port=6379;db=4;pass=my
89 89
 
90 90
 # Unix domain socket
91 91
 modparam("ndb_redis", "server", "name=srvY;unix=/tmp/redis.sock;db=3")
92
+
93
+# sentinel (for a redis slave)
94
+modparam("ndb_redis", "server", "name=srvZ;sentinel_group=group_name;sentinel_master=0;sentinel=1.2.3.4:26379;sentinel=1.2.3.5:26379")
95
+
96
+# sentinel (for a redis master)
97
+modparam("ndb_redis", "server", "name=srvZ;sentinel_group=group_name;sentinel_master=1;sentinel=1.2.3.4:26379;sentinel=1.2.3.5:26379")
98
+
92 99
 ...
93 100
 </programlisting>
94 101
 		</example>
... ...
@@ -68,9 +68,9 @@ int redis_append_formatted_command(redisContext *c, const char *cmd, size_t len)
68 68
  */
69 69
 int redisc_init(void)
70 70
 {
71
-	char addr[256], pass[256], unix_sock_path[256];
71
+	char addr[256], pass[256], unix_sock_path[256], sentinel_group[256];
72 72
 
73
-	unsigned int port, db, sock = 0, haspass = 0;
73
+	unsigned int port, db, sock = 0, haspass = 0, sentinel_master = 1;
74 74
 	redisc_server_t *rsrv=NULL;
75 75
 	param_t *pit = NULL;
76 76
 	struct timeval tv_conn;
... ...
@@ -90,6 +90,9 @@ int redisc_init(void)
90 90
 
91 91
 	for(rsrv=_redisc_srv_list; rsrv; rsrv=rsrv->next)
92 92
 	{
93
+		char sentinels[MAXIMUM_SENTINELS][256];
94
+		uint8_t sentinels_count = 0;
95
+		
93 96
 		port = 6379;
94 97
 		db = 0;
95 98
 		haspass = 0;
... ...
@@ -115,6 +118,74 @@ int redisc_init(void)
115 118
 			} else if(pit->name.len==4 && strncmp(pit->name.s, "pass", 4)==0) {
116 119
 				snprintf(pass, sizeof(pass)-1, "%.*s", pit->body.len, pit->body.s);
117 120
 				haspass = 1;
121
+			} else if(pit->name.len==14 && strncmp(pit->name.s, "sentinel_group", 14)==0) {
122
+				snprintf(sentinel_group, sizeof(sentinel_group)-1, "%.*s", pit->body.len, pit->body.s);
123
+			} else if(pit->name.len==15 && strncmp(pit->name.s, "sentinel_master", 15)==0) {
124
+				if(str2int(&pit->body, &sentinel_master) < 0)
125
+					sentinel_master = 1;
126
+			} else if(pit->name.len==8 && strncmp(pit->name.s, "sentinel", 8)==0) {
127
+				if( sentinels_count < MAXIMUM_SENTINELS ){
128
+					snprintf(sentinels[sentinels_count], sizeof(sentinels[sentinels_count])-1, "%.*s", pit->body.len, pit->body.s);
129
+					sentinels_count++;
130
+				}
131
+				else {
132
+					LM_ERR("too many sentinels, maximum %d supported.\n", MAXIMUM_SENTINELS);
133
+					return -1;
134
+				}
135
+			}
136
+		}
137
+		
138
+		// if sentinels are provided, we need to connect to them and retrieve the redis server
139
+		// address / port
140
+		if(sentinels_count > 0) {
141
+			for(int i= 0; i< sentinels_count; i++) {
142
+				char *sentinelAddr = sentinels[i];
143
+				char *pos;
144
+				redisContext *redis;
145
+				redisReply *res, *res2;
146
+				
147
+				port = 6379;
148
+				if( (pos = strchr(sentinelAddr, ':')) != NULL ) {
149
+					port = atoi(pos+1);
150
+					pos[i] = '\0';
151
+				}
152
+				
153
+				redis = redisConnectWithTimeout(sentinelAddr, port, tv_conn);
154
+				if( redis ) {
155
+					if(sentinel_master != 0) {
156
+						res = redisCommand(redis, "SENTINEL get-master-addr-by-name %s", sentinel_group);
157
+						if( res && (res->type == REDIS_REPLY_ARRAY) && (res->elements == 2) ) {
158
+							strncpy(addr, res->element[0]->str, res->element[0]->len + 1);
159
+							port = atoi(res->element[1]->str);
160
+							
161
+							
162
+							printf("sentinel replied: %s:%d\n", addr, port);
163
+						}
164
+					}
165
+					else {
166
+						res = redisCommand(redis, "SENTINEL slaves %s", sentinel_group);
167
+						if( res && (res->type == REDIS_REPLY_ARRAY) ) {
168
+							
169
+							for(int row = 0; row< res->elements; row++){
170
+								res2 = res->element[row];
171
+								
172
+								for(int i= 0; i< res2->elements; i+= 2) {
173
+									if( strncmp(res2->element[i]->str, "ip", 2) == 0 ) {
174
+										strncpy(addr, res2->element[i+1]->str, res2->element[i+1]->len);
175
+										addr[res2->element[i+1]->len] = '\0';
176
+									}
177
+									else if( strncmp(res2->element[i]->str, "port", 4) == 0) {
178
+										port = atoi(res2->element[i+1]->str);
179
+										break;
180
+									}
181
+								}
182
+								
183
+							}
184
+							
185
+							printf("slave for %s: %s:%d\n", sentinel_group, addr, port);
186
+						}
187
+					}
188
+				}
118 189
 			}
119 190
 		}
120 191
 
... ...
@@ -36,6 +36,7 @@
36 36
 
37 37
 #define MAXIMUM_PIPELINED_COMMANDS 1000
38 38
 #define MAXIMUM_NESTED_KEYS 10
39
+#define MAXIMUM_SENTINELS 5
39 40
 #define LM_DBG_redis_reply(rpl) print_redis_reply(L_DBG,(rpl),0)
40 41
 
41 42
 int redisc_init(void);