nginx

285 阅读9分钟

作用

1.负载均衡器
2.转发请求
3.缓存静态资源

什么是共享内存?

首先,共享内存,是所有进程都可以访问。是进程通信的一种方法。

其次,就是磁盘文件和内存的映射。

这里的内存是共享内存。

但是,在NGINX里,是没有用到磁盘文件,而只用到共享内存。

NGINX的共享内存,主要是被主进程和从进程共同使用。

主进程是master进程,从进程是work进程。

主进程,主要干几件事情:
1.管理所有/全局东西
2.创建从进程
fork方法
3.申请共享内存
Linux有专门的申请共享内存方法,其实就是磁盘文件和内存映射的方法。叫map什么的。

从进程,主要作用就是,处理请求。

线程

NGINX的进程都是单线程,不是多线程。

linux epoll 多路复用 基于注册事件机制 请求连接队列 异步非阻塞


消费队列和事件队列的区别?
不同点
一个是数据,一个是操作,都有写读。只不过一个是是写数据,一个是写操作。数据是写到集合里,比如队列。操作也是写到一个数据结构里,操作其实也只是一个对象,只不过概念有一点不一样而已。比如,消费队列是叫消费者需要订阅主题/消费队列,生产者向消息队列写数据。而事件是消费者需要先注册一个什么事件,比如TCP socket里的连接事件,写数据事件,,读数据事件。

相同点
都有生产者和消费者,都是一个生产者生产数据/操作,一个消费者消费数据/操作。

TCP连接细节

1.半连接
Syn
2.连接成功
Ack
3.关闭
Fin

4.窗口抖动?
这他妈什么破名字

5.backlog
队列最大数量,分别在各个不同的状态

创建连接,握手的这个过程,都是由操作系统负责,即Linux内核负责。

具体来说,就是客户端实际上是和操作系统内核打交道,一直到最终内核创建连接,并且把连接放到连接集合,即accept队列里。

NGINX,包括其他的所有的服务器软件,都只是从操作系统内核的连接队列即accept队列里取一个已经创建好的连接对象而已。

操作系统内核有两个集合,一个是未完成的连接,即刚进来的连接,新的连接,所谓未完成,指的是握手的这个流程没有完成。

一个是已经完成的连接,即完成握手的连接。

握手其实也就是请求,响应。按理来说,应该只有两步。

但是,实际情况是,更复杂一点。多了一个确认的过程。

本来应该是
1.客户端请求
2.服务器确认收到请求,处理数据
3.服务器返回数据

实际是
1.客户端请求
发送请求
2.服务器确认收到请求
把确认发给客户端。
你收到了请求,要告诉别人即客户端,别人即客户端才知道你服务器收到了请求。
3.客户端确认服务器收到了请求
和2同理,客户端收到了服务器的确认收到客户端请求,但是客户端也需要把这个确认告诉服务器。
4.服务器,即内核,把新连接放到已完成握手的队列里面

实际上,就是多了一个互相确认的过程,这个确认是指,还有点不一样。

服务器的确认是,收到了客户端的请求。

客户端的确认是,服务器收到了可客户端的请求。

内存池

每个http请求,分配一个内存池。 统一申请,统一释放。


六、内存池的设计 为了减少避免出现内存碎片、减少向操作系统申请内存的次数、降低各个模块的开发复杂度,Nginx采用了简单的内存池(统一申请,统一释放)。比如为每个http请求分配一个内存池,请求结束时销毁整个内存池。


c本来是需要程序员自己分配内存,自己释放内存,这样有两个问题,麻烦,而且还容易忘。基于此,JVM的垃圾回收就是为了解决这个问题的,就是内存释放的问题,把这个工作自动化,而不需要程序员人为的处理这个跟具体业务没什么关系的操作。至于分配内存,这个肯定是需要程序员手动创建的,因为创建对象,是程序员要不要创建和创建什么对象。NGINX里的内存池,也是为了解决自动释放内存的问题,具体是每个请求和每个连接都有自己的独立的线程池。这样的目的是,当请求/连接销毁的时候,即生命周期结束的时候,那么内存池也立即释放,这样就不会出现线程池申请之后,就一直占着内存的情况。

linux单机进程之间通信的各种方式

信号是其中的一种方式。

回调函数

所有的回调函数,都是基于阻塞队列,而阻塞队列的调用者是操作系统,就是有数据来了,就给消费者。

web服务器

按时间顺序
1.Apache
C
2.Tomcat
Java
3.NGINX
C
高性能
现在市场占用率第二名,超过Tomcat

自旋锁

是什么
顾名思义,是旋转多次获取锁,就是循环多次获取锁。而不是,在那里等待别人释放。


代码
代码如何实现,来一段代码。


锁的使用时间长短
因为要循环多次获取锁,所以适合锁占用时间短的情况。否则,锁一直被别的线程占用,那么自旋锁线程一直在长时间空转,浪费CPU。

不是获取不到锁,就必须要等待吗?为什么还能继续循环执行获取锁。

自旋锁,适合核心业务处理代码,因为必须要尽快主动获取锁,不能只是光等待。

信号量

作用
同步。


代码

信号

作用
进程之间的通信。主要是短数据,比如01,就是一个数字,一个进程通知一个进程做什么事情。


代码

与apache区别

1.nginx 单线程 //1.只要是基于netty的服务器/客户端架构,都是单线程处理所有请求,redis也是。2.dubbo也是单线程。dubbo主要是通信,服务提供者和服务消费者双方是对等的,因为双方都可以同时既是服务提供者又可能是消费者。不过,dubbo的双方通信时,也是基于单连接且长连接。也就是说,所有请求由单线程处理。(注:默认dubbo协议是单连接且长连接;hessian协议支持多连接且短连接,类似tomcat)

2.apache 每个请求一个线程 和tomcat一样

master和worker进程的区别?

1.接受请求
master
2.处理请求
worker //worker由master创建fork


为什么要分成一个master一个worker两个进程? 各司其职


好处? 提高处理速度


两个进程之间如何通信? master对work进程采用信号进行控制。

负载均衡算法

nginx 的 upstream目前支持 4 种方式的分配 
1)、轮询(默认) 
      每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。 
2)、weight 
      指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。 
2)、ip_hash 
      每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。  //最佳实践推荐,因为可以解决session的问题 //支付系统,没有在程序层面处理session的问题,所以同一个用户每次请求的tomcat服务器是同一个tomcat。如果ip经常改变怎么办?那就只能重新登录,不过一般很少出现这种情况。//hashcode具体计算方式?ip——》hashcode——》hashcode/机器数量 取余数,因为除数和被除数的值固定,所以同一个用户ip的请求的tomcat是同一个。
3)、fair(第三方) 
      按后端服务器的响应时间来分配请求,响应时间短的优先分配。  
4)、url_hash(第三方)

nginx内置策略包含加权轮询和ip hash

加权轮询算法分为先深搜索和先广搜索,那么nginx采用的是先深搜索算法,即将首先将请求都分给高权重的机器,直到该机器的权值降到了比其他机器低,才开始将请求分给下一个高权重的机器;

L7 负载均衡器?
待补充

C10K

请解释什么是C10K问题? C10K问题是指无法同时处理大量客户端(10,000)的网络套接字。

惊群

8、如何解决惊群现象?

惊群是多个子进程在同一时刻监听同一个端口引起的;

Nginx解决方法:同一个时刻只能有唯一一个worker子进程监听web端口,此时新连接事件只能唤醒唯一正在监听端口的worker子进程。

采用锁,互斥量实现!!

有哪些核心模块?

1.核心
2.配置
3.http
4.socket


一、Nginx优秀模块 模块设计:

高度模块化设计,除了少量核心代码,其他一切接模块。官方Nginx共有五大类型模块:核心模块、配置模块、事件模块、HTTP模块、mail模块。

要注意的是:nginx的模块是静态的,添加和删除模块都要对nginx进行重新编译,这一点与Apache的动态模块完全不同。

参考

陶辉 nginx

blog.csdn.net/Watson2016/… //写得好

segmentfault.com/a/119000001… //写的不好