首页 > 代码库 > PHP和Fastcgi/php-fpm的工作原理-理论部分 不涉及实验

PHP和Fastcgi/php-fpm的工作原理-理论部分 不涉及实验

标题:PHP概述
笔者:郑彦生
时间:2014-05-16
---------------

---|谢谢马哥教育|---

祝马哥的事业一帆风顺。

MIME,HTTP,HTML

MIME:N能够让http传送非文本信息;如mp3
http:只能解析html的文档,对于多媒体mp3等,浏览器需要安装插件 或者 web浏览器能够调与之匹配的web程序进行解码
注意:浏览器本身不能播放音乐,要么有自带的插件,要么主机上其它的程序可以播放音乐,而浏览器可以调用这个程序来执行播放音乐
服务器发过来的一般都是静态的文本

静态:放在哪都能执行,没有后台数据库
 html,mp3,jpeg,png,flv

动态网站:需要服务器来解释的,有后台数据库
 动态网站一定是能够根据应用程序请求,做出对应响应,甚至根据不同用户返回的内容是不一样的,根据客户端的请求返回不同结果的

 客户端动态
  不建议客户端动态
 服务器端动态
  ......

Applet
java在2000年很火的!运行动态网站

JVM俗称java虚拟机,类似于Windows下的vmware的虚拟机,只不过vmware是虚拟硬件来运行程序的,而JVM只是运行java的一个沙箱或者说是盒子。能够运行java的程序
因为java在运行的时候需要装载java的类和库、java程序的生命周期等;而JVM就是对java的一个虚拟化环境一次编译到处运行。
java的程序必须运行在JVM上,而java对环境依赖是被JVM隐藏了。
为什么java可以跨平台,就是因为java的官网提供了不同平台的JVM,java虚拟机。也就是意味着,如果java运行在windows上,那么就在windows上
安装一个windows的JVM,如果运行在linux上,就安装一个linux的jvm。从而是java可以运行在不同的平台上,变得很灵活,使jvm跟os平台兼容

因为java程序是运行在java虚拟机上的,就是客户端浏览器安装java的插件,即使运行恶意病毒程序,也最多是破坏java虚拟机,不会损坏底层的系统

底层不同:OS不同

Virtual Machine

 

能开发web程序的语言很多,只是有些程序更适合做开发web程序而已。
编程语言
 静态语言:编译型语言  --->是强类型的,只有先编译在运行
  c c++ java
  优点:效率高,性能好
  缺点:每一次改动都要重新编译,开发周期长,维护成本大。

 动态语言:解释性语言  --->是弱类型的,不需要编译,拿来就能使用,用一个解释器解释就可以。
  shell python perl...
  优点:便于维护,有众多模块,开发周期很短,维护成本小
  缺点:性能差

 facebook: 既性能好又开发成本小  内部转换器  动态语言转换成静态语言
  动态语言-->静态语言
  php--->Hiphop--> C++)_C++是一个静态程序,在服务器端可以直接执行,速度会是很快的。
  Hiphop是个内部转换器,它能够将php语言转换成C++语言

其实也应该用动态语言,去开发动态网站,但是也不是所有的动态语言都适合开发动态网站,比如bash
第一、耗资小,周期短、维护起来比较方便
第二、更接近用户体验

之所以互联网上到目的有那么多语言,是因为每一种语言都有它更适合的场景。没有任何一种语言都是赢家,没有一种语言更适合所有的环境。  
bash
bash不适合做动态网站,虽然也是动态语言,但是对于开发网站网站,周期会很长,互联网上也有使用bash开发动态网站的如博客。
一般bash是做自动化脚本,perl是要比bash都强大的自动化脚本。
java
java本身是一种完整意义上的语言,不适合做开发web站点,但是有人给java提供的特殊的类叫jsp类,使得java的运行周期完全可以在java容器中
完成了。使用jsp语言也可以快速的设计web站点了。都需要依赖额外的框架
php
有一种语言不需要额外的框架就可以设计web站点的。这种语言叫做php,因为它设计的时候就是为了做web站点开发的,但是还有asp,丑陋又不安全的东西



只有更适合的,没有最适合
bash:要实现系统自动化可以,但是如果用bash来开发web应用程序,周期会很长的。其实也有:比如俄罗斯方块,论坛
perl:模块
python:模块 框架
java:开发语言,类 jsp类  在web容器中快速完成:ssh
ruby:脚本语言 额外的框架:rails

开发:
基本算法
算法,数据结构
编译原理

学运维,首先要打开视野,使自已的动手能力足够的强。这是前期
到后期,我们应该更专注于系统原理,要么是了解编程,这样才能知道这个程序是怎样运行的

php于1994年诞生,出现php1.0版本
   于1997年,出现第二个版本php2.0  
   于同年发布第三个版本php3.0 奠定了坚实的基础

php is Hypertext perprocessor
超文本php预处理器

静态:编译器
动态:解释器

动态语言:
首先进行词法分析
其次进行语法分析
然后生成执行路径

CGI
 protocol:
  它能够让我们前端web服务器进程,根据对应程序的不同,调用对应的执行环境,来运行对应的程序文件,并且能够让运行程序文件的运行结果取回
  web进程的这么一种协议就是CGI

 web进程:web服务器进程根据对应程序的不同,调用对应的执行环境来运行那个对应的程序文件,并能将运行程序文件的显示结果取回web进程的的
      这种协议就叫做CGI协议。


web应用程序,webapp
 指在服务器端运行的web程序,这个程序在客户端访问页面的时候,这个页面不是直接返回给客户端的,而是服务器端先调用对应文件的执行环境,
 并将结果格式化成html文档,然后再返回给客户端的。



系统原理
程序原理

程序员和运维的区别
程序员是负责写程序的,运行时用这些程序的。

懂开发 会开发是两码事

现在众多的程序都是用python开发的
比如:
云计算框架:Openstack,也是使用python开发的
现在众多游戏程序python
服务器器自动化控制脚本:python
自动运维化框架:python


Zend Engine的出现将php的执行分成两部分,首先编译成二进制格式,然后执行二进制文件。1997年Zend Engine发布第一个版本1.0,诞生php4.0 
zend Engine的出现将php代码的处理分成了两个阶段,曾先是分析php代码,并将其转换为称作zend opcode的二进制格式(类似java字节码)
并将其存储于内存中;第二阶段使用zend engine来执行这些换换后的opcode;

opcode:操作码 
php是一种解释型语言 意味着php开发的程序要想执行 只需要php解释器解释就可以了 词法分析 语法分析 然后执行
这个过程是很慢的,那么如果要想让它快 应该将php的源代码首先转换成二进制格式 类似编译过程,php解释器编译的 然后再去执行
二进制程序
php source code ---->编译成二进制格式 -->执行二进制格式
以后我们访问这个php页面的时候,首先在服务器上编译,第一次访问慢,第二次访问的是偶直接指定到这个编译好的二进制格式,速度会快的多 
编译后结果叫做opcode,或者说是php的操作码,
虽然php编译的结果是二进制格式的,但是不能执行,只能说是类似于二进制格式,这种二进制格式只能在zend引擎当中运行。
也类似于java程序只能在jvm中运行。

 

PHP的Opcode
Opcode是一种php脚本编译后的中间语言,就像java的ByteCode字节码,或者.net的MSI。php执行php脚本代码一般会经过如下4个步骤
确切的来说,应该是php语言引擎Zend
1. Scanning(Lexing)---将php代码转换为语言片段(Tokens)  扫描 词法扫描
2. Parsing --将Tokens转换成简单而有意义的表达式            数值赋值于变量
3. Compilation --将表达式编译成Opcodes                     编译
4. Execution--顺次执行Opcodes,每次一条,从而实现php脚本的功能   执行  顺序执行php脚本

php编译结果opcode是放在进程中的地址空间上的或者说是内存上的。

opcode是放在内存中的
用户A和用户B
先后访问同一个页面1.php
假设
用户A向服务器发起一个1.php的请求,那么服务器会启动一个php进程来响应A用户的请求,首先由Zend Engine对1.php进行词法分析,语法分析,然后编译成
Opcode,并把结果放在进程的地址空间当中。
之后用户B也向服务器发起同一个页面1.php的请求,那么服务器会启动另外一个php进程来响应B用户的请求,这个时候Zend Engine也会按照流程进行
词法分析,语法分析,并编译成Opcode,缓存到此进程的内存的地址空间当中。
结论:就是进程之间无法进行Opcode共享

详细的结论
用户A和用户B发起的1.php请求的页面,服务器端不是使用同一个php进程来响应的
1.php需要先编译后执行 由Zend Engine负责编译  编译后结果Opcode放在响应进程内存地址空间当中,也就是都放在
响应用户进程的地址空间中。那么由Zend Engine编译后的Opcode无法进行进程间共享,每次即使请求同一个页面,还需要重新编译
每个进行都需要重新编译 然后再执行,因此我们的php程序在一定程度上执行效率还是很慢的
但是在同一进程内部是很快的,同一个用户访问同一个文件被访问多次2次 3次 10次...是很快的,因为可以不需要重新编译,直接由Zend Engine执行
缺点:其它进程访问同一个文件不会被加速的

 

php的加速器或者Opcode缓存器
那么有没有这么一种机制,能够编译一次,所有的进程可以共享Opcode,不需要重新编译。
答案是有的 这就是php的加速器
php的加速器的原理:提供一个缓存空间,将任意进程编译好的Opcode 放到到内存空间当中,任何进程都可以到这个缓存中读取编译好的Opcode。可以直接
由Zend Engine直接执行。速度会快很多的。

任何一个进程编译好的Opcode 不在放在自已的地址空间中,而是放在另外一个程序提供的的缓存空间当中 而这个缓存空间 可以 在多个php进程之间是共享的



这个提供缓存空间的程序就叫做php的加速器 Opcode缓存器
APC  目前APC版本不适合php5.4
eAccelerator 不在支持 目前版本不在更新
Xcache 快速而稳定的php Opcode 缓存
Zend Optimizer和Zend Guard Loader Zend优化器  免费闭源的


php是一种动态语言,可以用它来做web站点开发,但是php程序必须在Zend Engine进行编译,然后才能执行。

MVC:模块视图控制器

CGI
 Common Gateway Interface:通用网关接口,能够让web服务器跟后端的应用程序服务器结合 调用后端应用程序的接口 执行应用程序的接口

Apache:web服务器 提供静态html文档 图片 mp3 一种服务器
如果要想执行php程序,必须要有php解释器,这个时候apache怎样才能和php结合,建立关系


现在做一个假设
如果web服务器apache正在运行,这个时候用户发起一个请求.php的页面,apache自已执行不了,于是就是找php的解释器,来解释php脚本并把解释的结果
返回给apache的web服务。


简单点说就是CGI就是一个接口,这个接口能让我们的web程序,对php无法解释的脚本,通过CGI机制,转发后后端的web站点让php的解释器来解释,并返回
给web服务器。


------------------------------------------------------
apache+php的三种模式 
 CGI
 Module
 fastcgi/fpm  ---nginx+fastcgi/fpm

web服务器到底如何跟php交互
有三种方式:
第一种方式:
基于CGI模式
 CGI进程的生命周期
 如果有一个用户访问我们的web服务器,请求的是一个php的页面,那么web服务器会启动一个新的进程来响应用户php的请求,但是web服务器本身解释
 不了php的程序,于是它会调用php的解释器来解释这段代码,返回给web服务器,然后销毁进程,当下个用户仍然请求php页面的时候,在继续创建
 一个新的进程,然后返回给web服务器,销毁进程。以后都是这样的,创建进程,销毁进程,创建进程,销毁进程。很频繁的。势必赵成服务器的压力

假设 基于prefork的工作模式
如果同一时间内,有200个请求都是请求的php动态页面,那么服务器要运行多少个进程。
答案是400个php进程
因为apache工作在prefork的工作模式,每个php要请用一个进程,动态php的请求也会创建一个新的进程。
如果一个apache进程需要2M的内存空间 0.5G
一个php进程需要20M的内存空间  取决于请求页面的大小 4G
4.5G的空间瞬间没有了
缺点:会启用很多进程,并且CGI进程是临时创建的,还要有apche来创建和销毁CGI进程,响应php的请求会很慢


CGI这种机制对于php来说不是很好的机制,因为要大量的创建cgi进程销毁进程,会很频繁的创建和销毁  尤其是大量并发用户访问的时候。

第二种方式:
DSO机制  动态共享对象
 php_mod 把php做成apache的一个动态共享模块
这种机制,php装载到apache的动态模块中
优点:不用创建CGI进程,因为是在apache模块中启用的,因此直接用apache进程就可以响应请求,然后调取CGI来对代码解释就可以了
缺点:apache进程既要响应动态请求又要处理静态请求

用dns做负载均衡

第三种负载均衡:
fastcgi/fpm
如果apache工作在prefork的工作模式
叫做预先创建进程,就是即使没有用户请求,也会创建几个空闲的进程,当有用户访问的时候,可以直接响应用户的请求。速度会很快
一个进程生成一个线程,然后用线程处理用户请求

fpm这种模式就是为了解决CGI和加载php模块的不足
首先CGI进程不是临时创建的,是预先创建好的
其次使动态请求和静态请求分开,不用一个进程去处理,
以上两种会很大程度上提高响应用户的请求

动态响应和静态响应分来,不用一个即处理动态请求又处理静态请求

fpm-快速php模块

 

 


------------------------------

apache+php
对于rpm包来说只需要安装php就可以了。注意php5.3.3之前的版本还是不支持fpm的需要打补丁才能支持,之后的版本都支持fpm
[root@allentuns yum.repos.d]# yum install php php-mbstring    
php-mbstring:支持多字符串,一般情况下都要安装这个包,支持国际化的
[root@allentuns yum.repos.d]# rpm -ql php
/etc/httpd/conf.d/php.conf  #生成了一个web服务器的子配置文件
/usr/lib64/httpd/modules/libphp5.so #模块/编译成了动态共享库
/var/lib/php/session  #
/var/www/icons/php.gif #图标

因为这次笔记是记录php的 所以不涉及太多apache的只是,后续会有更多apache工作的模式,优化             
Apache配置文件中的参数
<IfModule prefork.c>
StartServers       8
MinSpareServers    5
MaxSpareServers   20
ServerLimit      256
MaxClients       256
MaxRequestsPerChild  4000
</IfModule>
Apache有三种工作模式
prefork:它采用的是进程管 理方式,所以它可以提供更可靠的性能和更好的兼容性
worker:它采用了线程控制方法,可以比perfork更节 约系统开销、处理更多的数据量,但同时兼容性并不是很好,很多旧的程序无法工作在worker下
event:处于试验阶段,它为每个任务分配不同的进程 池,目前不应该采用。

通过命令 httpd -l 可以获取目前Apache采用的是哪种MPM
[root@allentuns ~]# httpd -l
Compiled in modules:
  core.c
  prefork.c
  http_core.c
  mod_so.c

 

 

本文出自 “郑彦生” 博客,请务必保留此出处http://467754239.blog.51cto.com/4878013/1413239