Skip to content

Commit 5f9bc1a

Browse files
committed
feat: 支持限流问题修改
1 parent 6407da9 commit 5f9bc1a

File tree

3 files changed

+188
-69
lines changed

3 files changed

+188
-69
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
apiVersion: v1
3+
kind: Service
4+
metadata:
5+
name: nginx-gateway
6+
namespace: default
7+
labels:
8+
app: nginx-gateway
9+
spec:
10+
type: LoadBalancer
11+
ports:
12+
- port: 80
13+
name: service-nginx
14+
targetPort: 80
15+
selector:
16+
app: nginx-gateway
17+
---
18+
apiVersion: apps/v1
19+
kind: StatefulSet
20+
metadata:
21+
labels:
22+
app: nginx-gateway
23+
name: nginx-gateway
24+
namespace: default
25+
spec:
26+
podManagementPolicy: OrderedReady
27+
replicas: 2
28+
selector:
29+
matchLabels:
30+
app: nginx-gateway
31+
serviceName: nginx-gateway
32+
template:
33+
metadata:
34+
labels:
35+
app: nginx-gateway
36+
spec:
37+
containers:
38+
- image: polarismesh/nginx:1.1.0-alpha.6
39+
imagePullPolicy: Always
40+
name: nginx-gateway
41+
resources:
42+
limits:
43+
cpu: "500m"
44+
memory: 1000Mi
45+
terminationMessagePath: /dev/termination-log
46+
terminationMessagePolicy: File
47+
env:
48+
- name: polaris_address
49+
value: polaris.polaris-system:8091
50+
- name: polaris_nginx_namespace
51+
value: default
52+
- name: polaris_nginx_service
53+
value: nginx-gateway
54+
- name: polaris_nginx_ratelimit_enable
55+
value: "true"
56+
restartPolicy: Always
57+
updateStrategy:
58+
rollingUpdate:
59+
partition: 0
60+
type: RollingUpdate
61+

source/nginx_polaris_limit_module/ngx_http_polaris_limit_module.cpp

Lines changed: 100 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ static void split_query(std::string& s, std::map<std::string, std::string>& v);
3333
static void parse_query_token(const std::string& token, std::map<std::string, std::string>& v);
3434
static void get_labels_from_request(ngx_http_request_t* r, const std::set<std::string>*& label_keys,
3535
std::map<std::string, std::string>& keyword_map);
36-
static void join_set_str(const ngx_log_t *log, const std::set<std::string>*& label_keys, std::string& labels_str);
37-
static void join_map_str(const ngx_log_t *log, const std::map<std::string, std::string>& labels, std::string& labels_str);
36+
static void join_map_str(const std::map<std::string, std::string>& labels, std::string& labels_str);
3837

3938
static ngx_command_t ngx_http_polaris_limit_commands[] = {
4039
{ ngx_string("polaris_rate_limiting"),
@@ -88,22 +87,28 @@ static ngx_int_t ngx_http_polaris_limit_handler(ngx_http_request_t *r) {
8887
ngx_http_get_module_loc_conf(r, ngx_http_polaris_limit_module));
8988

9089
if (plcf->enable == 0) {
90+
ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "[PolarisRateLimiting] RateLimit not enabled");
9191
return NGX_DECLINED;
9292
}
93-
polaris::LimitApi* limit_api = Limit_API_SINGLETON.GetLimitApi();
93+
polaris::LimitApi* limit_api = Limit_API_SINGLETON.GetLimitApi(r->connection->log);
9494
if (NULL == limit_api) {
95+
ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "[PolarisRateLimiting] RateLimit api not created");
9596
return NGX_DECLINED;
9697
}
9798

9899
polaris::ServiceKey serviceKey = {plcf->service_namespace, plcf->service_name};
99100
std::string method = std::string(reinterpret_cast<char *>(r->uri.data), r->uri.len);
100-
ret = Limit_API_SINGLETON.GetLimitApi()->FetchRuleLabelKeys(serviceKey, label_keys);
101+
ret = limit_api->FetchRuleLabelKeys(serviceKey, label_keys);
102+
103+
if (ret != 0) {
104+
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "[PolarisRateLimiting] fail to fetchRuleLabelKeys return is: %d", ret);
105+
return NGX_DECLINED;
106+
}
101107

102-
std::string labels_key_str;
103108
if (label_keys != NULL) {
104-
join_set_str(r->connection->log, label_keys, labels_key_str);
109+
ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "[PolarisRateLimiting] FetchRuleLabelKeys labels count %d", label_keys->size());
105110
}
106-
ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "[PolarisRateLimiting] FetchRuleLabelKeys return is: %d, labels %s", ret, labels_key_str.c_str());
111+
107112
if (ret == polaris::kReturnTimeout) {
108113
return NGX_DECLINED; // 拉取labelkey超时,不限流
109114
} else if (ret != polaris::kReturnOk) {
@@ -117,12 +122,13 @@ static ngx_int_t ngx_http_polaris_limit_handler(ngx_http_request_t *r) {
117122
quota_request.SetMethod(uri);
118123
quota_request.SetLabels(labels); // 设置label用于匹配限流规则
119124

120-
std::string labels_values_str;
121-
join_map_str(r->connection->log, labels, labels_values_str);
122-
ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
123-
"[PolarisRateLimiting] quota_request namespace %s, service %s, method %s, labels %s", plcf->service_namespace.c_str(), plcf->service_name.c_str(), uri.c_str(), labels_values_str.c_str());
124-
125-
ret = Limit_API_SINGLETON.GetLimitApi()->GetQuota(quota_request, result);
125+
if (r->connection->log->log_level >= NGX_LOG_DEBUG) {
126+
std::string labels_values_str;
127+
join_map_str(labels, labels_values_str);
128+
ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
129+
"[PolarisRateLimiting] quota_request namespace %s, service %s, method %s, labels %s", plcf->service_namespace.c_str(), plcf->service_name.c_str(), uri.c_str(), labels_values_str.c_str());
130+
}
131+
ret = limit_api->GetQuota(quota_request, result);
126132

127133
ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "[PolarisRateLimiting] GetQuota return is: %d", ret);
128134
if (ret == polaris::kReturnTimeout) {
@@ -138,25 +144,12 @@ static ngx_int_t ngx_http_polaris_limit_handler(ngx_http_request_t *r) {
138144
return NGX_DECLINED;
139145
}
140146

141-
static void join_set_str(const ngx_log_t *log, const std::set<std::string>*& label_keys, std::string& labels_str) {
142-
if (log->log_level < NGX_LOG_DEBUG) {
143-
return;
144-
}
145-
for (std::set<std::string>::iterator it = label_keys->begin(); it != label_keys->end(); it++) {
146-
labels_str += *it;
147-
labels_str += " ";
148-
}
149-
}
150-
151-
static void join_map_str(const ngx_log_t *log, const std::map<std::string, std::string>& labels, std::string& labels_str) {
152-
if (log->log_level < NGX_LOG_DEBUG) {
153-
return;
154-
}
147+
static void join_map_str(const std::map<std::string, std::string>& labels, std::string& labels_str) {
155148
for (std::map<std::string, std::string>::const_iterator it = labels.begin(); it != labels.end(); it++) {
156149
labels_str += it->first;
157150
labels_str += "=";
158151
labels_str += it->second;
159-
labels_str += " ";
152+
labels_str += ",";
160153
}
161154
}
162155

@@ -215,37 +208,38 @@ static char *ngx_http_polaris_limit_conf_set(ngx_conf_t *cf, ngx_command_t *cmd,
215208
}
216209
continue;
217210
}
211+
212+
}
218213

219-
if (!has_namespace) {
220-
char *namespace_env_value = getenv(ENV_NAMESPACE.c_str());
221-
if (NULL != namespace_env_value) {
222-
plcf->service_namespace = std::string(namespace_env_value);
223-
} else {
224-
plcf->service_namespace = DEFAULT_NAMESPACE;
225-
}
226-
ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "[PolarisRateLimiting] use %s as nginx namespace", plcf->service_namespace.c_str());
227-
}
214+
if (!has_namespace) {
215+
char *namespace_env_value = getenv(ENV_NAMESPACE.c_str());
216+
if (NULL != namespace_env_value) {
217+
plcf->service_namespace = std::string(namespace_env_value);
218+
} else {
219+
plcf->service_namespace = DEFAULT_NAMESPACE;
220+
}
221+
ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "[PolarisRateLimiting] use %s as nginx namespace", plcf->service_namespace.c_str());
222+
}
228223

229-
if (!has_service) {
230-
char *service_env_value = getenv(ENV_SERVICE.c_str());
231-
if (NULL != service_env_value) {
232-
plcf->service_name = std::string(service_env_value);
233-
} else {
234-
plcf->service_name = DEFAULT_SERVICE;
235-
}
236-
ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "[PolarisRateLimiting] use %s as nginx service name", plcf->service_name.c_str());
237-
}
224+
if (!has_service) {
225+
char *service_env_value = getenv(ENV_SERVICE.c_str());
226+
if (NULL != service_env_value) {
227+
plcf->service_name = std::string(service_env_value);
228+
} else {
229+
plcf->service_name = DEFAULT_SERVICE;
230+
}
231+
ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "[PolarisRateLimiting] use %s as nginx service name", plcf->service_name.c_str());
232+
}
238233

239-
if (!has_enable) {
240-
char *enable_env_value = getenv(ENV_RATELIMIT_ENABLE.c_str());
241-
if (NULL != enable_env_value) {
242-
std::string enable_str = std::string(enable_env_value);
243-
plcf->enable = string2bool(enable_str) ? 1 : 0;
244-
} else {
245-
plcf->enable = 0;
246-
}
247-
ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "[PolarisRateLimiting] use %V as nginx ratelimit enable", plcf->enable);
248-
}
234+
if (!has_enable) {
235+
char *enable_env_value = getenv(ENV_RATELIMIT_ENABLE.c_str());
236+
if (NULL != enable_env_value) {
237+
std::string enable_str = std::string(enable_env_value);
238+
plcf->enable = string2bool(enable_str) ? 1 : 0;
239+
} else {
240+
plcf->enable = 0;
241+
}
242+
ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "[PolarisRateLimiting] use %d as nginx ratelimit enable", plcf->enable);
249243
}
250244

251245
return static_cast<char *>(NGX_CONF_OK);
@@ -282,6 +276,8 @@ static void *ngx_http_polaris_limit_create_conf(ngx_conf_t *cf) {
282276
}
283277

284278
conf->status_code = 429; // 限流默认返回429
279+
280+
Limit_API_SINGLETON.LoadPolarisConfig();
285281
return conf;
286282
}
287283

@@ -418,18 +414,58 @@ const std::string defaultConfigContent = R"##(
418414
serverConnector:
419415
addresses:
420416
- ${polaris_address}
417+
rateLimiter:
418+
rateLimitCluster:
419+
namespace: Polaris
420+
service: polaris.limiter
421421
)##";
422422

423-
LimitApiWrapper::LimitApiWrapper() {
423+
void LimitApiWrapper::Init(ngx_log_t *logger) {
424+
ngx_log_error(NGX_LOG_NOTICE, logger, 0, "[PolarisRateLimiting] start to init polaris limit api, polaris config %s", m_polaris_config.c_str());
425+
std::string err_msg("");
426+
m_limit = polaris::LimitApi::CreateFromString(m_polaris_config, err_msg);
427+
if (NULL == m_limit) {
428+
ngx_log_error(NGX_LOG_ERR, logger, 0, "[PolarisRateLimiting] fail to create limit api, err: %s", err_msg.c_str());
429+
} else {
430+
ngx_log_error(NGX_LOG_NOTICE, logger, 0, "[PolarisRateLimiting] success to init polaris limit api");
431+
}
432+
m_created = true;
433+
}
434+
435+
/// @brief 将文件内容读入字符串中
436+
std::string readFileIntoString(const std::string& path) {
437+
std::ifstream input_file(path);
438+
return std::string((std::istreambuf_iterator<char>(input_file)), std::istreambuf_iterator<char>());
439+
}
440+
441+
/// @brief 支持环境变量展开
442+
static std::string expand_environment_variables( const std::string &s ) {
443+
if( s.find( "${" ) == std::string::npos ) return s;
444+
445+
std::string pre = s.substr( 0, s.find( "${" ) );
446+
std::string post = s.substr( s.find( "${" ) + 2 );
447+
448+
if( post.find( '}' ) == std::string::npos ) return s;
449+
450+
std::string variable = post.substr( 0, post.find( '}' ) );
451+
std::string value = "";
452+
453+
post = post.substr( post.find( '}' ) + 1 );
454+
455+
const char *v = getenv( variable.c_str() );
456+
if( v != NULL ) value = std::string( v );
457+
458+
return expand_environment_variables( pre + value + post );
459+
}
460+
461+
void LimitApiWrapper::LoadPolarisConfig() {
424462
std::string conf_path = get_polaris_conf_path();
425-
std::string err_msg;
463+
std::string content("");
426464
if (exist_file(conf_path)) {
427-
m_limit = polaris::LimitApi::CreateFromFile(conf_path, err_msg);
428-
} else {
429-
std::cout << "[polaris-limiter] config file " << conf_path << " not exists, create with default config" << std::endl;
430-
m_limit = polaris::LimitApi::CreateFromString(defaultConfigContent, err_msg);
465+
content = readFileIntoString(conf_path);
431466
}
432-
if (NULL == m_limit) {
433-
std::cout << "[polaris-limiter] fail to create limit api, err: " << err_msg << std::endl;
467+
if (content.size() == 0) {
468+
content = defaultConfigContent;
434469
}
470+
m_polaris_config = expand_environment_variables(content);
435471
}

source/nginx_polaris_limit_module/ngx_http_polaris_limit_module.h

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ extern "C" {
2727
#include <fstream>
2828
#include <cstring>
2929
#include <cstdlib>
30+
#include <mutex>
3031

3132
static const char KEY_ENABLE[] = "enable";
3233
static const uint32_t KEY_ENABLE_SIZE = sizeof(KEY_ENABLE) - 1;
@@ -35,9 +36,9 @@ static const uint32_t KEY_NAMESPACE_SIZE = sizeof(KEY_NAMESPACE) - 1;
3536
static const char KEY_SERVICE_NAME[] = "service=";
3637
static const uint32_t KEY_SERVICE_NAME_SIZE = sizeof(KEY_SERVICE_NAME) - 1;
3738

38-
static const std::string ENV_NAMESPACE = "polaris.nginx.namespace";
39-
static const std::string ENV_SERVICE = "polaris.nginx.service";
40-
static const std::string ENV_RATELIMIT_ENABLE = "polaris.nginx.ratelimit.enable";
39+
static const std::string ENV_NAMESPACE = "polaris_nginx_namespace";
40+
static const std::string ENV_SERVICE = "polaris_nginx_service";
41+
static const std::string ENV_RATELIMIT_ENABLE = "polaris_nginx_ratelimit_enable";
4142

4243
static const std::string DEFAULT_NAMESPACE = "default";
4344
static const std::string DEFAULT_SERVICE = "nginx-gateway";
@@ -50,17 +51,38 @@ static const std::string PATH_SBIN = "sbin";
5051

5152
class LimitApiWrapper {
5253
public:
53-
LimitApiWrapper();
54+
55+
LimitApiWrapper() {
56+
m_created = false;
57+
}
58+
59+
void LoadPolarisConfig();
60+
61+
void Init(ngx_log_t *ngx_log);
5462

5563
static LimitApiWrapper& Instance() {
5664
static LimitApiWrapper limit_api;
5765
return limit_api;
5866
}
5967

60-
polaris::LimitApi* GetLimitApi() { return m_limit; }
68+
polaris::LimitApi* GetLimitApi(ngx_log_t *ngx_log) {
69+
if (m_created) {
70+
return m_limit;
71+
}
72+
m_mtx.lock();
73+
if (m_created) {
74+
return m_limit;
75+
}
76+
Init(ngx_log);
77+
m_mtx.unlock();
78+
return m_limit;
79+
}
6180

6281
private:
6382
polaris::LimitApi* m_limit;
83+
std::string m_polaris_config;
84+
std::mutex m_mtx;
85+
bool m_created;
6486
};
6587

6688
#define Limit_API_SINGLETON LimitApiWrapper::Instance()

0 commit comments

Comments
 (0)