apache / apisix

The Cloud-Native API Gateway
https://apisix.apache.org/blog/
Apache License 2.0
14.5k stars 2.52k forks source link

request help: question about dns_resolver_valid and resolver_timeout #4010

Closed diaosj closed 3 years ago

diaosj commented 3 years ago

Issue description

Two questions about dns_resolver_valid and resolver_timeout.

  1. What's the default unit? In my memory, the default unit is second rather than millisecond. And I found this comment in config.yaml: https://github.com/apache/apisix/blob/master/conf/config-default.yaml#L111 I guess the description "The unit is second." is valid for both dns_resolver_valid and resolver_timeout? And I found Nginx doc that says: "A value without a suffix means seconds. It is recommended to always specify a suffix." http://nginx.org/en/docs/syntax.html But the Nginx code here: https://github.com/nginx/nginx/blob/eb52de83114e8d98722cd17ec8435c47956b6315/src/http/ngx_http_core_module.c#L731-L733 resolver_timeout seems to be used with ngx_conf_set_msec_slot. "msec" here implies that unit is millisecond? I'm confused. And I tried to set this param like this: resolver_timeout: 5s. But APISIX said it can only be assigned with a number. Haha.

  2. In older versions, both dns_resolver_valid and resolver_timeout are enabled. Now only resolver_timeout is enabled in config.yaml. Curious about this change. ^_^

tokers commented 3 years ago

What's the default unit?

ngx_conf_set_msec_slot calls ngx_parse_time, in such a case, when the time doesn't contain the unit, nginx treats it a duration in seconds.

In older versions, both dns_resolver_valid and resolver_timeout are enabled. Now only resolvertimeout is enabled in config.yaml. Curious about this change. ^^

Now by default we use the ttl field in the DNS response as the cache ttl.

diaosj commented 3 years ago

Many thanks.

diaosj commented 3 years ago

What's the default unit?

ngx_conf_set_msec_slot calls ngx_parse_time, in such a case, when the time doesn't contain the unit, nginx treats it a duration in seconds.

Sorry, I reopen this issue. Just to make sure. I see ngx_parse_time is called in ngx_conf_set_msec_slot (https://github.com/nginx/nginx/blob/eb52de83114e8d98722cd17ec8435c47956b6315/src/core/ngx_conf_file.c#L1276):

*msp = ngx_parse_time(&value[1], 0);

I jumped to the definition of ngx_parse_time (https://github.com/nginx/nginx/blob/eb52de83114e8d98722cd17ec8435c47956b6315/src/core/ngx_parse.c#L112):

ngx_int_t
ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec)Ruslan Ermilov, 10 years ago: • Improved ngx_parse_time() code readability.
{
    u_char      *p, *last;
    ngx_int_t    value, total, scale;
    ngx_int_t    max, cutoff, cutlim;
    ngx_uint_t   valid;
    enum {
        st_start = 0,
        st_year,
        st_month,
        st_week,
        st_day,
        st_hour,
        st_min,
        st_sec,
        st_msec,
        st_last
    } step;

    valid = 0;
    value = 0;
    total = 0;
    cutoff = NGX_MAX_INT_T_VALUE / 10;
    cutlim = NGX_MAX_INT_T_VALUE % 10;
    step = is_sec ? st_start : st_month;

    p = line->data;
    last = p + line->len;

    while (p < last) {

        if (*p >= '0' && *p <= '9') {
            if (value >= cutoff && (value > cutoff || *p - '0' > cutlim)) {
                return NGX_ERROR;
            }

            value = value * 10 + (*p++ - '0');
            valid = 1;
            continue;
        }

        switch (*p++) {

        case 'y':
            if (step > st_start) {
                return NGX_ERROR;
            }
            step = st_year;
            max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 365);
            scale = 60 * 60 * 24 * 365;
            break;

        case 'M':
            if (step >= st_month) {
                return NGX_ERROR;
            }
            step = st_month;
            max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 30);
            scale = 60 * 60 * 24 * 30;
            break;

        case 'w':
            if (step >= st_week) {
                return NGX_ERROR;
            }
            step = st_week;
            max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 7);
            scale = 60 * 60 * 24 * 7;
            break;

        case 'd':
            if (step >= st_day) {
                return NGX_ERROR;
            }
            step = st_day;
            max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24);
            scale = 60 * 60 * 24;
            break;

        case 'h':
            if (step >= st_hour) {
                return NGX_ERROR;
            }
            step = st_hour;
            max = NGX_MAX_INT_T_VALUE / (60 * 60);
            scale = 60 * 60;
            break;

        case 'm':
            if (p < last && *p == 's') {
                if (is_sec || step >= st_msec) {
                    return NGX_ERROR;
                }
                p++;
                step = st_msec;
                max = NGX_MAX_INT_T_VALUE;
                scale = 1;
                break;
            }

            if (step >= st_min) {
                return NGX_ERROR;
            }
            step = st_min;
            max = NGX_MAX_INT_T_VALUE / 60;
            scale = 60;
            break;

        case 's':
            if (step >= st_sec) {
                return NGX_ERROR;
            }
            step = st_sec;
            max = NGX_MAX_INT_T_VALUE;
            scale = 1;
            break;

        case ' ':
            if (step >= st_sec) {
                return NGX_ERROR;
            }
            step = st_last;
            max = NGX_MAX_INT_T_VALUE;
            scale = 1;
            break;

        default:
            return NGX_ERROR;
        }

        if (step != st_msec && !is_sec) {
            scale *= 1000;
            max /= 1000;
        }

        if (value > max) {
            return NGX_ERROR;
        }

        value *= scale;

        if (total > NGX_MAX_INT_T_VALUE - value) {
            return NGX_ERROR;
        }

        total += value;

        value = 0;

        while (p < last && *p == ' ') {
            p++;
        }
    }

    if (!valid) {
        return NGX_ERROR;
    }

    if (!is_sec) {
        if (value > NGX_MAX_INT_T_VALUE / 1000) {
            return NGX_ERROR;
        }

        value *= 1000;
    }

    if (total > NGX_MAX_INT_T_VALUE - value) {
        return NGX_ERROR;
    }

    return total + value;
}

The input param is_sec is 0. So the variable step in L136 is assigned to st_month.

step = is_sec ? st_start : st_month;

Seems like to go to case ' ': branch. Then the variable step in L233 is assigned to st_last.

step = st_last;

Then the if (step != st_msec && !is_sec) branch in L242 makes scale to 1000 timed.

scale *= 1000;

Is this what you said, "nginx treats it a duration in seconds"?

tokers commented 3 years ago

Variable step doesn't have a chance to be used since all chars in line is digital.

diaosj commented 3 years ago

OK. Thanks!