Nginx源码阅读-笔记分享

项目笔记链接:https://github.com/mllijiatu/nginx_study

Nginx的架构

Nginx的源码主要分布在src/目录下,而src/目录下主要包含三部分比较重要的模块。

core:包含了Nginx的最基础的库和框架。包括了内存池、链表、hashmap、String等常用的数据结构。

event:事件模块。Nginx自己实现了事件模型。而我们所熟悉的Memcached是使用了Libevent的事件库。自己实现event会性能和效率方便更加高效。

http:实现HTTP的模块。实现了HTTP的具体协议的各种模块,该部分内容量比较大。

…………

Nginx的基础数据结构

数据结构定义

内存池

ngx_pool_t 内存池主结构

点击查看代码
/**
 * Nginx 内存池数据结构
 */
struct ngx_pool_s {
    ngx_pool_data_t       d; 		/* 内存池的数据区域*/
    size_t                max; 		/* 最大每次可分配内存 */
    ngx_pool_t           *current;  /* 指向当前的内存池指针地址。ngx_pool_t链表上最后一个缓存池结构*/
    ngx_chain_t          *chain;	/* 缓冲区链表 */
    ngx_pool_large_t     *large;    /* 存储大数据的链表 */
    ngx_pool_cleanup_t   *cleanup;  /* 可自定义回调函数,清除内存块分配的内存 */
    ngx_log_t            *log;      /* 日志 */
};

ngx_pool_data_t 数据区域结构

点击查看代码
typedef struct {
    u_char               *last;  /* 内存池中未使用内存的开始节点地址 */
    u_char               *end;   /* 内存池的结束地址 */
    ngx_pool_t           *next;  /* 指向下一个内存池 */
    ngx_uint_t            failed;/* 失败次数 */
} ngx_pool_data_t;

ngx_pool_large_t 大数据块结构

点击查看代码
struct ngx_pool_large_s {
    ngx_pool_large_t     *next;   /* 指向下一个存储地址 通过这个地址可以知道当前块长度 */
    void                 *alloc;  /* 数据块指针地址 */
};

ngx_pool_cleanup_t 自定义清理回调的数据结构

点击查看代码
struct ngx_pool_cleanup_s {
    ngx_pool_cleanup_pt   handler;  /* 清理的回调函数 */
    void                 *data; 	/* 指向存储的数据地址 */
    ngx_pool_cleanup_t   *next; 	/* 下一个ngx_pool_cleanup_t */
};

数组

ngx_array_t 数组的基础数据结构

点击查看代码
/* 数组Array数据结构 */
typedef struct {
    void        *elts; 		/* 指向数组第一个元素指针*/
    ngx_uint_t   nelts; 	/* 未使用元素的索引*/
    size_t       size; 		/* 每个元素的大小,元素大小固定*/
    ngx_uint_t   nalloc;	/* 分配多少个元素 */
    ngx_pool_t  *pool;  	/* 内存池*/
} ngx_array_t;

*elts:指向数组的第一个元素的指针地址
nelts:未使用的元素的计数器
size:每个元素的大小,元素大小是固定的。
nalloc:一共分配了多少个元素。如果元素不够用,Nginx会数组会进行自动扩容
pool:数组的数据结构ngx_array_t和元素所需要的内存都会分配在pool内存池上。

缓冲区结构

Nginx的buf缓冲区数据结构,主要用来存储非常大块的内存。ngx_buf_t数据结构也贯穿了整个Nginx。

Nginx的缓冲区设计是比较灵活的,可以自定义管理业务层面的缓冲区链表,也可以将空闲的缓冲区链表交还给内存池pool->chain结构。
缓冲区ngx_buf_t是nginx处理大数据的关键数据结构,它既应用于内存数据也应用于磁盘数据。

缓冲区内存块的数据结构 ngx_buf_t

点击查看代码
typedef struct ngx_buf_s  ngx_buf_t;
/**
 * Nginx缓冲区
 */
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;			/* 缓冲区标记地址,是一个void类型的指针。 */
    ngx_file_t      *file;			/* 引用的文件 */
    ngx_buf_t       *shadow;
 
 
    /* the buf's content could be changed */
 
    unsigned         temporary:1;	 /* 标志位,为1时,内存可修改 */
 
    /*
     * the buf's content is in a memory cache or in a read only memory
     * and must not be changed
     */
    unsigned         memory:1;   	/* 标志位,为1时,内存只读 */
 
    /* the buf's content is mmap()ed and must not be changed */
    unsigned         mmap:1;		/* 标志位,为1时,mmap映射过来的内存,不可修改 */
 
    unsigned         recycled:1;	/* 标志位,为1时,可回收 */
    unsigned         in_file:1;		/* 标志位,为1时,表示处理的是文件 */
    unsigned         flush:1;		/* 标志位,为1时,表示需要进行flush操作 */
    unsigned         sync:1;		/* 标志位,为1时,表示可以进行同步操作,容易引起堵塞 */
    unsigned         last_buf:1;	/* 标志位,为1时,表示为缓冲区链表ngx_chain_t上的最后一块待处理缓冲区 */
    unsigned         last_in_chain:1;/* 标志位,为1时,表示为缓冲区链表ngx_chain_t上的最后一块缓冲区 */
 
    unsigned         last_shadow:1;	/* 标志位,为1时,表示是否是最后一个影子缓冲区 */
    unsigned         temp_file:1;	/* 标志位,为1时,表示当前缓冲区是否属于临时文件 */
 
    /* STUB */ int   num;
};

缓冲区链表结构 ngx_chain_t

点击查看代码
typedef struct ngx_chain_s       ngx_chain_t;
/**
 * 缓冲区链表结构,放在pool内存池上面
 */
struct ngx_chain_s {
    ngx_buf_t    *buf;
    ngx_chain_t  *next;
};

双向链表

Nginx的链表结构非常小巧和简单。设计的非常精巧。

通过链表的简单和精巧的设计,让Nginx的链表的数据结构和具体业务依赖进行了解耦。

链表数据结构 ngx_queue_t

点击查看代码
typedef struct ngx_queue_s ngx_queue_t;
 
/**
 * 链表的数据结构非常简单,ngx_queue_s会挂载到实体
 * 结构上。然后通过ngx_queue_s来做成链表
 */
struct ngx_queue_s {
	ngx_queue_t *prev;
	ngx_queue_t *next;
};

使用举例

点击查看代码
/**
 * 该结构体用于描述一个网络连接
 */
struct ngx_connection_s {
	void *data; //连接未使用时,data用于充当连接池中空闲链表中的next指针。连接使用时由模块而定,HTTP中,data指向ngx_http_request_t
	ngx_event_t *read; //连接对应的读事件
	ngx_event_t *write; //连接对应的写事件
 
	ngx_socket_t fd; //套接字句柄
 
	ngx_recv_pt recv; //直接接受网络字节流
	ngx_send_pt send; //直接发送网络字节流
	ngx_recv_chain_pt recv_chain; //网络字节流接收链表
	ngx_send_chain_pt send_chain; //网络字节流发送链表
 
	/*用来将当前连接以双向链表元素的形式添加到ngx_cycle_t核心结构体
	 * 的reuseable_connection_queue双向链表中,表示可以重用的连接*/
	ngx_queue_t queue;
 
	/* 省去部分 */
};

单向链表

Nginx的list单向链表的结构和Nginx的数组结构Array有点类似,总体来说,数据结构也是非常简单清晰的。

Nginx的单向链表也是固定了每个元素的大小,并且用单向链表的方式连接。

gx_list_part_t 链表节点定义

点击查看代码
typedef struct ngx_list_part_s  ngx_list_part_t;
 
/**
 * 链表节点  每个节点大小 = size * nelts
 * 节点元素用完后,每次就会分配一个新的节点
 */
struct ngx_list_part_s {
    void             *elts;  	/* 节点的内存起始位置 */
    ngx_uint_t        nelts; 	/* 已经使用的元素*/
    ngx_list_part_t  *next;  	/* 指向下一个链表节点*/
};

ngx_list_t 链表结构

点击查看代码
/**
 * 链表结构
 */
typedef struct {
    ngx_list_part_t  *last;		/* 指向最新的链表节点*/
    ngx_list_part_t   part;		/* 第一个链表节点*/
    size_t            size;		/* 这个链表默认的每个元素大小 */
    ngx_uint_t        nalloc;	        /* 每个节点part 可以支持多少个元素*/
    ngx_pool_t       *pool;		/* 线程池*/
} ngx_list_t;

Hash表结构

Nginx的hash模块包含了对内存利用最大化、CPU利用最大化的很多设计细节,非常值得推荐和学习。

Nginx的hash表结构主要几个特点:

  • 静态只读。当初始化生成hash表结构后,是不能动态修改这个hash表结构的内容。
  • 将内存利用最大化。Nginx的hash表,将内存利用率发挥到了极致,并且很多设计上面都是可以供我们学习和参考的。
  • 查询速度快。Nginx的hash表做了内存对齐等优化。
  • 主要解析配置数据。

数据结构定义

点击查看代码
ngx_hash_elt_t hash表的元素结构
/**
 * 存储hash的元素
 */
typedef struct {
    void             *value; 	/* 指向value的指针 */
    u_short           len;   	/* key的长度 */
    u_char            name[1]; 	/* 指向key的第一个地址,key长度为变长(设计上的亮点)*/
} ngx_hash_elt_t;

ngx_hash_t hash表结构

点击查看代码
/**
 * Hash的桶
 */
typedef struct {
    ngx_hash_elt_t  **buckets; 	/* hash表的桶指针地址值 */
    ngx_uint_t        size; 	/* hash表的桶的个数*/
} ngx_hash_t;

ngx_hash_init_t hash表初始化结构

点击查看代码
/**
 * hash表主体结构
 */
typedef struct {
    ngx_hash_t       *hash;	/* 指向hash数组结构 */
    ngx_hash_key_pt   key;  /* 计算key散列的方法 */
 
    ngx_uint_t        max_size; 	/* 最大多少个 */
    ngx_uint_t        bucket_size; 	/* 桶的存储空间大小 */
 
    char             *name; /* hash表名称 */
    ngx_pool_t       *pool; /* 内存池 */
    ngx_pool_t       *temp_pool; /* 临时内存池*/
} ngx_hash_init_t;

字符串结构

ngx_str_t 字符串结构

点击查看代码
/**
 * 字符串结构
 */
typedef struct {
    size_t      len; //字符串长度
    u_char     *data; //具体的指针地址
} ngx_str_t;

ngx_keyval_t 字符串K V结构

点击查看代码
/**
 * 字符串的K V结构
 */
typedef struct {
    ngx_str_t   key;
    ngx_str_t   value;
} ngx_keyval_t;

主流程解析

Event事件

HTTP模块

posted @ 2022-08-07 22:37  Ricardo_ML  阅读(73)  评论(0编辑  收藏  举报