Nginx 타이머 이벤트
7726 단어 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;