Nginx 타이머 이벤트

개술
        Nginx 에서 타이머 이벤트 의 실현 은 커 널 과 무관 합 니 다.이벤트 모듈 에 서 는 기다 리 는 이벤트 가 지 정 된 시간 내 에 도착 하지 못 하면 Nginx 의 시간 초과 체 제 를 촉발 하고 시간 초과 체 제 는 시간 초과 사건 을 관리 하 며 시간 초과 사건 을 처리 합 니 다.정시 사건 에 대한 관 리 는 두 가지 측면 을 포함한다. 정시 사건 대상 의 조직 형식 과 정시 사건 대상 의 시간 초과 검 측 이다.
정시 이벤트 조직
        Nginx 의 타이머 가 빨 간 검 은 나무 로 이 루어 졌 습 니 다.이벤트 의 구조 체 ngx 저장 중event_t 중 세 명의 시간 관리 에 관 한 구성원 이 있 는데 다음 과 같다.
struct ngx_event_s{
    ...
    /*    , 1          */  
    unsigned         timedout:1;  
    /*    , 1                     */  
    unsigned         timer_set:1;  
    /*            */  
    ngx_rbtree_node_t   timer; 
    ...
};

        Nginx 는 타이머 에 대한 전역 변 수 를 두 개 설정 합 니 다.파일 src / event / ngxevent_timer. c 에서 정의:
/*               */
ngx_thread_volatile ngx_rbtree_t  ngx_event_timer_rbtree;
/*          */
static ngx_rbtree_node_t          ngx_event_timer_sentinel;


        이 붉 은 검 은 나무의 모든 노드 는 하나의 사건 ngx 를 대표 합 니 다.event_t 구조 체 의 구성원 timer, ngxrbtree_node_t 노드 는 이벤트 의 시간 초과 시간 을 대표 합 니 다. 이 시간 초과 크기 로 구 성 된 빨 간 검 은 나무 ngxevent_timer_rbtree, 이 빨 간 검 은 나무 중 가장 왼쪽 노드 는 시간 을 초과 할 수 있 는 사건 을 대표 합 니 다.
        타이머 이벤트 초기 화 실제 호출 레 드 블랙 트 리 초기 화, 파일 src / event / ngxevent_timer. c 에서 정의:
/*          */
ngx_int_t
ngx_event_timer_init(ngx_log_t *log)
{
    /*        */
    ngx_rbtree_init(&ngx_event_timer_rbtree, &ngx_event_timer_sentinel,
                    ngx_rbtree_insert_timer_value);

    /*            */
#if (NGX_THREADS)

    if (ngx_event_timer_mutex) {
        ngx_event_timer_mutex->log = log;
        return NGX_OK;
    }

    ngx_event_timer_mutex = ngx_mutex_init(log, 0);
    if (ngx_event_timer_mutex == NULL) {
        return NGX_ERROR;
    }

#endif

    return NGX_OK;
}

정시 이벤트 의 시간 초과 검사
        어떤 사건 에 대해 시간 초과 검 사 를 해 야 할 때 이 사건 을 타이머 레 드 블랙 트 리 에 추가 하면 됩 니 다. 함수 ngxevent_add_timer, 타이머 레 드 블랙 트 리 에서 함수 ngx 를 삭제 합 니 다.event_del_timer 구현.아래 함 수 는 모두 파일 src / event / ngx 에 있 습 니 다.event_timer. h 에서 정의:
/*           */
static ngx_inline void
ngx_event_del_timer(ngx_event_t *ev)
{
    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
                   "event timer del: %d: %M",
                    ngx_event_ident(ev->data), ev->timer.key);

    ngx_mutex_lock(ngx_event_timer_mutex);

    /*                  */
    ngx_rbtree_delete(&ngx_event_timer_rbtree, &ev->timer);

    ngx_mutex_unlock(ngx_event_timer_mutex);

#if (NGX_DEBUG)
    ev->timer.left = NULL;
    ev->timer.right = NULL;
    ev->timer.parent = NULL;
#endif

    /*          */
    ev->timer_set = 0;
}

/*            */
static ngx_inline void
ngx_event_add_timer(ngx_event_t *ev, ngx_msec_t timer)
{
    ngx_msec_t      key;
    ngx_msec_int_t  diff;

    /*             */
    key = ngx_current_msec + timer;

    /*            */
    if (ev->timer_set) {

        /*
         * Use a previous timer value if difference between it and a new
         * value is less than NGX_TIMER_LAZY_DELAY milliseconds: this allows
         * to minimize the rbtree operations for fast connections.
         */

        diff = (ngx_msec_int_t) (key - ev->timer.key);

        if (ngx_abs(diff) < NGX_TIMER_LAZY_DELAY) {
            ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
                           "event timer: %d, old: %M, new: %M",
                            ngx_event_ident(ev->data), ev->timer.key, key);
            return;
        }

        ngx_del_timer(ev);
    }

    ev->timer.key = key;

    ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
                   "event timer add: %d: %M:%M",
                    ngx_event_ident(ev->data), timer, ev->timer.key);

    ngx_mutex_lock(ngx_event_timer_mutex);

    /*                */
    ngx_rbtree_insert(&ngx_event_timer_rbtree, &ev->timer);

    ngx_mutex_unlock(ngx_event_timer_mutex);

    /*       */
    ev->timer_set = 1;
}


        함수 시간 초과 여 부 를 함수 ngx 로 판단 합 니 다.event_find_timer 구현, 타이머 모든 이벤트 검사 함수 ngxevent_expire_timer 구현.아래 함 수 는 모두 파일 src / event / ngx 에 있 습 니 다.event_timer. c 에서 정의:
/*                */
ngx_msec_t
ngx_event_find_timer(void)
{
    ngx_msec_int_t      timer;
    ngx_rbtree_node_t  *node, *root, *sentinel;

    /*        */
    if (ngx_event_timer_rbtree.root == &ngx_event_timer_sentinel) {
        return NGX_TIMER_INFINITE;
    }

    ngx_mutex_lock(ngx_event_timer_mutex);

    root = ngx_event_timer_rbtree.root;
    sentinel = ngx_event_timer_rbtree.sentinel;

    /*           ,        */
    node = ngx_rbtree_min(root, sentinel);

    ngx_mutex_unlock(ngx_event_timer_mutex);

    /*                 timer, timer  0     ,   0     */
    timer = (ngx_msec_int_t) (node->key - ngx_current_msec);

    /*
     *  timer  0,      ,    ;
     *  timer   0,     ,  0,        ;
     */
    return (ngx_msec_t) (timer > 0 ? timer : 0);
}


/*            */
void
ngx_event_expire_timers(void)
{
    ngx_event_t        *ev;
    ngx_rbtree_node_t  *node, *root, *sentinel;

    sentinel = ngx_event_timer_rbtree.sentinel;

    /*      */
    for ( ;; ) {

        ngx_mutex_lock(ngx_event_timer_mutex);

        root = ngx_event_timer_rbtree.root;

        /*          ,     ,       */
        if (root == sentinel) {
            return;
        }

        /*               ,      ,                */
        node = ngx_rbtree_min(root, sentinel);

        /* node->key <= ngx_current_time */

        /*              */
        if ((ngx_msec_int_t) (node->key - ngx_current_msec) <= 0) {
            /*           */
            ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer));

            /*          */
#if (NGX_THREADS)

            if (ngx_threaded && ngx_trylock(ev->lock) == 0) {

                /*
                 * We cannot change the timer of the event that is being
                 * handled by another thread.  And we cannot easy walk
                 * the rbtree to find next expired timer so we exit the loop.
                 * However, it should be a rare case when the event that is
                 * being handled has an expired timer.
                 */

                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0,
                               "event %p is busy in expire timers", ev);
                break;
            }
#endif

            ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
                           "event timer del: %d: %M",
                           ngx_event_ident(ev->data), ev->timer.key);

            /*                      */
            ngx_rbtree_delete(&ngx_event_timer_rbtree, &ev->timer);

            ngx_mutex_unlock(ngx_event_timer_mutex);

#if (NGX_DEBUG)
            ev->timer.left = NULL;
            ev->timer.right = NULL;
            ev->timer.parent = NULL;
#endif

            /*                     */
            ev->timer_set = 0;/* 0       */

            /*       */
#if (NGX_THREADS)
            if (ngx_threaded) {
                ev->posted_timedout = 1;

                ngx_post_event(ev, &ngx_posted_events);

                ngx_unlock(ev->lock);

                continue;
            }
#endif

            /*            */
            ev->timedout = 1;/* 1       */

            /*                      */
            ev->handler(ev);

            continue;
        }

        break;
    }

    ngx_mutex_unlock(ngx_event_timer_mutex);
}

참고 자료
《 깊이 분석 Nginx 》.
& lt; Nginx 깊이 이해 & gt;

좋은 웹페이지 즐겨찾기