Execution order of Nginx configuration directives (i)

Source: Internet
Author: User
Tags echo command nginx server

Most Nginx novices often encounter the confusion that when the same location configuration block uses multiple Nginx module configuration instructions, the order of execution of these instructions is likely to differ greatly from the order in which they were written. So many people choose the "Trial and Error Method", then their profiles are often changed to a messy. This series of tutorials is designed to help readers gradually understand the mysteries of the execution time and sequencing behind these configuration directives.

Now let's look at a puzzling example:

? location/test {
? Set $a 32;
? echo $a;
?
? Set $a 56;
? echo $a;
? }

From the point of view of this example, we expect the output to be a line 32 and a line 56 , since we first used the Echo configuration directive to output the $a value of the variable, and then we modified it with the Set Configuration Directive $a . Unfortunately, this is not true:

$ Curl ' Http://localhost:8080/test
56
56

As we can see, the statement appears to have been set $a 56 echo $a executed before the first statement. What is this for? Did we encounter a bug in Nginx?

Obviously, there is no nginx bug; To understand what is happening here, you need to know that nginx processes each user request in a number of different stages (phase).

Nginx request processing phase of a total of 11, we first introduce 3 of them are more common. According to the order in which they were executed, the phases, phases, and phases are followed rewrite access content (we have the opportunity to see more processing stages later).

The configuration instructions provided by all Nginx modules are generally only registered and run at one of the processing stages. For example, the set instruction in the example above is rewrite run in phase, and the echo command will only content run in stages. As we know earlier, during the processing of a single request, the rewrite stage is always content executed before the stage, so rewrite the configuration directives that belong to the stage are always executed unconditionally before the content configuration directives of the stage. So in the same location configuration block, the set instruction is always executed before the echo instruction, even though we intentionally write the SET statement behind the Echo statement in the configuration file.

Back to the example just now,

Set $a 32;
echo $a;

Set $a 56;
echo $a;

The actual order of execution should be

Set $a 32;
Set $a 56;
echo $a;
echo $a;

That is rewrite , the two set assignment statements are executed at the stage, and then the content two echo statements are executed sequentially in the later stages. The configuration instructions that belong to two different processing stages are not interspersed with each other.

To further verify this, we may wish to use Nginx's "debug log" to get a glimpse of Nginx's actual execution process.

Because this is the first time we have mentioned the "debug log" of Nginx, it is necessary to briefly introduce its activation method. The debug log is disabled by default because it introduces a larger run-time overhead and makes the Nginx server significantly slower. In general, we need to recompile and construct the Nginx executable, and ./configure pass the command-line option when invoking the script provided by the Nginx source package --with-debug . For example, when we download the Nginx source package and build it on Linux or Mac OS X, the typical steps are:

Tar xvf nginx-1.0.10.tar.gz
CD nginx-1.0.10/
./configure--with-debug
Make
Sudu make Install

If you're using a ngx_openresty package that I maintain, you can also ./configure pass command-line options to its script --with-debug .

When we enable the --with-debug option to rebuild the debug version of Nginx, we also need to use the standard error_log configuration instructions in the configuration file for the error log using the debug log level (which is also the lowest log level):

Error_log Logs/error.log Debug;

What is important here is the second parameter of the error_log instruction, and the debug first parameter in the previous argument is the path to the error log file logs/error.log . Of course, you can also specify a different path, but later we will check the contents of this file, so please pay special attention to the actual configuration of the file path here.

Now we restart Nginx (note that if the Nginx executable is also updated, just let Nginx reload the configuration is not enough, need to shut down and then start the Nginx main service process), and then request the sample interface we just now:

$ Curl ' http://localhost:8080/test '
56
56

You can now check the output in the previously configured Nginx error log file. Because the output in the file is much more (there are more than 700 lines on my machine), you might want to use the grep command to filter out the parts of the terminal that we are interested in:

Grep-e ' http (output Filter|script (set|value)) ' Logs/error.log

The output on my machine is like this (for ease of rendering, here are grep some simple edits to the actual output of the command, omitting the timestamp of the beginning of each line):

[Debug] 5363#0: * HTTP Script value: "32"
[Debug] 5363#0: * * HTTP script set $a
[Debug] 5363#0: * HTTP Script value: "56"
[Debug] 5363#0: * * HTTP script set $a
[Debug] 5363#0: * * HTTP Output filter "/test?"
[Debug] 5363#0: * * HTTP Output filter "/test?"
[Debug] 5363#0: * * HTTP Output filter "/test?"

Here you need to explain the specifics of the debugging information a little bit. The Set configuration directive prints two lines http script of debug information at the beginning of the actual run, where the first line of information is the value given in the SET statement, and the second row is the Nginx variable name that is assigned in the SET statement. So the above first filtered out

[Debug] 5363#0: * HTTP Script value: "32"
[Debug] 5363#0: * * HTTP script set $a

These two lines correspond to the configuration statements in our example.

Set $a 32;

And the next two lines of debugging information

[Debug] 5363#0: * HTTP Script value: "56"
[Debug] 5363#0: * * HTTP script set $a

The corresponding configuration statement

Set $a 56;

In addition, when the response body data is output in Nginx, the so-called "output filter" is called, and the echo instruction we have been using naturally is no exception. And once the Nginx "output filter" is called, it will produce debugging information similar to the following:

[Debug] 5363#0: * * HTTP Output filter "/test?"

Of course, the "/test?" section here may change for other interfaces because it shows the URI of the current request. It is easy to see that the two set statements in the previous example are actually executed before the two echo statements.

The attentive reader may ask, why this example uses only two echo statements to output, but there are three lines of http output filter debugging information? In fact, the first two lines of http output filter information do correspond to the two ECHO statements respectively, and the last line of information is the corresponding Ngx_echo module output indicates the end of the response body tag. It is in order to output this special end tag, only one more time to the Nginx "output filter" call. Many modules, including Ngx_proxy, have this behavior when outputting the response body data stream.

Now we will not be surprised that the previous example output two lines identical. 56 We never had a chance to use echo output before the second set statement. Fortunately, there are a few tricks that can still be used to achieve the initial goal:

location/test {
Set $a 32;
Set $saved _a $a;
Set $a 56;

echo $saved _a;
echo $a;
}

The output at this point conforms to the original idea of the problem example:

$ Curl ' http://localhost:8080/test '
32
56

This is done by introducing a new user variable $saved_a and $a saving $a the initial value in time before overwriting. For multiple set directives, the order of execution between them is guaranteed to be consistent with the writing order by the Ngx_rewrite module. Similarly, the Ngx_echo module itself guarantees the order of execution between its multiple echo instructions.

Careful readers should find that we have used this technique extensively in the example of the Nginx variable ramble series to circumvent the order of instruction execution due to the processing phase.

As you can see here, some readers may ask, "So how do I know exactly which processing stage it is running before I use a strange configuration command?" The answer is: review the documentation for the directive (and, of course, advanced developers can also view the module's C source directly). In the documentation for many modules, specific phases of their configuration directives are specifically marked. For example, the ECHO directive has a line in the document:

Phase:content

This line is to say that the current configuration instruction runs in content stages. If you use an Nginx module that does not happen to indicate the running phase of the document, you can contact the module directly to request a supplement. It is worth mentioning, however, that not all configuration directives are associated with a processing phase, such as the GEO directives we have previously mentioned in the Nginx variable ramble (a) and the map directives introduced in the Nginx variable ramble (iv). These configuration directives that are not associated with the processing phase are basically "declarative" (declarative), that is, not directly producing an action or process. Nginx author Igor Sysoev has emphasized more than once in public that the language used by Nginx configuration files is essentially "declarative" rather than "procedural" (procedural).

Execution order of Nginx configuration directives (i)

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.