nginx lua 모듈 에 sendfile 함 수 를 추가 하면 X - Accel - Redirect 를 대체 할 수 있 습 니 다.

7925 단어
nginx 에서 정적 파일 을 보 내 는 속도 가 매우 빠 릅 니 다. Nginx 의 x - sendfile 체 제 는 X - Accel - Redirect 특성 에 의 해 이 루어 져 야 합 니 다. 그러나 제 테스트 를 통 해 제 수 요 를 만족 시 키 지 못 합 니 다. 저 는 lua 로 업무 논 리 를 처리 한 다음 에 파일 내용 을 보 내 려 고 합 니 다. 처음에 다음 과 같은 방식 으로 이 루어 졌 습 니 다. 이런 방식 은 파일 이 작 으 면 상 관 없 지만 파일 이 많 을 때.성능 에 미 치 는 영향 이 매우 크다.
local file = io.open(filePath, "rb")


local size = file:seek("end")
ngx.header["Content-Length"] = size
file:seek("set", 0) 
data = file:read("*a")

ngx.print(data)
ngx.flush(true)

file:close()

알다 시 피 Liux 커 널 에 sendfile 함수 가 있어 서 0 복사 해서 파일 을 보 낼 수 있 습 니 다. 그래서 인터넷 에서 자 료 를 찾 았 습 니 다. 똑 같은 글 을 찾 았 습 니 다. 모두 Nginx 의 X - Accel - Redirect 를 어떻게 사용 하 는 지 소개 하 는 것 입 니 다. 테스트 를 통 해 X - Accel - Redirect 는 제 수 요 를 만족 시 킬 수 없습니다.
X - Accel - Redirect 의 공식 글 주 소 를 소개 합 니 다.http://wiki.nginx.org/XSendfile
결국 어 쩔 수 없 이 소스 코드 부터 시작 할 수 밖 에 없 었 다.
ngx 참조http_static_module.c  정적 파일 을 보 내 는 모듈 원본 코드 는 lua 의 인 터 페 이 스 를 실현 하기 로 결 정 했 습 니 다. lua 가 sendfile 함 수 를 직접 호출 하여 파일 내용 을 보 낼 수 있 습 니 다.
print 함수 ngxhttp_lua_log. c 에서 이 루어 집 니 다. 저도 sendfile 함 수 를 여기에 두 겠 습 니 다. 직접 ngxlua 의 프레임.
void
ngx_http_lua_inject_log_api(lua_State *L)
{
    ngx_http_lua_inject_log_consts(L);

    lua_pushcfunction(L, ngx_http_lua_ngx_log);
    lua_setfield(L, -2, "log");

    lua_pushcfunction(L, ngx_http_lua_print);
    lua_setglobal(L, "print");

    lua_pushcfunction(L, ngx_http_lua_sendfile); //     
    lua_setglobal(L, "sendfile");//     
}

위의 코드 에 luapushcfunction 은 함수 의 지침 을 스 택 에 누 르 는 것 입 니 다. luasetglobal 은 "sendfile" 을 스 택 에 누 르 고 전역 함수 로 설정 합 니 다. 전역 함수 라면 lua 에서 호출 하면 직접 sendfile () 입 니 다.  lua 로setfield 가 스 택 에 눌 러 넣 으 면 lua 에서 사용 해 야 합 니 다.  ngx. sendfile () 같은 형식 으로 호출 되 었 습 니 다.  어차피 두 가지 다 괜찮아, 마음대로 해.
아래 에 ngx 붙 이기http_lua_sendfile 함수 의 실현:
static int ngx_http_lua_sendfile(lua_State *L)
{
    u_char                    *last, *location;
    size_t                     root, len;
    ngx_http_request_t        *r;
    ngx_str_t                  path;
    ngx_int_t                  rc;
    ngx_uint_t                 level;
    ngx_log_t                 *log;
    ngx_buf_t                 *b;
    ngx_chain_t                out;
    ngx_open_file_info_t       of;
    ngx_http_core_loc_conf_t  *clcf;
	int                        offset;
	int                        bytes;
	char                      *filename;
	int                        nargs;

    lua_pushlightuserdata(L, &ngx_http_lua_request_key);
    lua_rawget(L, LUA_GLOBALSINDEX);
    r = lua_touserdata(L, -1);
    lua_pop(L, 1);

    if (r == NULL) 
    {
        luaL_error(L, "no request object found");
	return 1;
    }

 
    nargs = lua_gettop(L);

	filename = (char *) lua_tolstring(L, 1, &len);
	offset   = lua_tonumber(L, 2);
	bytes    = lua_tonumber(L, 3);

    log = r->connection->log;

    path.len = ngx_strlen(filename);

    path.data = ngx_pnalloc(r->pool, path.len + 1);
    if (path.data == NULL) {
        return 0;
    }

    (void) ngx_cpystrn(path.data, (u_char *) filename, path.len + 1);

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "ngx send lua filename: \"%s\"", filename);

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

    ngx_memzero(&of, sizeof(ngx_open_file_info_t));

    of.read_ahead = clcf->read_ahead;
    of.directio = clcf->directio;
    of.valid = clcf->open_file_cache_valid;
    of.min_uses = clcf->open_file_cache_min_uses;
    of.errors = clcf->open_file_cache_errors;
    of.events = clcf->open_file_cache_events;

    if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) 
    {
        return 0;//NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK)
    {
        switch (of.err) 
	{

        case 0:
            return 0;//NGX_HTTP_INTERNAL_SERVER_ERROR;

        case NGX_ENOENT:
        case NGX_ENOTDIR:
        case NGX_ENAMETOOLONG:

            level = NGX_LOG_ERR;
            rc = NGX_HTTP_NOT_FOUND;
            break;

        case NGX_EACCES:
#if (NGX_HAVE_OPENAT)
        case NGX_EMLINK:
        case NGX_ELOOP:
#endif
            level = NGX_LOG_ERR;
            rc = NGX_HTTP_FORBIDDEN;
            break;

        default:

            level = NGX_LOG_CRIT;
            rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
            break;
        }

        if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) 
	{
            ngx_log_error(level, log, of.err, "%s \"%s\" failed", of.failed, path.data);
        }

        return 0;//rc;
    }

    r->root_tested = !r->error_page;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd);

    if (offset < 0) {
        offset = 0;
    }

    if (bytes <= 0) {
        bytes = of.size - offset;
    }


#if !(NGX_WIN32) /* the not regular files are probably Unix specific */

    if (!of.is_file) 
    {
        ngx_log_error(NGX_LOG_CRIT, log, 0, "\"%s\" is not a regular file", path.data);

        return 0;//NGX_HTTP_NOT_FOUND;
    }

#endif

    if (r->method & NGX_HTTP_POST) 
    {
        return 0;//NGX_HTTP_NOT_ALLOWED;
    }

    rc = ngx_http_discard_request_body(r);

    if (rc != NGX_OK) 
    {
        return 0;//rc;
    }

    log->action = "sending response to client";

    len = (offset + bytes) >= of.size ? of.size : (offset + bytes);

    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = len - offset;
    r->headers_out.last_modified_time = of.mtime;

    if (ngx_http_set_content_type(r) != NGX_OK) 
    {
        return 0;//NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    if (r != r->main && of.size == 0) 
    {
         ngx_http_send_header(r);
		 return 0;//
    }

    r->allow_ranges = 1;

    /* we need to allocate all before the header would be sent */

    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
    if (b == NULL) 
    {
        return 0;//NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
    if (b->file == NULL) 
    {
        return 0;//NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    rc = ngx_http_send_header(r);

    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) 
    {
        return 0;//rc;
    }

    b->file_pos = offset;
    b->file_last = (offset + bytes) >= of.size ? of.size : (offset + bytes);

    b->in_file = 1;
    b->last_buf = (r == r->main) ? 1: 0;
    b->last_in_chain = 1;

    b->file->fd = of.fd;
    b->file->name = path;
    b->file->log = log;
    b->file->directio = of.is_directio;

    out.buf = b;
    out.next = NULL;

    ngx_http_output_filter(r, &out);
    return 0;//
}



sendfile 함수 의 인 자 는 모두 세 개 입 니 다. 첫 번 째 인 자 는 파일 이름 filename 입 니 다.두 번 째 매개 변 수 는 파일 편 이 량 offset 이 고 offset < 0 은 파일 헤더 부터 발송 합 니 다.세 번 째 매개 변 수 는 bytes 입 니 다. 보 낼 바이트 수 입 니 다. bytes < 0 이면 파일 끝 에 보 내 는 것 을 의미 합 니 다.
이렇게 lua 스 크 립 트 에서 이렇게 호출 할 수 있 습 니 다.
sendfile ("/ opt / f1. ts", - 1, - 1) 전체 파일 보 내기
혹은
sendfile("/opt/f1.ts", 104857600,104857600)  100 MB 부터 시작 하 는 곳 에서 100 MB 의 데 이 터 를 보 냅 니 다.
테스트 를 통 해 정적 파일 을 직접 nginx 로 보 내 는 속도 와 일치 합 니 다.
이 기능 을 추가 할 때 작은 문제 에 부 딪 혀 기록 했다.
ngx_lua 의 C 함수 반환 값 은 스 택 에 누 른 반환 값 의 개 수 를 의미 합 니 다. 제 위의 코드 를 보면 기본적으로 0 으로 돌아 갑 니 다. 이것 은 제 가 lua 의 스 택 에 어떠한 인자 도 누 르 지 않 았 고 아래 의 코드 를 의미 합 니 다.
4. 567913. 매개 변 수 를 누 른 것 을 의미 하기 때문에 반환 값 은 1 이 고 그렇지 않 으 면 세그먼트 오류 가 발생 할 수 있 습 니 다.
또한 lua 와 C 가 데 이 터 를 교환 하 는 스 택 원 리 를 알 아야 하 므 로 아래 의 글 을 참고 할 수 있 습 니 다.
http://blog.csdn.net/yhhwatl/article/details/9303675
이 글 은 창 고 를 매우 명확 하 게 소개 했다.
감사합니다. 안녕 히 주 무 세 요.

좋은 웹페이지 즐겨찾기