nginx细节

2013年2月5日 | 分类: 操作系统, 编程技术, 网络性能 | 标签:

nginx中有很多细节的地方做了性能优化,举几个例子。
例子1:
自定义字符串类型,在/src/core/config.h中,对字符串进行了封装,包含长度,和具体字符

typedef struct {
    size_t      len;
    u_char     *data;
} ngx_str_t;

typedef struct {
    ngx_str_t   key;
    ngx_str_t   value;
} ngx_keyval_t;

这样做的好处是,后续的字符操作,长度不需要再重复计算,而是直接引用,而且很多字符串string.h里面的操作差不多都重新实现了一遍。

例子2:
错误码的预定义,在main里面,刚开始会调用ngx_strerror_init,这个函数做的事情是把系统的错误码和错误信息,存在ngx_sys_errlist中,省去了出错时候再调用strerror()查找错误原因的开销,能减少系统调用就要避免。

ngx_int_t
ngx_strerror_init(void)
{
    char       *msg;
    u_char     *p;
    size_t      len;
    ngx_err_t   err;

    /*
     * ngx_strerror() is not ready to work at this stage, therefore,
     * malloc() is used and possible errors are logged using strerror().
     */
    
    //预分配NGX_SYS_NERR个字符对象,NGX_SYS_NERR在linux中是132
    len = NGX_SYS_NERR * sizeof(ngx_str_t);
    
    //分配全局错误列表空间
    ngx_sys_errlist = malloc(len);
    if (ngx_sys_errlist == NULL) {
        goto failed;
    }

    for (err = 0; err < NGX_SYS_NERR; err++) {
        //获取系统的每一个错误编号原因和长度
        msg = strerror(err);
        len = ngx_strlen(msg);

        p = malloc(len);
        if (p == NULL) {
            goto failed;
        }

        //赋值错误id和错误原因到全局列表中
        ngx_memcpy(p, msg, len);
        ngx_sys_errlist[err].len = len;
        ngx_sys_errlist[err].data = p;
    }

    return NGX_OK;

failed:

    err = errno;
    ngx_log_stderr(0, "malloc(%uz) failed (%d: %s)", len, err, strerror(err));

    return NGX_ERROR;
}

在这里nginx并没有使用其内存池,而是使用系统默认的malloc进行内存分配,因为在这里程序还没有创建内存池,而后续的初始化工作,可能出现未知的错误,那么,该处初始化的错误数组就可以派上用场。

例子3:
nignx的内存管理也用到了自己的内存池,但是注意到在申请内存时,有两个函数:ngx_palloc和ngx_pnalloc,两者的区别是一个进行了对齐,一个没有对齐,取整可以降低CPU读取内存的次数,提高性能。
对齐使用了ngx_align_ptr(p,a),把指针p按照a的size进行对齐。

 #define ngx_align_ptr(p, a)                            \
(u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))

总之nginx里面很多小的地方都做的很极致,希望有时间进一步发现,nginx的文章比较多,读起来比haproxy方便很多。

本文的评论功能被关闭了.