首页 > 系统服务 > 详细

Linux运维 第三阶段 (十五)理解LNMP

时间:2015-12-29 17:48:21      阅读:476      评论:0      收藏:0      [点我收藏+]

Linux运维第三阶段(十五)理解LNMP

 

一、相关概念:

nginxengine-Xnginx.orgperformancestabilityrich featuresimple configurationlow  resource consumption):

HTTP-server(轻量级、高性能WEB服务器)

reverse proxy(反向代理服务器,mail proxy servertcp proxy server,任何一种proxy必须要能精确理解某种协议的内容及操作,例如mysql-proxy能理解mysql的各种SQL语句从而实现rw-splitting

注:nginx能理解三种协议(httpmailsmtppop3imap);tcp);早期nginx就是用来做reverse  proxy;它起步就是用来解决C10K problemconnection 10K,连接数达到一定程度会产生诸多问题,网络服务在处理数以万计的客户端连接时,往往会出现效率低下甚至完全瘫痪)

 

 

1、单进程模型(阻塞模型,如第一个用户的请求与server建立连接后,当有第二个用户向服务器请求就要等待,等第一个用户断开后才能连接)

 

2、多进程模型:

httpdprefork模型,httpd是主进程,当有用户请求,httpd会派生出子进程予以响应,主进程管理这些子进程(创建、销毁等);

每个进程响应1个用户请求,进程是重量级的资源实体,是CPU的执行单位(调度的单位),CPU要给它分配时间片、内存资源等,开销大,内核在某一时刻还要调度这些进程,进程很多时会带来大量的进程切换CScontent switch,进程很多,但CPU有限,由内核处理进程切换),某一时刻1CPU只处理1个进程(1个用户请求),要让每个用户都觉得自己处于活动状态,进程会轮流在CPU上执行,每个进程仅占用CPU很短的时间;

如有1234四个进程,内核通过自己的内部程序(进程调度程序),观测每个进程的属性,发现下一次轮到了3号进程,将3号进程唤醒并将其载入到CPU的寄存器,将CPU的指针指向3号进程的地址空间,然后内核自己退出并转为睡眠状态,3号进程运行结束(如只有5ms),内核将3号进程退出转为睡眠,再将4号进程载入到CPU,指针指向4号进程地址空间,每一次进程切换,内核就要占用CPU,就要花费一些时间,若切换频繁会有大量时间浪费在进程切换上,进程切换并没有帮助用户响应内容,在内核中消耗的时间都是额外的内核开销(sys),这是多进程模型的缺陷(每个进程是独立的运行单位);

每个进程响应一个用户请求,若请求的是主页面,进程调用内核,内核从硬盘中取得数据返回给该进程(IO调用,在这过程中进程处于睡眠状态,不可中断睡眠,uninterruptable,阻塞状态,IO产生的阻塞,若强行中断睡眠,这时IO调用还未结束,内核还未返回数据,将其唤醒也无法响应用户请求),内核从硬盘中获取数据是先载入到内存的内核空间(内存分内核空间和用户空间),再将载入的数据复制到进程的地址空间,这时进程才能访问到;

数据如何从硬盘载入到内存?内存是分页的(buffer/cache,有些内存不分页那是堆内存),一次仅读取一个页面的数据,若每个页框大小为4K,每个磁盘块也是4K(磁盘块分1K2K4K),每个文件占用1个或多个磁盘块,每次读一个磁盘块填满页面,若磁盘块是2K则要读取2个磁盘块填满1个页面,数据加载结束才开始复制(数据从内存的内核空间-->进程的地址空间),如果是访问一个文件的一部分这是另外一种机制;

若一个文件占据10个内存页,每个内存页是4K,每个磁盘块是4K,这要涉及到10个磁盘块,每次要读哪个块,读完后数据要放至内存的哪个地址中(如何选择一个内存页面从哪分配),内核操作文件系统FSFS对应磁盘块,对应的是哪个块这由驱动程序管理,驱动程序运行是内核的功能,内核运行是要有CPU参与的,为加载一个文件内核会很繁忙,为尽可能降低内核对CPU的占用,让当前主机的CPU尽可能运行程序,现在硬件都具有DMA机制(direct memory access),在DMA下,内核在其内核空间(内存的缓冲区)中找一段连续的内存空间,将起始地址给DMA芯片(有访问内存的能力,有访问硬盘数据的能力,有数据传输占据系统总线的能力,有控制系统总线、数据总线的能力),交由DMA控制,由DMA指挥着将数据从硬盘加载至内存中,数据加载完成DMA会产生一个中断,强行告知CPU已完成,CPU这时将当下正在运行的进程中断并将其转为睡眠状态,内核将自己空间中加载好的数据复制到进程的地址空间,进程再通过与网卡交互(通过PCI总线与网卡联系)通过网线返回给用户,若多个进程处理的都是一个主页面的内容,每一个进程IO-->内核调用(IO调用)-->磁盘空间-->内核空间-->进程空间,内核有加速机制,当第一个进程读完后会在内存的内核空间中缓存下来,第二个进程访问的是同样内容直接从内核空间复制

若主页2M4个进程访问同一主页,在用户空间占据的内存大小4*2M=8M,本来一个主页面只需占据内存2M大小,但实际占用了8M内存(多进程模型的缺陷之一)

多进程模型中,系统调用结束(内核准备好数据),当前进程与client的连接处于等待状态,连接在tcp/ip协议栈是由内核管理的,内核怎么通知进程程哪个IO完成了?采用select()机制(内核要输出一个数据结构,假设这个数据结构是一排灯,第123的灯对应第123的进程,哪个灯亮了就说明哪个进程的数据准备好了,当第2个灯亮起时第二个进程就知道它要的数据准备好了,每一次内核准备好数据都要向用户空间输出整个数据结构,不输出进程是无法理解的,这种每次都逐个扫描IO事件描述符,将它从内核空间输出到用户空间的方式叫selectselect最多支持1024个灯泡,1024个进程,多余1024的进程只能在一边等待,早期的系统调用采用这种方式)

 

多进程模型总结:

每个进程响应一个请求;

进程量大,进程切换次数过多,会消耗大量资源,若是C10K1W个请求connection,可能无法应付;

每个进程的地址空间是独立的,很多空间是重复的数据,所以内存利用率低

技术分享

注:上图是进程在内存的分布

注:下图是多线程在内存的分布

技术分享

 

3、线程thread

lwplight weight process轻量级的进程,是进程内部的子运行单位;linux不支持原生态的线程(winsolaris支持),linux把线程当作进程对待,在管理上略有区别,在linux上实现线程功能需借助glibc提供的线程库来完成(以完成线程的创建、撤销等管理),linux上提供的线程库有多种(有内核自带的,也有redhat提供的),不同的线程库对系统资源的占用是不一样的;

所以线程是运行在进程内部的子单位,在进程内部可以启动多个执行流(线程是并发执行流),

程序=指令+数据;单个进程中指令在CPU上运行,是将指令从上至下按控制流程一条一条执行(仅一条流水线),用到数据时到堆或栈中去取(堆空间中的数据通常是打开的文件、栈空间中的数据存放变量),每一个进程的数据都是自己管理的,如果用到循环也是在局部循环;有了线程后,执行流是并发的是多个的,所有执行流共享这个进程的数据区域(共享全局变量、堆,打开的文件等,但栈是不能共享的,栈中各层函数帧代表着一条执行线索,一个线程是一条执行线索,每个线程独占一个栈,这些栈必须在所属进程的内存空间中),每一个执行流都是一个独立的实体,所以线程就是运行在同一个进程内部(进程的内存空间)共享了很多资源的运行的实体;

不同用户访问同一个文件,多线程比多进程性能要好很多:当第一个用户请求进来,server用一个线程响应,若这个线程要加载文件,经系统调用-->内核的内存空间-->复制到进程的内存空间,响应给前端,当第二个用户请求访问同样的文件,这个进程的内存空间已有数据,则直接从进程的内存空间返回(不需经系统调用到内核空间再复制到进程空间这个过程);

若连接请求很多,如有10K个连接,若由一个进程管理,内部很复杂,首先线程间要切换,线程过多,导致大量切换,会带来线程抖动(很严重,线程刚占用CPU啥事没干就切换出去了),切换本身靠内核来完成,也仍会占用过多资源;还要解决彼此间资源争用就超出我们预料,例如第一个线程要执行写操作,第二个线程若要读这时就要等待,等待写完成才能读(读是共享的,但读写不能共享),若要等待那CPU就要浪费给这个线程了,若进程切换,线程来读读不了,就要等

注:等有忙等和闲等;忙等,用的是自旋锁spin lock,看到第一个线程在写,读不到,若马上切换,要是刚切换出去,数据准备好了可读了,那就白切换了,再多等一会,CPU是不允许空闲的,CPU只要一供电,时钟频率就一直在那,无论有无程序执行CPU都一直在转,只不过计算能力白白流逝了,这就要运行指令,如每隔1ms来看下,这个线程始终占用着CPU不退出,时间未耗完事情没干完就不走,这叫忙等;闲等,切换出去,时间没耗完,事情没干完自愿退出

尽管多个线程可并行执行,但若主机仅一颗CPU,线程优势几乎发挥不出来,若是多颗CPU,多个线程在多个CPU上同时执行,而且程序在编写时采用并行编程技术(在一个进程内部或一个线程内部可有多个执行流)可实现更好的分配系统资源,如10CPU处理1W个连接,每个CPU只需1000个切换

在线程模型下,系统调用结束(内核准备好数据),内核如何通知线程它要的数据已准备好了?仍旧使用select模型(在linux中线程也是进程,只不过是轻量级进程,一个进程管理多个线程,IO是由进程管理,只不过减少了进程的数量,相应IO文件描述符的数量也少了,可响应更多的用户请求,这背后IO机制并没变,只不过多个线程可共享资源,至少提高了内存使用效率,所以在C10K上仍有问题,这时就要用到一个线程响应多个请求

线程总结:

每个线程响应一个请求,线程仍然要切换,但切换是轻量级的;

同一个进程的线程可以共享进程的诸多资源(如打开的文件);

对内存的需求较之进程略有下降;

快速切换时会带来线程抖动

 

多进程多线程模型:

N个进程,每个进程中有100个线程,使得资源争用不是很严重,例如有8CPU,单独拿出一颗用来运行内核和其它进程,另7颗独立空闲出来,隔离出来仅让web服务使用,web服务启动时只启动7个进程,每一个进程绑定一个CPU(一颗CPU对应一个进程,这将没有进程切换,但进程内部的线程切换是不可避免的),这样速度就会快很多,系统提供这种功能但要手动完成进程与CPU绑定

 

一个线程响应多个请求(多线程<-->N个请求):

一个线程要处理多个IO,若一个用户请求了主页,建立连接,系统调用结束后返回数据,如何唤醒当前建立的连接,怎么通知线程?event-driven IO(事件驱动IO

一旦有IO,线程是不能阻塞的(若阻塞,这个线程就无法完成其它用户请求,这与我们的初衷相悖(一个线程响应多个请求)),例如去饭店吃饭(顾客是用户请求,收银员是线程或者进程,后厨是内核):

阻塞(10个顾客,一个收银员,第一个顾客报饭给收银员-->收银员告诉后厨-->后厨做好后-->收银员-->顾客,这样第一顾客接待完后,第二个顾客才能建立连接;为提高效率,增加收银员的数量,同时三个收银员,多队列阻塞,同样第一个顾客拿到饭,第二个顾客才能连接,才能向收银员报饭)

非阻塞(第一个顾客向收银员报上饭后在一旁等着,营业员告知后厨,之后就与后厨暂时失去联系,继续接待下个顾客,第二个顾客也在一旁等着,后厨做好饭后在大屏幕上显示用这种方式通知(第一种通知方式,每做好一个将做好的和没做好的全部显示;第二种通知方式,只通知做好的,这样内核耗费资源就少了),若通知了一遍某个顾客没看到,要么就不管了,要么再通知直到顾客拿到饭,这种属通知机制,就不需用户始终盯着收银员)

同步(第一个顾客向收银员报上饭,收银员立即告知后厨,来自前端的直接交给后端)

异步(每一个顾客向收银员报上饭,收银员汇总后一并告知后厨)

多个顾客同时请求,又都能让顾客知道请求的内容是否就绪这称作IO复用机制

以上举例不精确,但有助于理解

 

AIOasynchronous IO,异步IO

一个thread维持多个用户,在某一时刻用户的请求尚未满足,这个用户要处于等待状态,当为这个用户请求的数据准备完成之后,与前端用户的连接再次重新建立起来,并通知用户可以取数据,在网络上完成多路IO的唤醒,在非阻塞模型下通过内核中的多路IO复用机制来完成(每一个请求在本机就是一堆文件描述符,一堆套接字的文件,当为某一个用户请求的数据准备好了,必须要将这个文件描述符激活,并让client过来取数据)

 

4、看清以下这五种模型:

技术分享

IO动作如何执行?(进程无法直接操作IO设备,必须通过系统调用请求kernel来协助完成IO动作;内核会为每个IO设备维护一个buffer(内核的内存空间);对于输入而言,等待wait数据输入至buffer需要时间,而从buffer复制copy数据到进程也需要时间;根据等待模式的不同,IO动作可分为五种模式)

五种模式:

blocking IOblocked all the way(阻塞IOsynchronous-blocking

nonblocking IOif no datain buffer,immediate returns ewouldblock(非阻塞IOsynchronous-nonblocking

IO multiplexingselect|poll):blocked separately in wait and copyIO复用,asynchronous-blocking

signal driven IOSIGIOevent drivenIO):nonblocked in wait but blocked in copysignaled when IO canbe initiated)(只要一个进程处理多个IO时(处理多个文件描述符)必须得复用,甚至一个进程响应一个请求时也要复用(与用户交互数据(接受键盘输入的数据,交互式IO),处理网络连接(网络IO))

asynchronous IOAIOasynchronous-nonblocking):nonblocked all the waysignaled when IO is complete)(异步IO,不导致请求进程阻塞;synchronousIO,引起请求进程阻塞,直到IO完成)

注:只要是synchronous,都通过read/write系统调用来完成IO

技术分享

如下图:synchronous-blocking,整个过程都是阻塞状态,是闲等

processthread向内核发起系统调用,内核将数据从磁盘复制到kernel’s buffer processthread一直监控着内核缓冲区

数据从kernel’s buffer复制到进程地址空间,这段时间内不能连入其它请求

技术分享

如下图:synchronous-nonblocking,是忙等(不断询问),此模型性能差,几乎不用

发起系统调用后是非阻塞状态,可以连入其它请求,但同时还要不断检查之前的IO返回状态,若再次连入的请求是打开其它文件,又要重新发起新的系统调用,进程又要发起新的IO请求,这同时就要不停地检查两个IO状态,第一个IO完成了,阻塞,复制数据到进程地址空间,再检查第二个IO,这个进程会很忙,若是很多个,性能会很差,所以这种模型几乎不用

技术分享

如下图:asynchronous-blockingIO multiplexing),分两段,两段都阻塞,第二段是由进程主导数据复制(进程再次发起系统调用)

可实现多个进程响应多个请求,如httpd,主进程接收用户请求,接进来分配一个子进程来处理这个请求,一个子进程只负责完成这一个IO,完成多个子进程响应多个请求,也可以一个进程响应多个请求,但性能会很差

select()函数,进程要知道内核准备的数据是否到kernel’sbuffer中,就要监控着缓冲区,在缓冲区中会打开一个文件描述符,进程需要read()这个缓冲区,返回一个状态,进程就知道它请求的数据是否准备好,若只考虑一个进程打开了一个文件(在真实环境中,一个用户请求了一个页面,这个页面由很多资源组成,每个资源就得一个进程来完成),每个子进程响应一个用户请求,每个子进程都打开一个文件,子进程是属于主进程的,主进程自身对select而言最多只支持1024个请求,也就是最多1024个子进程响应了(同时1024个并发连接)

要想实现multiplexing就要用selectpoll这种机制(pollselect的工作机制一样,但无文件数限制,由于工作机制一样,即使没有设置上限,性能与select差不多,select之所以有限制,说明它知道超过这个数性能会很差)

技术分享

如下图:event-driven,解决了IO multiplexingasynchronous-blocking)前半段的阻塞和synchronous-nonblocking前半段一直询问。刚开始在进程发起请求时,留有回调机制(可理解为给kernel留了联系方式),内核在数据准备完成后向进程通知(水平触发和边缘触发;水平触发,每隔一段时间通知一次,多次通知直到拿走数据;边缘触发,仅通知一次,不管你拿没拿到),边缘触发性能要好

一个线程响应多个请求,一个线程内部维护的有多个连接

一个线程接受用户请求,向内核发起系统调用,给内核留了联系方式,再接受第二个用户请求,发起系统调用,再留一个联系方式,依次接受第三个请求……,当内核准备好第一个的数据,使用回调机制告诉第一个联系方式数据准备完成,然后阻塞(第二段阻塞)等数据从内核空间复制到进程空间响应给用户

若内核将自己的内核空间共享给用户空间,连复制都不用了,这将更快,这是内存共享,注意不是内存映射(mmapmemory map指的是数据从磁盘到内核的内存空间,要流动过去,这要复制,内存映射是复制就不用了,直接将要打开的文件在磁盘中的数据结构映射到内存,在两者之间建立起关联关系,将磁盘中的文件与内存的一块区域建立关联关系,当访问时直接取数据即可)

event-driven模型使用selectpoll无法完成,它使用的是epolllinux上叫epoll),在solaris上叫/dev/poll,在FreeBSD上叫kqueue

技术分享

如下图:asynchronous-nonblocking,在数据复制到进程的内存空间后才给进程通知(给进程信号),而event-driven是在内核中通知的

nginx在磁盘IO上支持此模型(网络IO不是)

技术分享

技术分享

 

5nginx特性:

file AIO(文件或磁盘IO,基于异步IO),direct IO(对于正常的系统调用read/write流程是,read(数据从硬盘-->内核空间-->用户空间),write(数据从用户空间-->复制到内核空间的页缓存write直接返回-->OS会在恰当的时间写入磁盘,这是buffered IO),对于自缓存的应用程序来说,buffered IO不是好的选择,因此出现direct IO,不经内核空间直接写磁盘,必须阻塞,所以通常direct IOAIO会一同出现);

asynchronous(异步通信);

event-driven edge trigger(事件驱动边缘触发);

作为web-server处理静态文件,要依赖其它模块才能提供动态功能;索引文件(主页面)及自动索引;打开文件描述符缓存(nginx可以缓存源文件和文件描述符(路径));

使用缓存加速反向代理;简单负载均衡及容错(实现后端real serverhealth_check,一旦发现后端server故障直接剔除,类似keepalived,对于容错要安装第三方模块);

注:淘宝在nginx代码的基础上对其作了诸多扩充,直接将很多第三方模块(插件)整合进了nginx中,并对其作出大量改进,在nginx上作了第二次发行版Tengine,淘宝也将不断改进的代码反馈给nginx官方,有些代码被nginx吸纳并融入到后续的发行版中

远程fastcgiphpnginx不支持模块方式使用php,只有fastcgi这种方式);uwsgi(用来支持pythonweb框架,比fastcgi高效,不是php);scgimemcached服务的缓存加速支持(nginx已原生态支持memcachednginx自身作为代理它也可以提供缓存,只不过它默认是缓存在磁盘上的,但它能在内存中缓存打开的文件描述符);

注:缓存方面:varnishsquidnginxhttpdvarnish(是专业的缓存server,它在设计时考虑的是现代的计算机体系结构,缓存时可优先选择内存缓存,可在内存中实现对数据结构的创建、回收、销毁等,它引入很好的算法,在专业级别讲,varnish有更好的特性);squid(由于比较早期,它在开发时考虑的是原先计算机结构);varnishsquid的关系相当于nginxhttpd的关系;nginxdisk);httpddiskmemory

模块化架构设计;过滤器包括gzip压缩、ranges支持、chunked响应、XSLTSSI及图像缩放

注:SSIserver side include,服务器端包含,可实现将一个页面,某些内容作成动态,某些内容作成静态);图像缩放(节约网络带宽、提高用户体验)

支持SSLTLS SNI

基于主机名及IP的虚拟主机;

keepalivepipelined连接支持;

重新加载配置及在线升级时,不需要中断正在处理的请求(架构设计先进性的体现,热部署、平滑升级);

自定义访问日志格式,带缓存的日志写操作,快速日志轮转(若用户访问的记录马上写到磁盘中,会影响系统性能,这个功能使日志先在内存中缓存,过段时间再flush到磁盘上);

3XX-5XX错误代码重定向;

重写rewrite模块,使用正则表达式改变URI(尤其作为reverse proxy serverrewrite是个重要的功能);

根据client地址执行不同的功能(例如根据client的浏览器类型响应不同的页面内容,若用户使用的是手机,则返回wap页面,可节省流量等);

基于客户端IP地址和HTTP基本认证机制的访问控制;

支持验证HTTP referer(防盗链机制,ngx_http_referer_module允许拦截referer请求头中含有非法值的请求,referer指通过哪些链接进的网站(用户访问网站,要么在浏览器上输入,要么通过链接进入),正是因为referer的存在,很多网站可盗链我们网站,例如:有人在我们网站上传了一堆图片,在他的网站通过链接指向我们的服务器,这样我们就给他提供页面,消耗我们的流量,过段时间若图片过多我们的网站就有可能打不开了)

支持putdeletemkcolcopymove等方法;

支持flv流和mp4流(边下载边播放);

速度限制(限制同一client连接的带宽);

来自同一地址的同时连接数和请求数限制;

支持的IO框架机制,epolllinux),/dev/pollsolaris),kqueueFreeBSD),编程时基于这个框架就支持asynchronousevent-driven,另还有event portsselect/poll,这两种最不可取,当前三个不支持时再使用这两个;

支持sendfilesendfile64sendfileV(尽可能避免数据拷贝操作,用户请求进来,请求的是静态页面,页面内容在磁盘分区中某个FS上,内核处理通过80port到某个worker进程上,通过建立连接,请求分析,发现用户请求的是静态页面,系统调用,内核为其准备缓冲,内核将数据加载至缓冲区,将数据再复制到进程地址空间,worker进程再将数据封装成一个响应报文(http首部封装实际是在内核中完成的),将报文再传至内核,内核封装tcp首部、ip首部,再响应给用户,可见数据是从硬盘-->内核空间-->用户空间-->内核空间,若封装时只在内核中完成,不用到用户空间,封装完后只告诉worker已替你响应过去,这样就避免了两次复制(内核空间-->用户空间,用户空间-->内核空间),内核任何时候与进程交互都是复制,除非内存共享,当并发连接很多时sendfile功能若关闭的话将严重影响系统性能,由此sendfile实现数据从硬盘到内核空间直接响应给clientsendfile只支持小文件,sendfile64支持大文件);

支持accept_filters(连接过滤器,只接受有限的连接),tcp_defer_accept

10K个非活跃的HTTP keepalive连接仅占用2.5M内存(事件驱动机制,只扫描活动连接,对于非活动连接不作管理,nginx只需很少内存就能为一个连接维持一个文件描述符);

 

 

6nginx的基本工作框架(一个主进程和多个工作进程,工作进程以非特权用户运行):

master(主进程,监控worker进程(或叫worker线程)启动是否够数目及运行状况是否正常等,以管理员身份启动(web服务默认80port1023以下端口只有管理员才能使用))

workerworker进程真正负责响应用户请求,是master的子进程,由master负责启动,以普通用户身份运行(系统安全性得到提升))

cache loader(与缓存相关的进程)

nginx高度模块化(masterworker进程处理web应用非常简单,像额外的其它功能,例如sslflvgzipfastcgi等都不是由nginx自己提供,而是由额外的模块提供,在nginx内部会调用这些模块,用到哪个装载哪个,就连它自己的基本功能也是模块化的,如接入的请求是getput、请求哪些内容等,worker不负责,转交给模块,这些模块以流水线的方式工作,如第一个模块分析头部、第二个模块取得数据、第三个创建响应等等,每一个请求所请求的内容会不一样(如有的是静态内容,要求压缩再响应;有的是动态内容,要调用fastcgi模块),所以响应时所串连的模块也会不一样,每个请求接入,worker一分析,要用到几个模块,这几个模块就组合成流水线,各就各位,随时准备响应)

master负责装载主配置文件,若改动了配置文件,由master分析有无syntax error,就算重新装载有语法错误也不会影响worker进程,装载成功后,它也不会让启动的worker使用这个新装载的配置文件,让这些已建立的连接仍然使用老旧配置,当某一worker上的连接都退出了,把这个worker挂掉,再重新启动一新worker,新worker响应新请求,新worker就用了新的配置,所以之前的连接与新连接是没影响的,varnish的处理机制与nginx在设计哲学上是相通的

 

master主进程的工作内容:读取并验证配置信息(核心功能);启动、中止及维护worker进程的个数(核心功能);创建、绑定并关闭套接字;无须中止服务而重新配置工作特性;控制非中断式程序升级,启用新的二进制程序并在需要时回滚至老版本(热部署、平滑升级);重新打开日志文件,实现日志滚动;编译嵌入式perl脚本

 

worker进程主要完成的工作:接收、传入并处理来自客户端的连接;提供反向代理及过滤功能;nginx任何能完成的其它任务

 

cache loader进程的主要任务:检查缓存存储中的缓存对象;使用缓存元数据建立的内存数据库

 

cache manager进程完成的任务:缓存的失效及过期检验

 

 

二、操作:

环境:

[root@node1 ~]# uname -a

Linux node1.magedu.com2.6.32-358.el6.x86_64 #1 SMP Tue Jan 29 11:47:41 EST 2013 x86_64 x86_64 x86_64GNU/Linux

准备软件包:

nginx-1.8.0.tar.gz

mysql-5.6.28-linux-glibc2.5-x86_64.tar.gz

libmcrypt-2.5.8-9.el6.x86_64.rpm

libmcrypt-devel-2.5.8-9.el6.x86_64.rpm

mcrypt-2.6.8-10.el6.x86_64.rpm

mhash-0.9.9.9-3.el6.x86_64.rpm

mhash-devel-0.9.9.9-3.el6.x86_64.rpm

php-5.4.6.tar.bz2

xcache-3.0.4.tar.gz

准备好yum

 

1、安装nginx

[root@node1 ~]# yum -y groupinstall “DesktopPlatform” “Desktop Platform Development” "Server Platform Development" “Development tools” “Compatibility libraries”

[root@node1 ~]# yum -y install pcre-develperl扩展的正则表达式)

[root@node1 ~]# groupadd -r -g 108 nginx

[root@node1 ~]# useradd -r -g 108 -u 108nginx

[root@node1 ~]# tar xf nginx-1.8.0.tar.gz

[root@node1 ~]# cd nginx-1.8.0

[root@node1 nginx-1.8.0]# ./configure   --prefix=/usr   --sbin-path=/usr/sbin/nginx   --conf-path=/etc/nginx/nginx.conf  --error-log-path=/var/log/nginx/error.log  --http-log-path=/var/log/nginx/access.log   --pid-path=/var/run/nginx/nginx.pid    --lock-path=/var/lock/nginx.lock   --user=nginx   --group=nginx   --with-http_ssl_module   --with-http_flv_module   --with-http_stub_status_module   --with-http_gzip_static_module   --http-client-body-temp-path=/var/tmp/nginx/client/   --http-proxy-temp-path=/var/tmp/nginx/proxy/  --http-fastcgi-temp-path=/var/tmp/nginx/fcgi/  --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi   --http-scgi-temp-path=/var/tmp/nginx/scgi   --with-pcre

[root@node1 nginx-1.8.0]# make && make install

[root@node1 nginx-1.8.0]# cd

[root@node1 ~]# vim /etc/init.d/nginx(为nginx提供启动脚本,内容见文末附)

[root@node1 ~]# chmod +x /etc/init.d/nginx

[root@node1 ~]# chkconfig --add nginx

[root@node1 ~]# chkconfig nginx on

[root@node1 ~]# chkconfig --list nginx

nginx              0:off 1:off 2:on 3:on 4:on 5:on 6:off

[root@node1 ~]# service nginx start

正在启动 nginx                                           [确定]

 

2、安装mysql

[root@node1 ~]# fdisk -l

Disk /dev/sdb: 10.7 GB, 10737418240 bytes

[root@node1 ~]# pvcreate /dev/sdb

 Physical volume "/dev/sdb" successfully created

[root@node1 ~]# vgcreate myvg /dev/sdb

 Volume group "myvg" successfully created

[root@node1 ~]# lvcreate -L 8G -n mylv/dev/myvg

 Logical volume "mylv" created

[root@node1 ~]# lvs

……

 mylv    myvg     -wi-ao--- 8.00g  

[root@node1 ~]# mkfs.ext4 /dev/myvg/mylv

[root@node1 ~]# mkdir /mydata

[root@node1 ~]# mount -t ext4 /dev/myvg/mylv /mydata

[root@node1 ~]# ls /mydata

lost+found

[root@node1 ~]# vim /etc/fstab

/dev/myvg/mylv  /mydata         ext4   defaults    0 0

[root@node1 ~]# umount /mydata

[root@node1 ~]# mount -a

[root@node1 ~]# mount(查看是否有以下此行)

/dev/mapper/myvg-mylv on /mydata type ext4(rw)

 

[root@node1 ~]# useradd -r mysql

[root@node1 ~]# id mysql

uid=498(mysql) gid=498(mysql) =498(mysql)

[root@node1 ~]# mkdir /mydata/data

[root@node1 ~]# chown -R mysql.mysql /mydata/data/

[root@node1 ~]# ll -d /mydata/data

drwxr-xr-x 2 mysql mysql 4096 8  31 18:53 /mydata/data

[root@node1 ~]# tar xvf mysql-5.6.28-linux-glibc2.5-x86_64.tar.gz -C /usr/local/

[root@node1 ~]# cd /usr/local/

[root@node1 local]# ln -sv mysql-5.6.28-linux-glibc2.5-x86_64/ mysql

"mysql" ->"mysql-5.6.28-linux-glibc2.5-x86_64/"

[root@node1 local]# cd mysql

[root@node1 mysql]# chown -R root.mysql ./

[root@node1 mysql]#scripts/mysql_install_db --user=mysql --datadir=/mydata/data

[root@node1 mysql]# vim my.cnf

[mysqld]

datadir = /mydata/data

innodb_file_per_table = 1

socket = /tmp/mysql.sock

log-bin = mysql-bin

[root@node1 mysql]# vim /etc/profile.d/mysql.sh

export PATH=$PATH:/usr/local/mysql/bin

[root@node1 mysql]# . !$

. /etc/profile.d/mysql.sh

[root@node1 mysql]# vim /etc/ld.so.conf.d/mysql.conf

/usr/local/mysql/lib

[root@node1 mysql]# ldconfig -v

[root@node1 mysql]# ln -sv /usr/local/mysql/include/ /usr/include/mysql

[root@node1 mysql]# cp support-files/mysql.server /etc/init.d/mysqld

[root@node1 mysql]# chkconfig --add mysqld

[root@node1 mysql]# chkconfig --list mysqld

mysqld            0:关闭      1:关闭      2:启用      3:启用      4:启用      5:启用      6:关闭

[root@node1 mysql]# service mysqld start

Starting MySQL.......                                      [确定]

 

3、安装php

[root@node1 ~]# rpm -Uvh libmcrypt-2.5.8-9.el6.x86_64.rpm

[root@node1 ~]# rpm -Uvh libmcrypt-devel-2.5.8-9.el6.x86_64.rpm

[root@node1 ~]# rpm -Uvh mhash-0.9.9.9-3.el6.x86_64.rpm

[root@node1 ~]# rpm -Uvh mhash-devel-0.9.9.9-3.el6.x86_64.rpm

[root@node1 ~]# rpm -Uvh mcrypt-2.6.8-10.el6.x86_64.rpm

[root@node1 ~]# yum -y install net-snmpnet-snmp-devel libcurl-devel bzip2-devel

注:不安装这几个rpm包,会出现错误,例如(类似如下错误,都要安装其对应的devel包):

configure: error: Could not findnet-snmp-config binary.

configure: error: Please reinstall theBZip2 distribution

[root@node1 ~]# tar xvf php-5.4.6.tar.bz2

[root@node1 ~]# cd php-5.4.6

[root@node1 ~]# ./configure --prefix=/usr/local/php --with-mysql=/usr/local/mysql --with-openssl --enable-fpm  --enable-sockets  --enable-sysvshm  --with-mysqli=/usr/local/mysql/bin/mysql_config  --enable-mbstring--with-freetype-dir  --with-jpeg-dir  --with-png-dir  --with-zlib-dir --with-libxml-dir=/usr  --enable-xml  --with-mhash  --with-mcrypt  --with-config-file-path=/etc  --with-config-file-scan-dir=/etc/php.d --with-bz2  --with-curl  --with-snmp

[root@node1 ~]# make && make install

 

[root@node1 php-5.4.6]# cp php.ini-production /etc/php.ini

[root@node1 php-5.4.6]# cp sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm

[root@node1 php-5.4.6]# chmod +x /etc/init.d/php-fpm

[root@node1 php-5.4.6]# chkconfig --add php-fpm

[root@node1 php-5.4.6]# chkconfig php-fpm on

[root@node1 php-5.4.6]# chkconfig --list php-fpm

php-fpm           0:off 1:off 2:on 3:on 4:on 5:on 6:off

[root@node1 php-5.4.6]# cd

[root@node1 ~]# cp /usr/local/php/etc/php-fpm.conf.default /usr/local/php/etc/php-fpm.conf

[root@node1 ~]# vim /usr/local/php/etc/php-fpm.conf(根据主机性能调整)

[global]

pid = /usr/local/php/var/run/php-fpm.pid

[www]

listen = 127.0.0.1:9000

pm.max_children = 150the maximum number of children that can be alive at the same time

pm.start_servers = 8the number of children created on startup

pm.min_spare_servers = 5the minimum number of children in ‘idle‘ state (waiting to process). If the number of‘idle‘ processes is less than this number then some children will be created

pm.max_spare_servers = 10the maximum number of children in ‘idle‘ state (waiting to process). If the number of‘idle‘ processes is greater than this number then some children will be killed

[root@node1 ~]# service php-fpm start

Starting php-fpm  done

[root@node1 ~]# netstat -tnlp | grep :9000

tcp       0      0 127.0.0.1:9000              0.0.0.0:*                   LISTEN      5983/php-fpm   

[root@node1 ~]# ps aux | grep php1masterprocess8children process

 

4、整合nginxphp

[root@node1 ~]# cp /etc/nginx/nginx.conf.default /etc/nginx/nginx.conf

[root@node1 ~]# vim /etc/nginx/nginx.conf

  ……

http {

server {

    ……

       location / {

           root   html;

           index  index.php index.htmlindex.htm;

       }  

       ……

       location ~ \.php$ {

           root  html;

           fastcgi_pass  127.0.0.1:9000;

           fastcgi_index  index.php;

           fastcgi_param  SCRIPT_FILENAME/script$fastcgi_script_name

           include  fastcgi_params;

       }

       ……

}

[root@node1 ~]# vim /etc/nginx/fastcgi_params

#-----------content start-----------------

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;

fastcgi_param  SERVER_SOFTWARE    nginx;

fastcgi_param  QUERY_STRING       $query_string;

fastcgi_param  REQUEST_METHOD     $request_method;

fastcgi_param  CONTENT_TYPE       $content_type;

fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_FILENAME   $document_root$fastcgi_script_name;fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;

fastcgi_param  REQUEST_URI        $request_uri;

fastcgi_param  DOCUMENT_URI       $document_uri;

fastcgi_param  DOCUMENT_ROOT      $document_root;

fastcgi_param  SERVER_PROTOCOL    $server_protocol;

fastcgi_param  REMOTE_ADDR        $remote_addr;

fastcgi_param  REMOTE_PORT        $remote_port;

fastcgi_param  SERVER_ADDR        $server_addr;

fastcgi_param  SERVER_PORT        $server_port;

fastcgi_param  SERVER_NAME        $server_name;

#--------------contentend--------------------

[root@node1 ~]# vim /usr/html/index.php

<?php

phpinfo();

?>

[root@node1 ~]# service nginx reload

nginx: the configuration file/etc/nginx/nginx.conf syntax is ok

nginx: [emerg] mkdir()"/var/tmp/nginx/client/" failed (2: No such file or directory)

nginx: configuration file/etc/nginx/nginx.conf test failed

[root@node1 ~]# mkdir /var/tmp/nginx/client/ -pv

mkdir: created directory `/var/tmp/nginx‘

mkdir: created directory`/var/tmp/nginx/client/‘

[root@node1 ~]# service nginx reload

nginx: the configuration file/etc/nginx/nginx.conf syntax is ok

nginx: configuration file/etc/nginx/nginx.conf test is successful

重新载入 nginx                                           [确定]

技术分享

 

5、安装Xcache

[root@node1 ~]# tar xvf xcache-3.0.4.tar.gz

[root@node1 ~]# cd xcache-3.0.4

[root@node1 xcache-3.0.4]#/usr/local/php/bin/phpize

Configuring for:

PHP Api Version:         20100412

Zend Module Api No:      20100525

Zend Extension Api No:   220100525

[root@node1 xcache-3.0.4]# ./configure --enable-xcache --with-php-config=/usr/local/php/bin/php-config

[root@node1 xcache-3.0.4]# make && make install

 

[root@node1 xcache-3.0.4]# mkdir /etc/php.d/

[root@node1 xcache-3.0.4]# cp xcache.ini/etc/php.d

[root@node1 xcache-3.0.4]# vim /etc/php.d/xcache.ini

[xcache-common]

extension ="/usr/local/php/lib/php/extensions/no-debug-non-zts-20100525/xcache.so"

[root@node1 ~]# service php-fpm restart

Gracefully shutting down php-fpm . done

Starting php-fpm  done

技术分享

 

 

三、扩展:架构方面

nginx支持FSAIO,支持mmap,支持event-driven(比httpd支持的连接数多的多)

一主机(4G内存,2CPU),若使用nginx,支持3-5W个并发连接一点问题都没有;而要使用httpd,在prefork模型下,一个进程响应一个请求,最多同时并发1024个,再多就拒绝响应了,若在worker模型下(虽一个线程响应一个请求,一个进程会生成并管理多个线程,这只不过进程切换数少了些),并发连接数并没提升(因为select机制的限制)

nginx程序本身才1M,但功能单一,众多httpd的功能nginx不支持;而httpd有众多的模块,整体与nginx比,它是重量级

很少将nginx拿来用作web-server,因为它的功能不够丰富,stable上讲,一个线程响应多个请求固然很好,但若一个线程崩溃了,N个请求都玩完,像httpd一个进程响应一个请求,一个进程崩溃不影响其它请求,httpdprefork模型要稳定的多;所以nginx通常拿来做前端的reverse proxy反向代理(如mysql-proxy,它本身不是mysql-server,但通过它能连后后端的mysql-server,而nginxwebproxy,解析http协议),而httpd用来做后端的web-server

技术分享

web object分静态和动态(静态,html文档、图片、CSS样式表等;动态,php脚本)

nginxreverse proxy(可精确理解web协议、各种用户操作、URLrewrite、资源重定向等);LVS并不能理解哪些是静态内容哪些是动态内容,在高级功能设定上不具备

2CPU4G内存的主机(nginxweb-server,若请求的是5-10K的图片,每秒处理5000-10000个,另还取决于带宽及磁盘IO;若响应动态内容大约1000个,要占据CPU时间生成html文档才返回)

varnish(用来缓存动态内容,如64G内存500G固态硬盘,一般要命中率要达到50%

memcached(缓存mysql-server的内容,它是个旁路缓存,php程序要用到数据先找memcachedmemcached中没有得自己找mysql-server,返回时先到memcached中,再返回给php程序)

可在haproxy前端加MQrabbitmqzeromq,可理解为连接池,所有连接进来并不是马上提供服务,而是先缓存下来;在异步管理中,MQ很常用)

地理位置法则,缓存策略(CDNcontent distribute network),将所有静态内容(包括动态内容的缓存)放至全国各地机房中的varnish缓存集群中,做智能DNS解析用户请求,如华北区的用户直接解析到离他最近的缓存服务器集群上,命中率要90%(缓存放在用户的家门口,访问时直接返回),做内容路由(如华北区用户访问最近的缓存中没有,到其它区域的缓存中找,若都没,再找原始服务器)

淘宝在抢购时tpsmysql的每秒事务量transaction per second5W多),一般500个并发连接都扛不住

NOSQL(工作在内存,支持事务,如redismongodb),若要实时写操作,而且量很大,就要用到NOSQL,内存数据库,需要持久存储(将结构化数据放至mysql中,非结构化或半结构化数据放在FS上)并用来后期分析,以后在FS上对数据进行分析就不像mysql那样,要检索有效数据集来分析,而要对文件全量提取进行分析,要用并行处理平台才能完成(如hadoop

注:NOSQL解决抢购时随时更新商品剩余量,在前端的内存服务器(在内存中执行事务,小事务,每次抢购完就结束,快速执行,快速反馈,对于商品的更新只要事务一完成立即更新)

redis(作为计数器,快速法则响应,如微博中有多少人转载、评论等要计数,在内存工作,将数据同步到硬盘,并且实现将数据转存至mysql中(持久化存储法则);而memcached只提供缓存,不能保存数据)

mongodb(对于写数据多时使用)

日志服务器(可将日志放在mysql-server中,mysql放在更高IO能力的硬盘上,再导入到分布式FS上;或将日志放在10server上,在每个server上布署个日志小程序(facebook有个日志收集器,让每个server管理自己的日志),每天将日志读一份放至分布式FS上,在分布式FS上通过并行处理程序完成日志分析(如完成前一天抢购中哪个区的用户,哪个店铺的成交量最多等,每天的日志可能上G多达则Thadoop对这些数据作批处理,hadoop的分析是异步的,而且有两段执行过程(各自分开执行))

若将一个机房的主机做成高可用集群(云平台),在云平台上开一堆的虚拟机,各种虚拟机完成各种任务(不同的服务在不同的虚拟机上),哪一个虚机故障直接kill掉(进程而已),再启动一个新的,或者实时迁移到其它虚拟机上;对于共享存储(监控存储解决方案,任何一个虚拟机开了,自动在存储上找个空间,创建虚拟磁盘,实现虚拟机进程的启动);hadoop不能放在虚拟机上,hadoop需要大师的磁盘IO,虚拟机的IO能力是很差的,所以要用云+hadoop实现;另可将mysql放在云里,云有三种模型(iaaspaassaas,将mysql做成saas向外提供软件服务;这样mysqlhadoopweb、云各自都模块化

架构师:

网络

自动化运维编程(shellpython

各服务的性能、特性、适用场景、优缺点等要做到通盘掌握

DBA能力

服务运维能力

运维经验

 

 

 

 

以上是学习《马哥运维课程》做的笔记。

 

 


本文出自 “Linux运维重难点学习笔记” 博客,谢绝转载!

Linux运维 第三阶段 (十五)理解LNMP

原文:http://jowin.blog.51cto.com/10090021/1729562

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!