背景
这篇文章是陶辉nginx的学习笔记。
什么是共享内存?
首先,共享内存,是所有进程都可以访问。是进程通信的一种方法。
其次,就是磁盘文件和内存的映射。
这里的内存是共享内存。
但是,在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
队列最大数量,分别在各个不同的状态
具体来说,就是客户端实际上是和操作系统内核打交道,一直到最终内核创建连接,并且把连接放到连接集合,即accept队列里。
NGINX,包括其他的所有的服务器软件,都只是从操作系统内核的连接队列即accept队列里取一个已经创建好的连接对象而已。
操作系统内核有两个集合,一个是未完成的连接,即刚进来的连接,新的连接,所谓未完成,指的是握手的这个流程没有完成。
一个是已经完成的连接,即完成握手的连接。
握手其实也就是请求,响应。按理来说,应该只有两步。
但是,实际情况是,更复杂一点。多了一个确认的过程。
本来应该是
1.客户端请求
2.服务器确认收到请求,处理数据
3.服务器返回数据
实际是
1.客户端请求
发送请求
2.服务器确认收到请求
把确认发给客户端。
你收到了请求,要告诉别人即客户端,别人即客户端才知道你服务器收到了请求。
3.客户端确认服务器收到了请求
和2同理,客户端收到了服务器的确认收到客户端请求,但是客户端也需要把这个确认告诉服务器。
4.服务器,即内核,把新连接放到已完成握手的队列里面
实际上,就是多了一个互相确认的过程,这个确认是指,还有点不一样。
服务器的确认是,收到了客户端的请求。
客户端的确认是,服务器收到了可客户端的请求。
内存池
c本来是需要程序员自己分配内存,自己释放内存,这样有两个问题,麻烦,而且还容易忘。基于此,JVM的垃圾回收就是为了解决这个问题的,就是内存释放的问题,把这个工作自动化,而不需要程序员人为的处理这个跟具体业务没什么关系的操作。至于分配内存,这个肯定是需要程序员手动创建的,因为创建对象,是程序员要不要创建和创建什么对象。NGINX里的内存池,也是为了解决自动释放内存的问题,具体是每个请求和每个连接都有自己的独立的线程池。这样的目的是,当请求/连接销毁的时候,即生命周期结束的时候,那么内存池也立即释放,这样就不会出现线程池申请之后,就一直占着内存的情况。
linux单机进程之间通信的各种方式
信号是其中的一种方式。
回调函数
所有的回调函数,都是基于阻塞队列,而阻塞队列的调用者是操作系统,就是有数据来了,就给消费者。
web服务器
按时间顺序
1.Apache
C
2.Tomcat
Java
3.NGINX
C
高性能
现在市场占用率第二名,超过Tomcat
自旋锁
是什么
顾名思义,是旋转多次获取锁,就是循环多次获取锁。而不是,在那里等待别人释放。
代码
代码如何实现,来一段代码。
锁的使用时间长短
因为要循环多次获取锁,所以适合锁占用时间短的情况。否则,锁一直被别的线程占用,那么自旋锁线程一直在长时间空转,浪费CPU。
不是获取不到锁,就必须要等待吗?为什么还能继续循环执行获取锁。
自旋锁,适合核心业务处理代码,因为必须要尽快主动获取锁,不能只是光等待。
信号量
作用是同步。
代码
信号
作用是进程之间的通信。主要是短数据,比如01,就是一个数字,一个进程通知一个进程做什么事情。
代码
参考
陶辉 nginx