Nginx命令行

当我们安装好Nginx并且准备好Nginx的配置文件后,这个时候我们就要开始操作Nginx的命令行,来启动Nginx为我们服务了。

Nginx命令行如同大多数linux命令是一样的,首先nginx后面跟上基本的指令,后面再跟指令相应的参数。

nginx -s reload

当我们需要帮助的时候呢,可以用-? 或者 -h, 来获取帮助。

nginx -?
nginx -h

默认情况下我们编译出来的Nginx会去寻找我们执行configure时指定的那个位置的配置文件。但是我们在命令行中,可以人为的指定另一个不同的配置文件。这个时候我们可以用-c 路径

那么我们还能指定一些配置的指令,这些指令可以用-g,所谓的指令就是在Nginx的configure目录里我们有很多条指令,但是这些条指令如果我需要在命令行中覆盖中间的一些指令呢,是可以做到的,可以使用-g来做到。

接下来我们还可以指定运行目录,因为我们的运行目录下会有很多的子目录,这些子目录比如说log,比如说modules。

如果我们指定了运行目录呢,他就会把我们在configure中定义好的那个运行目录替换掉。

nginx去操作运行中的进程的方法,一般是通过发送信号的,发送信号呢我既可以通过linux通用的kill命令也可以用nginx -s这个子命令,这个子命令后我们可以用stop,quit,reload,reopen

nginx -s stop # 停止nginx服务
nginx -s quit # 优雅的停止nginx服务
nginx -s reload # 重载配置文件
nginx -s reopen # 重新开始记录日志文件。

有时候我们改了配置文件之后不知道他里面有没有语法错误,我们可以用-t让nginx先去测试一下配置文件有没有问题,如果没有问题我们再发布到线上。

我们可以打印nginx的版本信息和编译信息,其中-v可以看到他的版本信息,-V就是我们在编译他的时候,用configure这个脚本执行的时候所加的所有的参数,都可以在这里看到。

下面我们做一个命令行的演示,主要包括三个部分,第一个是重载配置文件,第二个是热部署,第三个是切割日志文件。

首先我们来看一下什么叫重载配置文件,也就是说现在我需要去修改nginx配置文件中的一些值,比如说conf/nginx.conf文件中,我们打开tcp_nopush。

当我们修改完这个配置文件以后,我们可以直接执行nginx -s reload这样的话nginx是在不停止对客户服务的情况下使用了我们tcp_nopush这个新的配置项,非常的简单。

接下来我们看热部署,首先热部署是说我的nginx是正在运行的,现在我想更换最新版本的nginx,那么根据我们之前所说的,nginx编译方法,现在我们下载了一个更新的nginx。

说先我需要把现有的nginx二进制文件备份一下,因为我们所更换的只是二进制文件,并不会更换其他文件,接着我们需要把我们刚刚编译好的,最新版本的nginx二进制文件,copy到这个目录中,替换掉正在运行的进程所使用的的nginx文件。

copy完成我们需要给正在运行的nginx的master进程发送一个信号,告诉他我们开始进行热部署了,做一次版本升级,这个时候我们给nginx的master进程发送一个信号,USR2这个信号。

kill -USR2 进程号(13195)

接着nginx会新启一个master进程,那么这个新的master进程他使用了我们刚刚复制过来的最新的nginx二进制文件来启动的。

老的worker呢也在运行,新的master会生成新的worker,他们会平滑的把所有的请求过渡到新的二进制文件启的进程中。

这样我们就实现了一个平滑的过渡,这个时候我们再去看进程的状况,可以看到新老master进程和worker进程都在运行,但是老的worker进程已经不再监听80或者443这样的web端口了。

所以新的请求新的连接只会进入新的nginx进程中,这个时候我们需要向老的nginx进程发送一个信号叫做WINCH,告诉他请优雅的关闭你的所有进程。

kill -WINCH 13195

这时老的master进程和老的worker进程有一个变化,老的worker进程呢已经优雅的退出了,但是我们看到老的master进程还在,但是已经没有worker进程了。

这其实说明一件事情就是所有的请求已经全部切换到我们新的nginx中了,但是我们有可能会发现一些问题,需要把新版本退回到老版本,所以老的进程我们还可以发送reload命令,让他重新把worker进程拉起来。再把新版本关掉。

所以老的master进程他是不会自动退出的,保留在这里允许我们做版本回退。

接下来我们看日至切割,比如说我们当前的日志已经很大了。我需要把以前的日志备份到另外一个文件中,但是nginx还是正常运行的。

这就要通过reopen这个命令来做,首先我们需要把当前正在使用的日志copy一份放在另外的位置.

mv access_log bak.log

接着我们执行命令reopen。

nginx -s reopen

这个时候就重新生成了一个access.log, 原本的log我们备份成了bak.log,这样我们就实现了日志切割。

当然这种方法会非常不好用,实际上我们往往是每一天,或者是每一周执行一次日至切割,我们可以先写成一个bash脚本。

在这个bash脚本中我首先把这个文件复制一下,再执行-s reopen这个命令,最后把这个脚本放在crontab中。

以上就是nginx命令行的几个简单演示。

静态资源服务器

使用nginx搭建一个静态的资源服务器,这要求我们有一台安装了linux的机器。

编辑conf/nginx.conf文件。首先我们找到server代码块中,listen配置监听哪个端口,这里我们用8080端口,然后我们需要配置一个location,这里所有的url请求都访问到www文件夹,这里我们使用/表示所有的请求。

我们这里需要指定这个url的后缀要与我们的文件目录后面的后缀一一对应,我们这里有两种用法,root和alias,root相对来说有一个问题,他会把url中的一些路径带到我们目录中来,所以我们通常使用alias。

alias就是Nginx安装目录的www目录下,后面的路径与我们的url路径是一一对应的。

server {
    listen 8080;
    ...
    location / {
        alias www/;
        ...
    }
    ...
}

那么我们做完配置之后再去启动Nginx就可以看到效果了。我们在浏览器中访问localhost:8080就可以访问。

nginx -s reload

这里我们开启gzip压缩,做完gzip压缩以后,传输的字节数会大幅度减少,所以通常我们会打开gzip。

首先我们打开nginx.conf文件,找到http代码块中的gzip相关选项,打开gzip(off -> on), gzip_min_length是小于多少字节不再执行压缩,因为小于一定的字节http传输直接就可以发送了,压缩反而消耗cpu性能,这里我们为了测试写成1,gzip_comp_level代表压缩级别,gzip_types是针对某些类型的文件才做gzip压缩。

http {
    ...
    gzip on;
    gzip_min_length 1;
    gzip_comp_level 2;
    gzip_types text/plain applicaton/x-javascript text/css image/png;
    ...
}

配置好之后我们重启Nginx, 浏览器中查看就会发现,传输的文件已经减少了很多,响应头中多出了Content-encoding: gzip。所以使用gzip以后整个web服务传输效率会高很多。

接下来我们演示另一个常用的功能,比如跟目录下有一个文件夹叫dlib,假定我们需要把dlib中的文件,或者文件夹及其目录结构信息分享给用户,用户来决定使用哪些文件。

这种常用的应用场景下呢,Nginx给我们提供了一个官方模块叫做autoindex, 我们先来看一下autoindex的说明,他可以提供当我们访问以/结尾的url时,显示这个目录的结构。使用方法也特别简单,就是autoindex on加入这样一个指令就可以了。

location / {
    autoindex on;
}

reload之后代码就生效了,他会把我们所访问的文件夹内所有文件列出来,当我们打开一个目录时,可以继续显示这个目录中的文件,这是一个很好的静态资源帮助功能。

还有一个非常常见的功能,比如我们的公网带宽是有限的,当有很多并发用户使用我们的带宽时,他们会形成一个争抢关系,我们可能会为了让用户访问某些大文件的时候来限制他的速度,以期望能够分理出足够的带宽给用户访问一些必要的小文件,如css,js等。

这个时候我们就可以使用set命令,配合我们一些内置的变量去实现这样的功能,比如说我们加上set $limit_rate 1k,他就在限制我们Nginx向客户浏览器发送响应的一个速度。

他的意思是每秒传输多少数据到浏览器中,这里我们写的是1k,这个时候我们去访问首页会发现,速度非常慢。

location / {
    set $limit_rate 1k;
}

接下来我们看下Nginx的另外重要的功能,就是记录access日志,首先我们需要记录access日志到底是怎样一种格式,我们找到一个指令叫做log_format, 他用来定义日志的格式。这里可以使用变量。

http {
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
    '$status $body_bytes_sent "$http_referer" '
    '"$http_user_agent" "$http_x_forwarded_for"';
}

$remote_addr为远端的地址,也就是浏览器客户端的ip地址,$time_local表示当时的时间。$status是返回的状态码。这样的日志格式我们需要命名,比如说我们这里命名为main。

为什么要做命名的,可能我们要对不同的域名下,做不同格式的日志记录,或者对不同的url一些大文件或者做一些反向代理等等不同用途时,我们记录不同日志格式。

配置好log_format之后我们还要去设置我们日志记录在哪里,我们可以用access_log这条指令,access_log所在的位置决定了他所属的这样一类请求会记录到后面的路径中,采用main这样一种格式。

比如access_log这里放在了server下,也就是所有发现这个域名或者这个端口的请求日志,都会记录到这个文件中。

那么刚刚我们再说日志格式的时候,我们提到了很多变量都可以放进来,这里我们举个例子。只要是变量我们这里都可以使用,gzip中有个变量叫做$gzip_radio, 表示当时使用的压缩比率,我们可以吧$gzip_radio放在我们的access.log中。

server {
    listen 8080;
    access_log logs/yindong.log main;
    location / {
        alias dlib;
    }
}

当我们配置好yindong.log后,所有的请求在完成之后都会记录下一条日志,在我们的yindong.log中, 我们可以进入logs/yindong.log中查看。每一条都是我们设置的格式。

以上就是搭建web静态资源服务器的常用方法和基本流程。

反向代理

前面几节像大家演示了Nginx怎样作为一个静态资源web服务器工作,我们将以这个作为例子,把这个静态资源服务作为上游服务,再搭建一个Nginx作为反向当离,然后向大家演示,Nginx作为反向代理应该怎样使用。

由于上游服务要处理非常复杂的业务逻辑而且强调开发效率,所以他的性能并不怎么样,我们使用Nginx作为反向代理以后呢,可以由一台Nginx把请求按照负载均衡算法代理给多台上游服务器工作。

这样我们就实现了水平扩展,在用户无感知的情况下,我们添加更多的上游服务器,来提升我们的处理性能,而当上游服务器出现问题的时候,那么Nginx可以自动的把请求从有问题出现灾难的服务器,转交给正常的服务器。

我们可以把服务器作为上游服务器,上游服务器一般是不能被公网直接访问到的,我们可以在listen 8080端口时前面加上一个ip地址,比如127.0.0.1表示只能本机的进程来访问我们8080端口。

server {
    listen 127.0.0.1:8080;
}

这个时候我们再去访问页面地址就可以看到页面已经无法访问了,因为Nginx拒绝了浏览器发过去的链接。

现在我们搭建一个Nginx的反向代理,之前的Nginx服务我们使用的是Nginx的1.14版本,反向代理我们用openRestry。

反向代理另外一个Nginx的配置文件,我们首先添加一个upstream,也就是我的上游服务,他的一台server,访问地址是127.0.0.1:8080,如果我有很多台上游服务可以依次的放在这里。

upstream设置的一批服务,我们做一个命名比如叫local,接着我们做一个简单的配置。

因为我们这里作为反向代理的服务器有域名,对所有的请求我们使用proxy_pass这样一条指令,代理到我们刚刚配置的上游服务里。

upstream local{
    server 127.0.0.1:8080;
}
server {
    server_name yindong.com;
    listen 80;
    location / {
        proxy_set_header Host $host;
        proxt_set_header X-Real_IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://local;
    }
}

这时我们访问代理服务器上配置的域名,就可以看到访问结果了。

这个时候我们的响应头是由反向代理服务器发给我们的。

现在我们看下localtion中相关的配置,比如proxy_set_header,这个命令他起到一个这样的作用,因为有了一台反向代理,所以我们再去拿一些变量或者一些值可能就会出错了,比如说一个tcp链接他其实是有对端地址的,但是有了反向代理以后我们的反向代理与客户端是一个tcp链接,而反向代理与上游服务器又是另外一个连接,所以如果我们取原来的变量叫$remote_addr, 也就是tcp链接的远端地址,那么这个时候在上游服务那里,我去到的其实是我发现代理的这台机器的地址,那么如果我想拿浏览器的地址,作为我限制浏览器访问速度等功能的一个作用时其实是拿不到的。所以通过proxy_set_header我可以把有一些值添加一条新的header发送到上游,比如说叫x-real-ip,然后把他的值设为我们从tcp链接里面拿到的远端ip地址。

$host也是同样的因为用户直接访问的域名,是他在浏览器输入的,我们既可以让他在上游服务器可以处理这个域名,也可以由反向代理来处理。

所有这些配置特性我们都可以在官网中的http_proxy_module找到。

这里有个很重要的特性就是proxy_cache, 因为当我们的Nginx作为反向代理时,通常只有动态的请求,也就是不同的用户访问同一个url看到的内容是不同的,这个时候才会交由上游服务处理。

但是有一些内容可能是一段时间不会发生变化的,这个时候为了减轻上游服务器的压力,我们就会让Nginx把上游服务返回的内容缓存一段时间,比如缓存一天,在一天之内即使上游服务器对这个内容的响应发生了变化,我们也不管,我们只会去拿缓存住的这段内容向浏览器做出响应。

因为Nginx的性能远远领先于上游服务器的性能。所以使用这样一个特性后,对我们一些小的站点会有非常大的性能提升。

下面我们来演示一下怎么样配置一个缓存服务器。配置缓存服务器首先我们要去通过proxy_cache_path这条指令去设置我们的缓存文件写在哪个目录下。

比如这里是/tmp/nginxcache, 以及这些文件的命名方式,这些文件的关键之key, 我们是要放在共享内存中的。这里我们开了10MB的共享内存,命名为my_cache, 这些参数都在控制我们的缓存。

proxy_cache_patj /tmp/nginxcache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path_off;

这些缓存的使用方法就是在我们需要做缓存的url路径下,添加proxy_cache, 后面所跟的参数就是我们刚刚开辟的那一个共享内存,那么在共享内存中我们所设置的key是什么呢,就想我刚刚说的,同一个url访问时对不同的用户可能展示的东西是不一样的,所以用户这样一个变量就要放在key中。

这里我们做一个非常简单的key,比如说我们只跟我们访问的host url我们可能加了一些参数,这些参数可能已经指明了是哪个用户哪个资源,$host$uri$is_args$args; 这些作为一个整体的key。对于哪些访问不返回,我们这里也做了一些简单的处理。

location / {
    proxy_cache my_cache;
    proxy_cache_key $host$uri$is_args$args;
    proxy_cache_valid 200 304 302 1d;
}

加完这些参数以后,我们可以尝试停掉上游服务,然后访问站点,可以发现站点仍然是可以访问的。就是因为被缓存了。

Access日志

Access日志记录了Nginx非常重要的信息,我们可以用Access日志来分析定位问题,也可以用它来分析用户的运营数据,但是如果想实时分析Access.log相对来说还比较困难。

有一款工具叫GoAccess, 他可以以图形化的方式,通过websocket协议实时的把Access.log的变迁反应到浏览器中,方便我们分析问题。下面我们将介绍GoAccess怎样应用在Nginx的Access.log的分析中。

GoAccess的站点是 https://goaccess.io, 他以一种非常好的图形化方式显示给我们,我们先来看以前之前的access日志。我们来看下之前搭建的静态服务器中的access是怎样的格式。

cat yindong.log

显示的是我们没有修改任何配置,只是安装完Nginx之后默认的access的日志格式所打印出来的日志内容,那这个时候GoAccess站点给我们提供了一个非常方便的日志格式用法。

我们打开GoAccess的Get Started目录快速开始,当我们的Nginx所用的log配置没有发生任何变化时,我们可以使用--log-format=COMBINED这样一种格式。

也就是说Nginx的Access非常灵活,我们可以自己添加各种不同的各模块的内置变量加入到Access中,所以当我们修改了Access.log的格式的时候,我们需要在log-format中重新定义我们所添加的格式,那么在这里我们没有添加任何的变量。

那么GoAccess是怎样使用的呢,它实际上会去使用-o这个参数生成一个新的html文件,把当前我们access.log文件中的内容以html图表的方式展示出来,当access.log变迁的时候呢GoAccess会新起一个socket进程,通过一种端口的方式把新的access.log推送到我们的客户端。

goaccess access.log -o report.html --log-format=COMBINED

现在我们开始执行GoAccess程序,首先我们制定了access.log程序制定的位置(yindong.log), 我们把它输出到../html/report.html这个文件中,我们使用的是--real-time-html就是事实更新这个页面的方式,我们的时间格式,--time-format='%H:%M:%S', 日期格式: --date-format='%d/%b/%Y', 以及日志格式--log-format=COMBINED都已经指定好了。

cd logs
goaccess yindong.log -o ../html/report.html --real-time-html --time-format='%H:%M:%S' --date-format='%d/%b/%Y' --log-format=COMBINED

那么GoAccess的安装可以用yum或者wget,也可以下载源码进行编译,这里就不再演示了。

启动完成之后可以看到一条log叫做 WebSocket server ready to accept new client connections, 也就是他已经打开了一个新的websocket监口,当我们访问他的report.html的时候,会向这个进程发起连接, 由这个进程给我们推送最新的log的变更。

接下来我们还要在nginx.conf中添加一个location,就是每当我们访问/report.html时候我们需要用alias把他重定向到我们刚刚访问的report.html中。

server {
    ...
    location /report.html {
        alias /usr/local/openresty/nginx/html/report.html;
    }
    ...
}

这时我们打开localhost:8080/report.html可以发现页面中展示7张表,因为我们静态web服务器刚刚搭建,所以几乎没用请求,这里有一些总体的统计,也有根据时间,根据浏览器,根据url,根据带宽等等各种信息统计出来的数值,而且这个数值是实时变动的,比如现在是281。

我们没有刷新这个页面,在我们去访问服务器之后我们日志发生变更,所以这里也变成了287。

以上就是GoAccess.log的简单用法,那么使用他以后我们可以非常直观的看到我们access.log统计信息上的变迁,他对我们分析我们网站的运营情况非常有帮助,可以看到每个时间点,每一周每一天,甚至不同的国家地区使用不同浏览器和操作系统的人使用我们站点的一个比例和分布。