1. 一些和文件操作相关的函数
(1)ngx_file_info
宏定义: #define ngx_file_info(file, sb) stat((const car*)file, sb)
stat函数 :具体用法见 http://wenku.baidu.com/view/31777dc1d5bbfd0a795673b1.html
(2)ngx_open_file(name,mode,create,access)
宏定义 : #define ngx_open_file(name,mode,create,access) open((const char*) name, mode|create, access);
open函数: http://baike.baidu.com/view/26337.htm
2. nginx如何读取缓存文件
之前紧紧大致弄明白了upstream的工作流程,可一谈到细节,依然是一头雾水。
例如,nginx如何读取缓存文件?今天继续看源代码,希望能够找到答案。
(1)打开缓存文件
在ngx_http_file_cache.c中
ngx_http_file_cache_open() {
……//打开或是创建内存结点
if (ngx_open_cached_file(clcf->open_file_cache,&c->file.name,&of,r->pool) != NGX_OK) {
}
c->file.fd = of.fd;//保存缓存文件的文件句柄
c->uniq = of.uniq;//保存缓存文件的inode节点号
c->length = of.size;//保存缓存文件的大小(字节)
c->buf = ngx_create_temp_buf(r->pool,c->body_start)//这个buf中不知存储着什么????
}
这个ngx_open_cached_file似乎和打开缓存文件有关,于是深入地查看一下。
ngx_open_cached_file(ngx_open_file_cache_t *cache, ngx_str_t *name, ngx_open_file_info_t *of, ngx_pool_t *pool) {
if (cache == NULL) {
if (of->test_only) {}//不会执行这个if语句
rc = ngx_open_and_stat_file(name->data, of, pool->log);
if (rc == NGX_OK && !of->is_dir) {
clnf->fd = of ->fd;//保存打开文件的句柄
clnf->name = name->data;//保存文件路径
}
}
}
再看ngx_open_and_stat_file() {
……
fd = ngx_open_file(name,….)//打开缓存文件
……
of->fd = fd;//将文件句柄保存于of
}
(2) 利用缓存文件响应客户端
ngx_http_upstream_cache() {
……
case NGX_OK:
rc = ngx_http_upstream_cache_send(r,u);
}
ngx_http_upstream_cache_send() {
……
ngx_http_cache_send();
}
ngx_http_cache_send() {
ngx_buf_t *b;
ngx_chain_t out;
c = r->cache;
b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
if (b == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
b->file = ngx_pcalloc(r->pool,sizeof(ngx_file_t));
if (b->file == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
b->file_pos = c->body_start;
b->file_last = c->length;
b->in_file = 1;
b->last_buf = (r==r->main)?1:0;
b->last_in_chain;
b->file->fd = c->file.fd;
b->file->name = c->file.name;
b->file->log = r->connection->log;
out.buf = b;
out.next = NULL;
return ngx_http_output_filter(r,&out);
}
(3) 自己使用缓存文件响应客户
a.缓存文件的结构:
缓存文件的第一部分存储着关于ngx_http_file_cache_header_t这个结构的数据。
typedef struct {
time_t valid_sec;
time_t last_modified;
time_t date;
uint32_t crc32;
u_short valid_msec;
u_short header_start;//缓存文件中,存放HTTP头的起始位置
u_short body_start;//存放HTTP body的起始位置
缓存文件的第二部分是KEY,例如KEY:http://主机IP/相对路径/文件名 , 如果客户端拥有
相同的KEY,那么客户端使用同一个缓存。
第三部分是源服务器的响应头,这部分内容可存储到结构
第四部分是源服务器的响应体。
b. 缓存文件的文件名: r->cache->file.name.data,可以通过此文件名打开缓存。
c. 打开文件,获得文件句柄
ngx_fd_t fd;
fd = ngx_open_file(r->cache->file.name.data, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK,NGX_FILE_OPEN, 0);
if (fd == NGX_INVALID_FILE) {
//打开失败
}
d. 获取文件信息
ngx_file_info_t fi;
if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
//获取信息失败
ngx_close_file(fd);
}
e. 获取文件信息后提取有效信息
int length;
if (ngx_is_dir(&fi)) {
ngx_close_file(fd);//如果打开的是文件夹
} else {
length = ngx_file_size(&fi);//打开文件的字节数
}
f. 申请空间,以读取缓存文件
u_char *buf = ngx_palloc(pool, u->conf->buffer_size);
ssize_t n;
#if (NGX_HAVE_PREAD)
n = pread(fd, buf, u->conf->buffer_size,0);
#else
n = read(fd,buf,u->conf->buffer_size);
#endif
if (n == -1) {
ngx_close_file(fd);//读取出错
}
g. 分析缓存文件的第一部分
ngx_http_file_cache_header_t *h;
h = (ngx_http_file_cache_header_t *) buf;
size_t body_start = h->body_start;
size_t header_start = h->header_start;
h. 读取缓存的body
u_char *sbuf = ngx_palloc(pool, length – body_start);
n = pread(fd, cbuf, length-body_start, body_start);
i. 使用ngx_http_send_header()和ngx_http_output_filter()发送HTTP数据。
你好. 我想咨询下这个读取缓存的实现.
目前通过nginx自带的配置缓存,有一个问题.如果源有1个新文件, 前端的业务机有多少用户请求,那么业务机就会向后端请求多少次.导致后端压力很大.
我看了下你这篇文章. 应该是可以实现第一个用户请求,其他用户会使用缓存中的文件.
不过应该要如何实现呢.
nginx的几篇笔记是四五年前写的, 很久没研究了。 你提到的关于nginx缓存的问题是确实存在的。 因为当时源服务器的资源是视频分片文件, 可以轮询下载, 所以我的方案是第一个新资源的请求受理, 其余请求直接拒绝。 nginx的缓存更新完毕后, 才受理后续的请求。 这种方案比较粗放, 应该不适合你。
按这么说. 第一个接受请求其他拒绝.这样太粗放太暴力了.或者有不有什么类似的缓存软件推荐呢. 因为是跑下载的.用户压力也是很大,也想新机器快速上线
现在不研究服务器了, 不大清楚, 抱歉。 。nginx的缓存的行为也算是一种最优解, 只是在分片视频播放中有劣势, 因为分片文件比较大。