Time management in nginx and nginx Time Management

Source: Internet
Author: User

Time management in nginx and nginx Time Management
Nginx uses the lib_event-like method for performance consideration and caches the time to reduce the call to gettimeofday (), because the server generally does not have a particularly high requirement on time accuracy, however, if you need a more accurate timer, nginx also provides a timer_resolution command to set the time precision. The specific mechanism will be introduced later. In ngx_times.c, The ngx_time_update () function is provided to update the time cache. In addition, the ngx_time_sigsafe_update () function used to update cached_err_log_time in signal processing is provided, and time is obtained from the time cache elsewhere.

Since nginx adopts the master-workers multi-process method, each process maintains its own time cache. When will the time cache be updated in nginx? As mentioned above, nginx adopts two methods to maintain the time. First, we will introduce the situation where the time precision is not set using the timer_resolution command, that is, if ngx_timer_resolution is 0, you only need to find ngx_time_update () and ngx_time_sigsafe_update () are called. First, let's take a look at ngx_time_sigsafe_update (). It just updates ngx_cached_err_log_time, which is called every time the signal processing function is executed, that is, in the ngx_signal_handler () function. The ngx_time_update () function is called in the main loop of ngx_master_process_cycle () in the master process. After the location is the sigsuspend () function, that is to say, the master process will update the time cache when it captures and processes a signal returned. In the worker process, the call chain of the ngx_time_update function is ngx_worker_process_cycle ()-> ngx_process_events_and_timers () -> ngx_process_events ()-> ngx_time_update (), where ngx_process_events () is actually a macro, which is defined as follows in nginx:

# Define ngx_process_events ngx_event_actions.process_events

Ngx_event_actions is the structure of the nginx I/O model interface function, which encapsulates the interfaces provided, such as epoll, kqueue, select, and poll. Here, only epoll is analyzed. Others are similar, therefore, ngx_event_actions.process_events corresponds to the ngx_epoll_process_events () function in the ngx_epoll_events .c file. After epoll_wait () is returned, ngx_time_update () is called to update the time cache, that is, when an epoll notification event arrives or the epoll times out, it will update the time. The cache_manager process also calls ngx_time_update () to maintain its own time cache, which is not described here.

In the second method, ngx_timer_resolution is set to be greater than 0. That is to say, the nginx time cache is precise to ngx_timer_resolution in milliseconds. The specific implementation method is to initialize the function ngx_event_process_init () in the event module () the setitimer () function is called. It generates a SIGALRM signal every several milliseconds after ngx_timer_resolution. The signal processing function is ngx_timer_signal_handler (), which is defined as follows:

 

Ngx_timer_signal_handler (int signo)
{
Ngx_event_timer_alarm = 1;

# If 1
Ngx_log_debug0 (NGX_LOG_DEBUG_EVENT, ngx_cycle-> log, 0, "timer signal ");
# Endif
}

It is very simple. It only sets ngx_event_timer_alarm to 1 to record the occurrence of SIGALRM signals. Now we can see that the ngx_epoll_process_events () function and the timeout of epoll_wait () is set to-1, if epoll_wait () is awakened by the SIGALRM signal, ngx_time_update () is called to update the time cache. Otherwise, the previous time cache will continue to be used because setitimer () always generates a SIGALRM signal every several milliseconds, this ensures that the precision of the time cache is ngx_timer_resolution in milliseconds. This section only describes the situation of worker processes. Other processes are similar.

 

The implementation of the ngx_time_update () and ngx_time_sigsafe_update () functions is relatively simple, but there are still a few notes. First, because the time may be updated in signal processing, in addition, the time may be updated simultaneously when multiple threads are used. nginx uses the atomic variable ngx_time_lock to write and lock the time variable, in addition, nginx does not lock the read due to performance reasons because of many read time operations. Instead, it uses the maintenance of multiple time slots to minimize read access conflicts. The basic principle is, when read and write operations occur at the same time (1. multithreading may occur; 2. When a process is in the read time cache, It is interrupted by a signal to execute a signal processing function, the time cache will be updated in the signal processing function), that is, when the read operation is in progress (for example, if you have just copied ngx_cached_time-> sec, or copied ngx_cached_http_time.data for half ), if the write operation changes the read operation Time, the final time of the read operation becomes chaotic. Nginx uses 64 slot times, that is, the next slot is updated each time it is updated. If the read operation is performed at the same time, the previous slot is read and has not been changed, of course, this can only minimize the chance of time confusion, because the number of slots is not infinite, slots are cyclical, and there is always a probability that write operations will be written to the slot of the read operation. However, nginx does not actually adopt multithreading, and only updates cached_err_log_time in signal processing. Therefore, read access to other time variables will not be chaotic. The other is that both functions call ngx_memory_barrier (). In fact, this is also a macro. Its definition is related to the compiler and architecture. in gcc and x86 environments, the definition is as follows:

# Define ngx_memory_barrier () _ asm _ volatile ("": "memory ")

Its role is actually related to preventing read operation confusion. It tells the compiler not to optimize the statements behind it, not to disrupt the execution sequence. Let's take a look at the ngx_time_update function:

Ngx_time_update ()

{

...

 

If (! Ngx_trylock (& ngx_time_lock )){
Return;
}

...

Tp = & cached_time [slot];

Tp-> sec = sec;
Tp-> msec = msec;

Ngx_gmtime (sec, & gmt );


P0 = & cached_http_time [slot] [0];

(Void) ngx_sprintf (p0, "% s, % 02d % s % 4d % 02d: % 02d: % 02d GMT ",
Week [gmt. ngx_tm_wday], gmt. ngx_tm_mday,
Months [gmt. ngx_tm_mon-1], gmt. ngx_tm_year,
Gmt. ngx_tm_hour, gmt. ngx_tm_min, gmt. ngx_tm_sec );

# If (NGX_HAVE_GETTIMEZONE)

Tp-> gmtoff = ngx_gettimezone ();
Ngx_gmtime (sec + tp-> gmtoff * 60, & tm );

# Elif (NGX_HAVE_GMTOFF)

Ngx_localtime (sec, & tm );
Cached_gmtoff = (ngx_int_t) (tm. ngx_tm_gmtoff/60 );
Tp-> gmtoff = cached_gmtoff;

# Else

Ngx_localtime (sec, & tm );
Cached_gmtoff = ngx_timezone (tm. ngx_tm_isdst );
Tp-> gmtoff = cached_gmtoff;

# Endif


P1 = & cached_err_log_time [slot] [0];

(Void) ngx_sprintf (p1, "% 4d/% 02d/% 02d % 02d: % 02d: % 02d ",
Tm. ngx_tm_year, tm. ngx_tm_mon,
Tm. ngx_tm_mday, tm. ngx_tm_hour,
Tm. ngx_tm_min, tm. ngx_tm_sec );


P2 = & cached_http_log_time [slot] [0];

(Void) ngx_sprintf (p2, "% 02d/% s/% d: % 02d: % 02d: % 02d % c % 02d % 02d ",
Tm. ngx_tm_mday, months [tm. ngx_tm_mon-1],
Tm. ngx_tm_year, tm. ngx_tm_hour,
Tm. ngx_tm_min, tm. ngx_tm_sec,
Tp-> gmtoff <0? '-': '+ ',
Ngx_abs (tp-> gmtoff/60), ngx_abs (tp-> gmtoff % 60 ));


Ngx_memory_barrier ();

Ngx_cached_time = tp;
Ngx_cached_http_time.data = p0;
Ngx_cached_err_log_time.data = p1;
Ngx_cached_http_log_time.data = p2;

Ngx_unlock (& ngx_time_lock );

}

You can see that ngx_memory_barrier () is followed by four value assignment statements. If ngx_memory_barrier () is not available, the compiler may convert ngx_cached_time = tp, ngx_cached_http_time.data = p0, bytes = p1, ngx_cached_http_log_time.data = p2 and the previous tp = & cached_time [slot], p0 = & cached_http_time [slot] [0], p1 = & cached_err_log_time [slot] [0], p2 = & cached_http_log_time [slot] [0] merged and optimized, the consequence is ngx_cached_time, ngx_cached_http_time, ngx_cached_err_log_time, ngx_c Ached_http_log_time the inconsistency duration of the four time caches increases, because the four time caches are consistent after the last ngx_sprintf is executed, before that, if other locations are reading the time cache, the read time may be incorrect or inconsistent. After ngx_memory_barrier () is used, only a few clock cycles are required to update the time cache to a consistent state. Because there are only four value assignment commands, the probability of a read time cache in such a short period of time is much lower. It can be seen from this that the Igor consideration is very meticulous.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.