1 nginx 安装编译,演示
将
解压出来后,cd到nginx-1.22.1,执行下面的configure命令
./configure --prefix=/usr/local/nginx --with-http_realip_module --with-http_addition_module --with-http_gzip_static_module --with-http_secure_link_module --with-http_stub_status_module --with-stream --with-pcre="实际路径"/nginx-main/pcre-8.45 --with-zlib="实际路径"/nginx-main/zlib-1.2.13 --with-openssl="实际路径"/nginx-main/openssl-1.1.1s
然后 make -j4 完成编译(pcre-8.45/missing: line 81: aclocal-1.16: command not found ⇒ sudo apt-get install autoconf)
最后安装 sudo make install
启动:
cd /usr/local/nginx
/usr/local/nginx$ sudo ==./sbin/nginx -c== conf/nginx.conf
ifconfig 看一下,当前机器的ip,然后浏览器输入IP:80,看以看到nginx的初始页面:/usr/local/nginx/html/index.html
2 nginx基础概念
它可以是工作在应用层的一个网关,网关相当于是一个IP,外界需要需要访问内网,须通过这个软网关来访问。
基于此,可以在nginx定义诸多的规则。
怎么配置这些规则呢?在\nginx-1.22.1\conf\目录下的.conf文件中。
安装后的目录在 /usr/local/nginx/conf
nginx 进程不用重启
html的内容改动,只需要浏览器,重新刷新一次就好。(这样是不是大大提高了前端开发的效率?)
3 nginx 常用命令
常用命令
$ nginx -s signal
信号signal 的值可能是以下之一:
stop 快速关闭服务
quit 正常关闭服务
reload 重新加载配置文件
reopen 重新打开日志文件
4 nginx的配置文件conf初探
4.1 测试自定义的conf
root@xx:/usr/local/nginx# touch conf/test.conf // 先创建一个空的conf文件
root@xx:/usr/local/nginx# ./sbin/nginx -c conf/test.conf // 直接执行空的conf文件试试看
nginx: [emerg] no "events" section in configuration // 报错
4.2 加入events
在conf/test.conf 填入下面的内容:
events {
worker_connections 1024;
}
再次 ./sbin/nginx -c conf/test.conf
看一下有没有启动:
ps -aux |grep nginx
root 969625 0.0 0.0 4136 272 ? Ss 14:15 0:00 nginx: master process ./sbin/nginx -c conf/test.conf
nobody 969626 0.0 0.0 4748 2588 ? S 14:15 0:00 nginx: worker process
但是它并没有监听端口:
:/usr/local/nginx# netstat -anop |grep nginx
unix 3 [ ] 流 已连接 7194380 969625/nginx: maste
unix 3 [ ] 流 已连接 7194381 969625/nginx: maste
4.3 加入server
再往 conf/test.conf 追加如下内容:
http {
server {
listen 8000;
}
}
重启 ./sbin/nginx -s stop, ./sbin/nginx -c conf/test.conf, 再次查看端口 (这次可以看到端口了)
:/usr/local/nginx# netstat -anop |grep nginx
tcp 0 0 0.0.0.0:8000 0.0.0.0:* LISTEN 969807/nginx: maste 关闭 (0.00/0/0)
unix 3 [ ] 流 已连接 7199479 969807/nginx: maste
unix 3 [ ] 流 已连接 7199480 969807/nginx: maste
浏览器中输入 http://192.168.1.80:8000/,又能访问 /usr/local/nginx/html/index.html 了
4.4 加入多个server
修改 conf/test.conf
http {
server {
listen 8000;
}
server {
listen 8001;
}
server {
listen 8002;
}
server {
listen 8003;
}
}
再查看一下进程:
# netstat -anop |grep nginx
tcp 0 0 0.0.0.0:8000 0.0.0.0:* LISTEN 969920/nginx: maste 关闭 (0.00/0/0)
tcp 0 0 0.0.0.0:8001 0.0.0.0:* LISTEN 969920/nginx: maste 关闭 (0.00/0/0)
tcp 0 0 0.0.0.0:8002 0.0.0.0:* LISTEN 969920/nginx: maste 关闭 (0.00/0/0)
tcp 0 0 0.0.0.0:8003 0.0.0.0:* LISTEN 969920/nginx: maste 关闭 (0.00/0/0)
unix 3 [ ] 流 已连接 7210410 969920/nginx: maste
unix 3 [ ] 流 已连接 7210409 969920/nginx: maste
上面的进程ID都是 969920,4个server在一个进程里面
也可以是放在多个进程里面,需要“ 往 conf/test.conf 追加worker_processes 4; ”,效果如下:
# ps -aux |grep nginx
root 970186 0.0 0.0 4276 392 ? Ss 15:21 0:00 nginx: master process ./sbin/nginx -c conf/test.conf
nobody 970187 0.0 0.0 4960 2756 ? S 15:21 0:00 nginx: worker process
nobody 970188 0.0 0.0 4960 2756 ? S 15:21 0:00 nginx: worker process
nobody 970189 0.0 0.0 4960 2756 ? S 15:21 0:00 nginx: worker process
nobody 970190 0.0 0.0 4960 2756 ? S 15:21 0:00 nginx: worker process
4.5 进程 与 server 之间的关系
nginx ---> n进程---> nsever (TCP)
一个TCP server只监听一个端口
用netstat -anop |grep 8000查看 ,现在都是监听在master 970186 上
而当客户端来连接时,处理连接的进程在worker进程上:(work进程fork了master进程)
当连接来了,交给worker进程去处理(epoll监听在worker中进行),此时这里有4个worker进程去竞争来的连接(惊群)。
用telnet连接测试一下telnet 192.168.1.80 8001 woker进程有反应了:
当worker进程较多的时候,惊群的问题,可以通过给worker进程分配锁来解决,哪个worker持有锁,则由它来连接。
5 nginx 配置文件简介
5.1 根据不同的端口号配置不同的网页(服务器)
http {
server {
listen 8000;
location / {
root /home/test/nginx/html8000/;
}
}
server {
listen 8001;
location / {
root /home/test/nginx/html8001/;
}
}
server {
listen 8002;
location / {
root /home/test/nginx/html8002/;
}
}
server {
listen 8003;
location / {
root /home/test/nginx/html8003/;
}
}
}
在html8000到html8003 四个文件夹中分别放入index.html ,最后的端口号根据目录名修改一下
5.2 负载均衡,反向代理
将访问8000代理到 backend(名字可以自定义) ,也就是 8002,8003
http {
upstream backend {
server 192.168.1.80:8002;
server 192.168.1.80:8003;
}
server {
listen 8000;
location / {
root /home/test/nginx/html8000/;
proxy_pass http://backend;
}
}
server {
listen 8001;
location / {
root /home/test/nginx/html8001/;
}
}
server {
listen 8002;
location / {
root /home/test/nginx/html8002/;
}
}
server {
listen 8003;
location / {
root /home/test/nginx/html8003/;
}
}
}
这样访问8000时,会出现两种情况:
此时,8002与8003是交替执行的
增加权重
upstream backend {
server 192.168.1.80:8002 weight=2;
server 192.168.1.80:8003 weight=1;
}
重新加载 /sbin/nginx -s reload 后
发现8002 与 8003出现次数比值是2:1,这里就是负载的比值,当有很有端口要处理时,为不同的端口配置不同的weight,可以定制负载,也可以做到负载均衡(根据服务器的强弱与访问频次的强弱进行配对)。
这里客户端访问的是服务器8000,却被代理到8002,8003,服务器被代理了,===> 反向代理(相对的正向代码是客户端被代理了)
这时负载均衡是建立在反向代理的基础上。
6 nginx代码试读
以.conf文件中的 “worker_processes”为例,通过搜索找到
{ ngx_string("worker_processes"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
ngx_set_worker_processes,
0,
0,
NULL },
NGX_MAIN_CONF 表示该指令可以在全局配置块中使用,通常位于配置文件的顶部
NGX_DIRECT_CONF 表示该指令可以在任何配置块中使用,包括全局配置块和其他块
NGX_CONF_TAKE1 带一个参数
然后找到ngx_set_worker_processes,如下:
static char *
ngx_set_worker_processes(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_str_t *value;
ngx_core_conf_t *ccf; // 可以联想一下启动命令: ./sbin/nginx -c conf/test.conf
ccf = (ngx_core_conf_t *) conf; // ccf 可以理解为解析出的conf文件的数据结构
if (ccf->worker_processes != NGX_CONF_UNSET) {
return "is duplicate";
}
value = cf->args->elts; // 从conf文件解析出来的参数数组
if (ngx_strcmp(value[1].data, "auto") == 0) {
ccf->worker_processes = ngx_ncpu;
return NGX_CONF_OK;
}
ccf->worker_processes = ngx_atoi(value[1].data, value[1].len);
if (ccf->worker_processes == NGX_ERROR) {
return "invalid value";
}
return NGX_CONF_OK;
}
可以从代码找到“worker_processes”的值还可以是 "auto"。
通过搜索 worker_processes 找到
ngx_start_worker_processes(cycle, ccf->worker_processes,
NGX_PROCESS_RESPAWN);
ngx_spawn_process(cycle, ngx_worker_process_cycle,
(void *) (intptr_t) i, "worker process", type);
再到fork进程
pid = fork();
switch (pid) {
case -1:
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"fork() failed while spawning \"%s\"", name);
ngx_close_channel(ngx_processes[s].channel, cycle->log);
return NGX_INVALID_PID;
case 0:
ngx_parent = ngx_pid;
ngx_pid = ngx_getpid();
proc(cycle, data);
break;
可以逐步与理论相印证。