这次主要来看mochiweb如何处理http协议以及如何将外部模块加载到mochiweb框架中。
首先在上一篇的分析最后,我们知道当accept句柄之后,mochiweb最终会调用call_loop方法,那么我们就从call_loop开始
call_loop({M, F}, Socket) ->
M:F(Socket);
call_loop({M, F, [A1]}, Socket) ->
M:F(Socket, A1);
call_loop({M, F, A}, Socket) ->
erlang:apply(M, F, [Socket | A]);
call_loop(Loop, Socket) ->
Loop(Socket).
阅读全文…
Nginx的cache实现比较简单,没有使用内存,全部都是使用文件来对后端的response进行cache,因此nginx相比varnish以及squid之类的专门做cache的server,可能效果不会那么好。特别如果cache内容比较大的话。不过还有一种折衷的处理,那就是挂载一个内存盘,然后让nginx cache到这个盘。
我这里的看的代码是1.1.17.
首先来看Nginx中如何开启cache,http cache主要是应用在upstream中的,因此upstream对应的两个命令来启用cache,一个是xxx_cache_path(比如proxy_cache_path),它主要是用来创建管理cache的共享内存数据结构(红黑树和队列).一个是xxx_cache,它主要是使用前面创建的zone。
先来看第一个命令,xxx_cache_path,它会调用ngx_http_file_cache_set_slot函数,在看这个函数之前,先来看ngx_http_file_cache_t这个数据结构,它主要用来管理所有的cache文件,它本身不保存cache,只是保存管理cache的数据结构。每一个xxx_cache_path都会创建一个ngx_http_file_cache_t.
阅读全文…
这次主要来分析upstream中的发送数据给client, 以及当buf不足,将一部分写到temp file的部分,他们对应的函数分别是ngx_event_pipe_write_to_downstream和ngx_event_pipe_write_chain_to_temp_file.
先来看ngx_event_pipe_write_to_downstream,这个函数顾名思义,就是写buf到临时文件。而所写的buf就是p->in,也就是将要发送给client的数据。
这个函数,它会处理两类的情况,一类是cache打开,一类是cache未打开。我们这里主要来分析cache关闭的情况。
首先来看这个函数的第一部分的代码,这部分代码主要是遍历p->in,然后计算能写多少buf到文件(temp file的size是有限制的).
//out就是将要保存到file的数据
if (p->buf_to_file) {
//cache打开的情况
fl.buf = p->buf_to_file;
fl.next = p->in;
out = &fl;
} else {
//得到数据
out = p->in;
}
//如果cache没有打开
if (!p->cacheable) {
size = 0;
cl = out;
ll = NULL;
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0,
"pipe offset: %O", p->temp_file->offset);
//开始遍历out
do {
//计算大小
bsize = cl->buf->last - cl->buf->pos;
.....................................................
//看是否超过限制限制
if ((size + bsize > p->temp_file_write_size)
|| (p->temp_file->offset + size + bsize > p->max_temp_file_size))
{
break;
}
size += bsize;
ll = &cl->next;
cl = cl->next;
} while (cl);
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "size: %z", size);
if (ll == NULL) {
return NGX_BUSY;
}
//cl存在则说明只有一部分buf能够写入到temp file,此时p->in保存剩下的chain
if (cl) {
p->in = cl;
*ll = NULL;
} else {
//否则说明所有的buf都写入到了temp file,此时p->in则设置为空
p->in = NULL;
p->last_in = &p->in;
}
} else {
//cache打开的情况,可以看到和上面类似.
p->in = NULL;
p->last_in = &p->in;
}
阅读全文…
这次主要来看upstream的几个相关的hook函数。
首先要知道,对于upstream,同时有两个连接,一个时client和nginx,一个是nginx和upstream,这个时候就会有两个回调,然后上篇blog中,我们能看到在upstream中,会改变read_event_handler和write_event_handler,不过这里有三个条件,分别是
1 没有使用cache,
2 不忽略client的提前终止
3 不是post_action
//条件赋值
if (!u->store && !r->post_action && !u->conf->ignore_client_abort) {
//然后给读写handler赋值
r->read_event_handler = ngx_http_upstream_rd_check_broken_connection;
r->write_event_handler = ngx_http_upstream_wr_check_broken_connection;
}
阅读全文…
先看这篇文章:http://wiki.nginx.org/IfIsEvil,这篇文章只是简单的介绍了if使用中一些很恶心的地方,接下来我会通过代码来看if为什么是 evil的。
if是rewrite模块里面的一个命令,因此if部分的执行也是在rewrite的phase执行的,下面就来简要的描述下rewrite模块是如何运行的。
这里有一个很关键的函数就是ngx_http_script_code_p,它的原型如下:
typedef void (*ngx_http_script_code_pt) (ngx_http_script_engine_t *e);
在rewrite模块中,所有将要在rewrite phase执行的代码的函数都会是一个ngx_http_script_code_pt类型的函数(比如rewrtie的正则匹配,比如if指令等等,而当进入rewrite handler的时候,将会依次执行这些函数,这些函数都是保存在ngx_http_script_engine_t中,下面我们来看这个结构。
typedef struct {
//这个指针指向了所有的需要执行的函数(ngx_http_script_code_pt)数组的首地址.
u_char *ip;
u_char *pos;
ngx_http_variable_value_t *sp;
...............................................................
//表示执行完对应的函数之后的返回值.
ngx_int_t status;
ngx_http_request_t *request;
} ngx_http_script_engine_t;
阅读全文…
接上篇,这篇主要来看nginx的网络部分的初始化
首先是ngx_http_optimize_servers函数,这个函数是在ngx_http_block中被调用的,它的主要功能就是创建listening结构,然后初始化。这里ngx_listening_t表示一个正在监听的句柄以及它的上下文。
static ngx_int_t
ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
ngx_array_t *ports)
{
ngx_uint_t p, a;
ngx_http_conf_port_t *port;
ngx_http_conf_addr_t *addr;
if (ports == NULL) {
return NGX_OK;
}
port = ports->elts;
for (p = 0; p < ports->nelts; p++) {
..................................................
//初始化listen结构
if (ngx_http_init_listening(cf, &port[p]) != NGX_OK) {
return NGX_ERROR;
}
}
return NGX_OK;
}
阅读全文…
近期评论