nginx http proxy模块缓冲区管理

        最近在工作中使用了nginx,我们使用的是openresty,使用的是http proxy模块,即将nginx作为后端服务器的反向代理来使用。这里我们主要分析nginx作为反向代理服务器时的缓存管理。

        这里所说的缓存指的是对后端服务器响应体的缓存,而对缓存的管理无非就是指如何高效地管理从后端服务器到客户端的响应头部和body。一般来说,nginx到后端服务器的传输速度大于客户端至nginx的传输速度(一般是内网vs外网),这种速度上的差异使得nginx必须要设法管理好那些暂存在nginx的响应,适当时候将它们发出去。

ngx_buf_t & ngx_chain_t

        在仔细分析之前,我们首先描述下nginx缓冲区的管理,nginx与缓冲区管理相关的数据结构有以下几个:

typedef struct ngx_buf_s  ngx_buf_t;

struct ngx_buf_s {
    u_char          *pos;    // 缓冲区数据部分的开始地址
    u_char          *last;   // 缓冲区数据部分的结束地址
    off_t            file_pos;
    off_t            file_last;

    u_char          *start;         // 缓冲区起始地址
    u_char          *end;           // 缓冲区结束地址
    ngx_buf_tag_t    tag;
    ngx_file_t      *file;
    ngx_buf_t       *shadow;

    /* the buf's content could be changed */
    unsigned         temporary:1;

    /*
     * the buf's content is in a memory cache or in a read only memory
     * and must not be changed
     */
    unsigned         memory:1;

    /* the buf's content is mmap()ed and must not be changed */
    unsigned         mmap:1;

    unsigned         recycled:1;
    unsigned         in_file:1;
    unsigned         flush:1;
    unsigned         sync:1;
    unsigned         last_buf:1;
    unsigned         last_in_chain:1;

    unsigned         last_shadow:1;
    unsigned         temp_file:1;

    /* STUB */ int   num;
};
上面的结构就是缓冲区的管理结构(类似linux page cache的struct page),pos和last分别记录缓冲区有效数据的范围,start和end则是缓冲区的地址范围。如下图所示:


struct ngx_chain_s {
    ngx_buf_t    *buf;
    ngx_chain_t  *next;
};
这个数据结构会将多个buffer链接成链表。

http proxy 缓冲区管理


        前面说过,这里的缓冲区主要是管理那些已经从后端服务器读取但尚未来得及发送给客户端的响应。缓冲区的管理看起来简单,实则比较复杂,这里面涉及到http proxy模块里面很多的缓冲区链表之间的数据拷贝等逻辑,我们会在下面仔细梳理。

  • free_raw buffers
        我们接触到的第一个缓冲区链表是free_raw_buffers。顾名思义,这就是最原始缓冲区,即没有存储数据或者只缓存了部分数据的缓冲区,每次有数据到来时,会从该链表上获取缓冲区。该缓冲区的数量是通过nginx参数配置的,而且是按需分配,并非一次性分配好。注意:只存储了部分数据的buffer会被存放在链表的标头,因为数据肯定需要按照偏移顺序紧接着上次接收数据的后面来存放,如下图所示:

  • in buffers
        当从free_raw_bufs摘取的缓冲区被写满数据以后,其就会被放在另外一个链表in。也就是说,in链表保存的是从上游服务器读取的但尚未经过处理的响应数据,等待接受进一步处理,当然这些响应数据是按照偏移有序组织在链表上的,如下图所示:


  • out buffers 
        nginx为每个请求能分配的缓冲区数量有限,可通过指令设置。超过该限制后无法再分配出新的缓冲区了,因此我们需要回收利用已分配的缓冲区。回收的方法是将部分缓冲区中存储的响应数据写到磁盘上,对写入磁盘文件的所有缓冲区也被组织在一个链表上,称为out链表。
        具体写入的逻辑是:每次从上面的in链表中取出若干缓冲区(可写入的缓冲区数量由nginx指令控制),然后调用ngx_write_chain_to_temp_file()将这些缓冲区响应数据写入临时文件。写入完成后需要更新out链表上的buffer状态。其实更准确来说,out链表上保存的buffer并非实际数据,而是一种映射关系,维护内存响应和文件中数据的映射。另外,不必为每个内存buffer都维护一个映射关系,如果上一次映射的范围与本次写入的正好连续,则没必要再弄一个新的映射关系出来,直接更新原有的映射关系状态即可。关于这点,我们会在后面的博客中仔细阐述如何将内存中的响应数据写入临时文件中。
  • free buffers
        另外,对于释放的buffer,会将其存储在一个链表free上,这样下次再来申请的时候就无需从系统分配了,而是直接从free链表分配即可,其实free链表上存储的并不是存储数据的缓冲区,而是管理缓冲区的数据结构,这个我们在前面说过。
        比如,我们在将内存中的buffer数据写入临时文件后其实就可以释放这些缓冲区以存储接下来的响应数据了。因此涉及释放缓冲区的操作,这里的释放会涉及到释放存储数据的原始缓冲区以及释放存储缓冲区管理结构的数据结构,而free buffers上存放的是管理缓冲区的数据结构。关于这里面的复杂过程我们也会在后面详述。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值