多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
# 01 课程介绍 # ## 1-1 课程介绍 ## 本课程以作者5年的行业招聘经验和8年的开发和培训经验,讲述就业面试的答案。 各大企业常见的PHP面试题 - 面试考点 - 考官考察思路 - 复习PHP面试考点 - 总结面试难点 - 掌握解题方法和技巧 - 挖掘知识点 - 面试官的角度 - 深度剖析知识点 - 一网打尽所有考点内容 一句话:全面的剖析面试题和面试技巧,快速的提升技能以及面试技巧,找到更好的工作。 ### 95%以上的PHP面试考察点 - PHP基础知识 - JavaScript,jQuery,Ajax基础知识 - Linux基础知识 - MySQL数据库的基础与优化 - 程序设计题 - PHP框架基础知识 - 算法、逻辑思维 - 高并发解决方案 ## 1-2 怎样看待面试这回事 ## 面试是一个程序员生涯开始必须要经历的过程,也是证明自我、体现自我价值的敲门砖,我们的课程重点引领大家用好“自身技术”撬开步入理想企业的胜利之门。 面试基本流程 1. 筛选个人简历(HR,技术Leader) - 基本信息 - 掌握技能(重要) - 项目经验 2. 进行技术面试(电话面试,facetoface) 3. 商议薪资待遇,双方达成共识(HR) 4. 办理入职流程,上岗 面试前需要了解的 - PHP市场需求 - 为什么还是找不到工作(技术要点复习) - 技术能力为核心 求职者的七个等级阶段 - PHP爱好者 - 初学者 - 初级程序员 - 中级程序员 - 高级程序员 - 服务端技术专家 - 架构师 ## 1-3 基础的重要性 ## 重要性: - 以基础为前提的面试考察 - 坚实基础的重要性 - 保持谦卑之心 ### 常见经典面试题 - 什么是引用变量,在PHP当中,用什么符号定义引用变量? - 要求写出jQuery中,可以处理Ajax的几种方法。 - 写出尽可能多的Linux命令 - 写出三种以上MySQL数据库存储引擎的名称 - 编写一个在线留言本,实现用户的在线留言功能 - 谈谈你对MVC的认识,介绍几种目前比较流行的MVC框架 - 请写出常见的排序算法 - PHP中如何解决网站的大流量与高并发的问题 ## 1-4 透过现象看本质 ## 解题思路和技巧 - 回忆知识点 - 揣测面试官的考察思路 - 量的前提是精 # 第2章 PHP基础知识考察点 # ## 2-1至2-2 PHP引用变量考察点 ## 全方位剖析三大步骤: - 回顾真题 - 考点分析 - 一网打尽 回顾真题: 什么是引用变量?在PHP中用什么符号定义引用变量。 考官分析: - PHP的引用变量的概念和定义方式。 - 延伸:PHP引用变量的原理 概念: 在PHP中引用意味着用不同的名字访问同一个变量内容。 定义方式: 使用符号& 工作原理: 代码实例... 阶梯方法: 画图分析法 一网打尽: 真题 ## 2-3 常量及数据类型考察点## 回顾真题: PHP中字符串可以使用哪三种定义方法以及各自的区别是什么? 考官分析: PHP的字符串的定义方式及各自区别。 延伸:PHP数据类型及常量 PHP中定义字符串的三种方式: - 单引号 - 双引号 - heredoc和newdoc 单引号区别: - 单引号不能解析变量 - 单引号不能解析转义字符,只能解析单引号和反斜线本身 - 变量和变量、变量和字符串、字符串和字符串之间可以用.连接 - 单引号效率更高 双引号区别: - 双引号可以解析变量,变量可以使用特殊字符和{}包含 - 双引号可以解析所有转义字符 - 也可以用.来连接 实例 .... doc区别: - Heardoc类似于双引号 - Newdoc类似于单引号 - 两者主要用于处理大文本 实例 ... 知识点延伸:数据类型 - 三大数据类型(标量、复合、特殊) - 浮点:浮点类型不能用于比较运算符,例如:(0.1+0.7)==0.8 返回值是FALSE - 布尔类型:FALSE的七种情况。0,0.0,' ','0',false,array(),NULL - 数组类型:超全局数组。$GLOBALS, $_GET, $_POST, $_REQUEST, $_SESSION, $_COOKIE, $_SERVER, $_FILES, $_ENV。 - NULL:三种情况,直接赋值NULL,未定义变量,unset销毁的变量。 - 常量:定义const, define。const更快,是语言结构,define是函数。define不能用于类常量的定义,const可以。常量一旦定义,不可以被修改和删除。 - 预定义常量:__FILE__, __DIR__, __LINE__, __FUNCTION__, __CLASS__, __TARIT__, __METHOD__, __NAMESPACE__。 备注:记住`$_SERVER`的一些选项。 解题方法: 总之常用知识点进行梳理和复习,“牢记”。 一网打尽: - 用PHP写出显示客户端IP与服务器IP的代码。 - `__FILE__`表示什么意思? ## 2-4 运算符考察点## 回顾真题: foo()和@foo()之间的区别。 考官分析: - PHP的运算符和错误控制符@ - 延伸:PHP的所有运算符 - 运算符的优先级 - 比较运算符 - 逻辑运算符 - 递增/递减运算符 ... 一网打尽: 真题... ## 2-5 流程控制考察点## 回顾真题: 请列出3种PHP数组循环操作的语法,并注明各种循环的区别。 考官考点: 一网打尽: PHP中如何优化多个if...else语句的情况? - 将可能性较大的条件尽可能往前挪; - 如果条件表达式的结果为:字符串、浮点数或整型,则可以使用switch...case。 ## 2-6至2-7 自定义函数及内部函数考察点(上)## 考官考点: - 变量的作用域和静态变量 - 延伸:函数的参数及参数的引用传递 - 延伸:函数的返回值及引用返回 - 延伸:外部文件的导入 - 延伸:系统内置函数 ## 2-8 正则表达式考察点## 回顾真题: 至少写出一种验证139开头的11位手机号码的正则表达式 考官考点: - 手机号码的正则表达式编写 - 正则表达式的组成及编写方法 正则表达式知识点: - 正则表达式的作用:分割、查找、匹配、替换字符串。 - 分隔符:正斜线/,hash符号#, 以及取反符号~ - 通用原子:\d, \D, \w, \W, \s, \S - 元字符:. * ? ^ $ + {n} {n,} {n,m} `[]` `()` [^] | [-] - 模式修正符:i m e s U x A D u ## 2-9 文件及目录处理相关考点## 回顾真题: 不断在文件hello.txt头部写入一行"hello world"字符串,要求代码完整。 考官考点: - 文件读取与写入操作 - 延伸: ## 2-10 会话控制技术## 回顾真题: 简述cookie和session的区别及各自的工作机制,存储位置等,简述cookie的优缺点。 考官考点: - PHP的会话控制技术 为什么要使用会话控制技术? ## 2-11 面向对象考点## 模块 回顾真题: 请写出PHP类权限控制修饰符 考官考点: - PHP的类权限控制修饰符 - 延伸:面向对象的封装、继承和多态 - 延伸:魔术方法 - 延伸:设计模式 ## 2-12 网络协议考察点## 回顾真题: HTTP/1.1中,状态码200, 301, 304, 403, 404, 500的含义。 考官考点: - HTTP协议状态码 - 延伸:OSI七层模型 - 延伸:HTTP协议的工作特点和工作原理 - 延伸:HTTP协议常见请求/响应头和请求方法 - 延伸:HTTPs协议的工作原理 - 延伸:常见网络端口协议含义及端口 ## 2-13 开发环境及配置相关考点## 回顾真题: 您是否使用过版本控制软件?如果有您用的版本控制软件的名字是什么? # 第3章 JavaScript、jQuery以及AJAX基础考察点 # ## 3-1 JavaScript和jQuery基础考察点 ## 回顾真题: 下列不属于JavaScript语法关键/保留字的是(var, $, function, while) 考官考点: - JavaScript基本语法 - 延伸:JavaScript内置对象 - 延伸:JavaScript HTML DOM对象 - 延伸:jQuery基础知识 ### JavaScript基础语法 变量的定义: 变量必须以字母开头 变量也能以$和_开头 变量名称对大小写敏感 使用关键字var来声明变量 可以在一条语句中声明多个变量 未使用值来声明的变量,值是undefined 如果重新声明javascript变量,该变量的值不会丢失 var a=1; var a; 数据类型: 字符串、数字、布尔、数组、对象、Null、undefined JavaScript变量均为对象,当您声明了一个变量,就声明了一个对象 创建对象: new Object() 使用对象构造器 使用JSON对象 函数: 定义函数 无默认值 函数内部声明的变量是局部变量 在函数外部声明的变量是全局变量,所有脚本和函数都能访问它 运算符: +号用来拼接字符串 流程控制: else if必须分开写 ### 延伸:JavaScript内置对象 Number var pi = 3.14; var myNum = new Number(value); var myNum = Number(value); String var str = 'This is String'; var str = new String(s); var str = String(s); Boolean var bol = true; var bol = new Boolean(value); var bol = Boolean(value); Array var arr = new Array(); var arr = new Array(size); var arr = new Array(e1,e2,e3,...en); Date var date = new Date(); Math var pi_value = Math.PI; var sqrt_value = Math.sqrt(15); RegExp /pattern/attributes new RegExp(pattern, attributes); ### 延伸:JavaScript Window对象 Window对象 Window, Navigator, Screen, History, Location ### 延伸:JavaScript HTML DOM对象 DOM对象 Dcoument, Element, Attr, Event ### 延伸:jQuery基础知识 jQuery选择器: 基本选择器,层次选择器,过滤选择器,可见性过滤选择器,属性过滤选择器,子元素过滤选择器,表单对象属性过滤选择器 jQuery事件: $("button").click(function(){...do somthing...}) jQuery效果: $("p").show() jQuery DOM操作: 属性,值,节点,CSS,尺寸 ### 解题方法 牢记以上基础知识点,比较常考察的是JavaScript的HTML样式操作以及jQuery的选择器和事件、样式操作。 document.getElementById('test').className = 'good' ### 一网打尽 JavaScript中的id为test的元素设置样式为good; 要求使用jQuery事件写在页面元素加载完成后,动态绑定click事件到btnOk元素; $(function(){ $(".btnOk").click(function(){ ... }) }); ## 3-2 AJAX基础内容考察点 ## 回顾真题: Ajax技术利用了什么协议?简述Ajax的工作机制? 考官考点: - Ajax的基本工作原理 - 延伸:jQuery的Ajax操作 ### Ajax的基本工作原理 Ajax基础概念: Asynchronous JavaScript and XML 通过在后台与服务器进行少量数据交换,AJAX可以使网页实现异步更新; Ajax工作原理: XMLHttpRequest是Ajax的基础 XMLHttpRequest用于在后台与服务器交换数据 XMLHttpRequest对象请求: open(method, url, async) XMLHttpRequest对象响应: - responseText - responseXML - onreadystatechange - readyState: 0(请求未初始化) 1(服务器连接已建立) 2(请求已接收) 3(请求处理中) 4(请求已完成,且响应已就绪) - status: 200, 400 ### 延伸:jQuery的Ajax操作 常用方法: $(ele).load(), $.ajax(), $.get(), $.post(), $.getJSON(), $.getScript() ### 解题方法 理解AJXA工作原理,这也是与面试官面聊时可能会被问到的; 牢记jQuery的AJAX操作方法,遇到AJAX编程题,先考虑jQuery的AJAX操作方式,判断是GET还是POST请求,然后选择对应的方法,通常不会考察JavaScript的原生操作方式; ### 一网打尽 要求写出jQuey中,可以处理AJAX的几种方法。 # 第4章 Linux基础考察点 # ## 4-1 Linux基础考察点 ## 回顾真题: 写出尽可能多的Linux命令。 考官考点: - Linux常用命令 - 延伸:系统定时任务 - 延伸:vi/vim编辑器 - 延伸:shell基础 ## Linux常用命令 ### 进程管理 w, top, ps, kill, pkill, pstree, killall ### 用户管理 id, usermod, useradd, groupadd, userdel ### 文件系统 mount, umount, fsck, df, du ### 网络应用 ### 网络测试 ### 网络配置 hostname, ifconfig ### 常用工具 ssh, screen, clear, who, date ### 软件包管理 yum, rpm, apt-get ### 文件查找和比较 locate, find ### 文件内容查看 head, tail, less, more ### 文件处理 touch, unlink, rename, ln, cat ### 目录操作 cd, mv, rm, pwd, tree, cp, ls ### 文件权限属性 setfacl, chmod, chown, chgrp ## 延伸:系统定时任务 crontab -e * * * * * 命令(分 时 日 月 周) at命令: # at 2:00 tomorrow at> /home/Jason/do_job at> Ctrl+D ## 延伸:vi/vim编辑器 一般模式: - 一般模式,编辑模式,命令行模式 - 一般模式:删除,复制和粘贴 - 切换编辑模式:i, I, o, O, a, A, r, R - 切换命令行模式::, /, ? 移动光标: ctrl+f, ctrl+d, 0或者Home,$或者END,G,gg,N+enter 查找和替换: /word, ?word, :n1,n2s/word1/word2/g :1,$s/word1/word2/g :1,$s/word1/word2/gc 删除、复制和粘贴: x,X dd, ndd, yy, nyy, p, P, ctrl+r, . 保存退出: w, q, wq 配置行号: :setnu, :setnonu ## 延伸:shell基础 脚本执行方式 赋予权限,直接执行,例如:chmod +x test.sh; ./test.sh 调用解释器使得脚本执行,例如:bash, csh, ash, bsh, ksh等等; 编写基础: 开头用#!指定脚本解释器,如:#!/bin/sh 编写具体功能 ## 解题方法 牢记以上知识点 ## 一网打尽 如何实现每天0点重新启动服务器 crontab -e 0 0 * * * reboot # 第5章 MySQL数据库考察点 # ## 5-1 MySQL数据库基础考察点 ## 回顾真题: - 请写出下面MySQL数据类型表达的意义: int(0), char(16), varchar(16), datetime, text 考官考点: - MySQL数据类型 - 延伸:MySQL基础操作 - 延伸:MySQL存储引擎 - 延伸:MySQL锁机制 - 延伸:MySQL事务处理、存储过程、触发器 ### MySQL数据类型: 整数类型: - TINYINT,SMALLINT,MEDIUMINT,INT,BIGINT - 属性:UNSIGNED - 长度:可以为整数指定宽度,例如:INT(11),对大多数应用是没有意义的,它不会限制值的合法范围,只会影响显示字符的个数,配合ZEROFILL使用。 实数类型: - FLOAT,DOUBLE,DECIMAL - DECIMAL可存储比BIGINT还大的整数;可以用于存储精确的小数 - FLOAT和DOUBLE类型支持使用标准的浮点进行近似计算 字符串类型: - VARCHAR,CHAR,TEXT,BLOB - VARCHAR类型用于存储可变长字符串,它比定长类型更节省空间; - VARCHAR使用1或2个额外字节记录字符串的长度,列长度小于255字节,使用1字节表示,否则用2个; - VARCHAR长度,如果存储内容超出指定长度,会被截断; - CHAR是定长的,根据定义的字符串长度分配足够的空间; - CHAR会根据需要采用空格进行填充以方便比较; - CHAR适合存储很短的字符串,或者所有值都接近同一个长度; - CHAR长度,超出设定的长度,会被截断; - 对于经常变更的数据,CHAR比VARCHAR更好,CHAR不容易产生碎片; - 对于非常短的列,CHAR比VARCHAR在存储空间上更有效率; - 只分配真正需要的空间,更长的列会消耗更多的内存; - 尽量避免使用BLOB/TEXT类型,查询会使用临时表,导致严重的性能开销; 枚举: - 有时可以使用枚举代替常用的字符串类型 - 把不重复的集合存储成一个预定义的集合 - 非常紧凑,把列表值压缩到一个或两个字节 - 内部存储的是整数 - 尽量避免使用数字作为ENUM枚举的常量,易混乱 - 排序是按照内部存储的整数进行排序 - 枚举表会使表大小大大减少 日期和时间类型: - 尽量使用TIMESTAMP,比DATETIME空间效率高 - 用整数保存时间戳的格式通常不方便处理 - 如果需要存储微秒,可以使用bigint存储 列属性: - auto_increment, default, not null, zerofill 常见操作: - MySQL的连接和关闭:mysql -u -p -h -p - 其他:\G, \c, \q, \s, \h, \d InnoDB表引擎: - 默认事务型引擎,最重要最广泛的存储引擎,性能非常优秀 - 数据存储在共享表空间,可以通过配置分开 - 对主键查询的性能高于其他类型的存储引擎 - 内部做了很多优化,从磁盘读取数据时自动在内存构建hash索引 - 插入数据时自动构建插入缓冲区 - 通过一些机制和工具支持真正的热备份 - 支持崩溃后的安全恢复 - 支持行级锁 - 支持外键 MyISAM表引擎: - 5.1版本前,MyISAM是默认的存储引擎 - 拥有全文索引,压缩,空间函数 - 不支持事务和行级锁,不支持崩溃后的安全恢复 - 表存储在两个文件,MYD和MYI - 设计简单,某些场景下性能很好 其他表引擎: - Archive, Blackhole, CSV, Memory - 优先选择InnoDB 基础概念: - 表锁是日常开发当中常见的问题,因此也是面试中最常见的考察点,当多个查询同一时刻进行数据修改时,就会产生并发控制的问题。 写锁: - 排他的,一个写锁会阻塞其他的写锁和读锁,这样可以只允许一个人进行写入,防止其他用户读取正在写入的资源。 锁粒度: - 表锁,系统性能开销最小,会锁定整张表,MyISAM使用表锁行锁,最大程度地支持并发处理,但是也带来了最大的锁开销,InnoDB实现行级锁。 事务处理: - MySQL提供事务处理的表引擎,InnoDB - 服务器层不管理事务,由下层的引擎实现,所以在同一个事务中,使用多种存储引擎不靠谱,在非事务的表上执行事务操作MySQL不会发出提醒,也不会报错。 MySQL存储过程: - 为以后的使用而保存的一条或者多条MySQL语句的集合 - 存储过程就是有业务逻辑和流程的集合 - 可以在存储过程中创建表,更新数据,删除等等 MySQL存储过程使用场景: - 通常把处理封装在容易使用的单元中,简化复杂的操作 - 保证数据的一致性 - 简化对变动的管理 触发器: - 提供给程序员和数据分析员来保证数据完整性的一种方法,它是与表事件相关的特殊的存储过程。 触发器使用场景: - 可通过数据库中的相关表实现级联更改 - 实现监控某张表中的某个字段的更改而需要作出相应的处理 - 某些业务编号的生成 - 滥用会造成数据库及应用程序的维护困难 解题方法: - 牢记以上基础知识点,理解数据类型Char和Varchar的差异,表存储引擎InnoDB和MyISAM的区别。 ## 5-2 MySQL创建高性能的索引考察点 ## 回顾真题: 简单描述MySQL中,索引、主键、唯一索引、联合索引的区别,对数据库的性能有什么影响? 考官考点: - MySQL索引的基础和类型 - 延伸:MySQL索引的创建原则 - 延伸:MySQL索引的注意事项 ### MySQL索引的基础和类型 索引的基础 - 索引类似于书籍的目录,要想找到一本书的某个主题,需要先找到书的目录,定位对应的页码。 - 存储引擎使用类似的方式进行数据查询,先去索引当中找到对应的值,然后根据匹配的索引找到对应的数据行。 索引对性能的影响 - 大大减少服务器需要扫描的数据量 - 帮助服务器避免排序和临时表 - 将随机I/O变顺序I/O - 大大提高查询速度,降低写的速度,占用磁盘 索引的使用场景 - 对于非常小的表,大部分情况下全表扫描效率最高 - 中到大型表索引非常有效 - 特大型的表,建立和使用索引的代价将随之增长,可以使用分区技术来解决 索引的类型 - 索引有很多类型,都是实现在存储引擎层的 - 普通索引:最基本的索引,没有任何约束限制 - 唯一索引:与普通索引类似,但是具有唯一性约束 - 主键索引:特殊的唯一索引,不允许有空值 - 一个表只能有一个主键索引,可以有多个唯一索引 - 主键索引一定是唯一索引,唯一索引不是主键索引 - 主键可以与外键构成参照完整性约束,防止数据不一致 - 组合索引:将多个列组合在一起创建索引,可以覆盖多个列 - 外键索引:只有InnoDB类型的表才可以使用外键索引,保证数据的一致性,完整性和实现级联操作 - 全文索引:MySQL自带的全文索引只能用于MyISAM,并且只能对英文进行全文检索 ### 延伸:MySQL索引的创建原则 原则 - 最适合索引的列是出现在WHERE子句中的列,或连接子句中的列而不是出现在SELECT后面的列 - 索引列的基数越大,索引的效果越好 - 对字符串进行索引,应该制定一个前缀长度,可以节省大量的索引空间 - 根据情况创建复合索引,复合索引可以提高查询效率 - 避免创建过多索引,索引会额外占据磁盘空间,降低写操作效率 - 主键尽可能选择较短的数据类型,可以有效减少索引的磁盘占用提高查询效率 ### 延伸:MySQL索引的注意事项 注意 - 复合索引遵循前缀原则 - like查询,%不能在前,可以使用全文索引 - column is null可以使用索引 - 如果MySQL估计使用索引比全表扫描更慢,会放弃使用索引 - 如果or前的条件中的列有索引,后面的没有,索引都不会被用到 - 列类型是字符串,查询时一定要给值加上引号,否则索引失效 ### 解题方法 在一些MySQL索引基础考题中,我们可以轻松的通过索引基础和类型来解决此类问题,对于一些索引创建注意事项方面的考点,我们可以通过索引创建原则和注意事项来解决。 ### 一网打尽 创建MySQL复合索引应该注意哪些事项? ## 5-3 MySQL的SQL语句编写考察点 ## 回顾真题: 有A(id,sex,par,c1,c2),B(id,age,c1,c2)两张表,其中A.id与B.id关联,现在要求写一条SQL语句,将B中age>50的记录的c1,c2更新到A表中统一记录的c1,c2字段中。 考官考点: - MySQL的关联UPDATE语句 - 延伸:MySQL的关联查询语句 ### MySQL的关联UPDATE语句 UPDATE A,B SET A.c1=B.c1,A.c2=B.c2 WHERE A.id=B.id and ... UPDATE A INNER JOIN B ON A.id=B.id SET A.c1=B.c1,A.c2=B.c2 WHERE ... ### 延伸:MySQL的关联查询语句 六种关联查询: 交叉连接(CROSS JOIN) 内连接(INNER JOIN) 外连接(LEFT JOIN/RIGHT JOIN) 联合查询(UNION与UNION ALL) 全连接(FULL JOIN) 交叉连接 SELECT * FROM A,B(,C) 或者 SELECT * FROM A CROSS JOIN B (CROSS JOIN C) 没有任何关联条件,结果是笛卡尔积,结果集会很大,没有意义,很少使用。 内连接 SELECT * FROM A,B WHERE A.id=B.id 或者 SELECT * FROM A INNER JOIN B ON A.id=B.id 多表中同时符合某种条件的数据记录的集合 内连接分为三类 等值连接 ON A.id=B.id 不等值连接 ON A.id>B.id 自连接 SELECT * FROM A T1 INNER JOIN A T2 ON T1.id=T2.pid INNER JOIN 可以缩写为 JOIN 外连接 > 左外连接 LEFT OUTER JOIN, 以左表为主,先查询出左表,按照ON后的关联条件匹配右表,没有匹配到的用NULL填充,可以简写成LEFT JOIN 外连接 > 右外连接 RIGHT OUTER JOIN, 以右表为主,先查询出右表,按照ON后的关联条件匹配左表,没有匹配到的用NULL填充,可以简写成RIGHT JOIN 联合查询 SELECT * FROM A UNION SELECT * FROM B UNION ... 就是把多个结果集集中在一起,UNION前的结果为基准,需要注意的是联合查询的列数要相等,相同的记录行会合并,如果使用UNINON ALL不会合并重复的记录行。 全连接 MySQL不支持全连接 可以使用LEFT JOIN和UNION和RIGHT JOIN联合使用 SELECT * FROM A LEFT JOIN B ON A.id=B.id UNION SELECT * FROM A RIGHT JOIN B ON A.id=B.id 嵌套查询 用一条SQL语句的结果作为另外一条SQL语句的条件 SELECT * FROM A WHERE id IN (SELECT id FROM B) ### 解题方法: 根据考题要搞清楚表的结构和多表之间的关系,根据想要的结果思考使用哪种关联方式,通常把要查询的列先写出来,然后分析这些列都属于哪些表,才考虑使用关联查询。 ### 一网打尽: 为了记录足球比赛的结果,设计表如下: team表: CREATE TABLE `team`( `teamID` int unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY, `teamName` varchar(20) NOT NULL )ENGINE=InnoDB DEFAULT CHARSET=utf8; match表: CREATE TABLE `match`( `matchID` int unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY, `hostTeamID` int NOT NULL, `guestTeamID` int NOT NULL, `matchResult` varchar(20) NOT NULL, `matchTime` timestamp NOT NULL )ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `match` (hostTeamID, guestTeamID, matchResult, matchTime) VALUES (1, 2, '1:1', '2018-09-23 18:00'), (2, 1, '2:1', '2018-09-30 18:00'), (1, 3, '3:1', '2018-09-23 18:00'), (1, 4, '4:0', '2018-09-23 18:00'), (1, 5, '0:4', '2018-09-23 18:00'), (1, 6, '2:2', '2018-09-23 18:00'), (1, 7, '3:1', '2018-09-23 18:00'); 其中,match赛程表中的hostTeamID和guestTeamID都和team表中的teamID关联,查询出2016-6-1至2016-7-1之间所有的比赛,并且用以下形式列出:拜仁 2:0 不莱梅 2006-6-21 SELECT T1.teamName, M.matchResult, T2.teamName, M.matchTime FROM `match` M LEFT JOIN `team` T1 ON T1.teamID=M.hostTeamID LEFT JOIN `team` T2 ON T2.teamID=M.guestTeamID WHERE M.matchTime between '2018-09-01' and '2018-09-30'; ## 5-4 MySQL的查询优化考察点 ## 回顾真题: 请简述项目中优化SQL语句执行效率的方法,从哪些方面,SQL语句性能如何分析? 考官考点: - 查找分析查询速度慢的原因 - 优化查询过程中的数据访问 - 优化长难的查询语句 - 优化特定类型的查询语句 ### 查找分析查询速度慢的原因 分析SQL查询慢的方法: - 记录慢查询日志 - 分析查询日志,不要直接打开慢查询日志进行分析,这样比较浪费时间和精力,可以使用pt-query-digest工具进行分析 - 使用show profile set profiling=1;开启,服务器上执行的所有语句会检测消耗的时间,存储到临时表中; show profiles; show profile for query 临时表ID - 使用show status show status会返回一些计数器,show global status查看服务器级别的所有计数 有时根据这些计数,可以猜测出哪些操作代价较高或者消耗时间多 - 使用show processlist 观察是否有大量线程处于不正常的状态或者特征 - 使用explain 分析单条SQL语句 ### 优化查询过程中的数据访问 访问数据太多导致查询性能下降 确定应用程序是否在检索大量超过需要的数据,可能是太多行或列 确认MySQL服务器是否在分析大量不必要的数据行 避免使用如下SQL: - 查询不需要的记录,使用limit - 多表关联返回全部列,指定A.id,A.name,B.age - 总是取出全部列,`SELECT *` 会让优化器无法完成索引覆盖扫描的优化 - 重复查询相同的数据,可以缓存数据,下次直接读取缓存 是否在扫描额外的记录: - 使用explain来进行分析,如果发现查询需要扫描大量的数据但只返回少数的行,可以通过如下技巧去优化: - 使用索引覆盖扫描,把所有用的列都放到索引中,这样存储引擎不需要回表获取对应行就可以返回结果; - 改变数据库和表的结构,修改数据表范式; - 重写SQL语句,让优化器可以以更优的方式执行查询; ### 优化长难的查询语句 一个复杂查询还是多个简单查询: - MySQL内部每秒能扫描内存中上百万行数据,相比之下,响应数据给客户端就要慢得多; - 使用尽可能少的查询是好的,但是有时将一个大的查询分解为多个小的查询是很有必要的; 切分查询: - 将一个大的查询分为多个小的相同的查询 - 一次性删除1000万的数据要比一次删除1万,暂停一会的方案更加损耗服务器开销 分解关联查询: - 可以将一条关联语句分解成多条SQL来执行 - 让缓存的效率更高 - 执行单个查询可以减少锁的竞争 - 在应用层做关联可以更容易对数据库进行拆分 - 查询效率会有大幅提升 - 较少冗余记录的查询 ### 优化特定类型的查询语句 优化count()查询: - `count(*)`中的`*`会忽略所有的列,直接统计所有的列数,因此不要使用`count(列名)` - MyISAM中,没有任何WHERE条件的`count(*)`非常快 - 当有WHERE条件,MyISAM的count统计不一定比其他表引擎快 优化关联查询: - 确保ON或者USING子句的列上有索引 - 确保GROUP BY和ORDER BY中只有一个表中的列,这样MySQL才有可能使用索引 优化子查询: - 尽可能使用关联查询来替代 优化GROUP BY和DISTINCT: - 这两种查询均可使用索引来优化,是最有效的优化方法 - 关联查询中,使用标识列进行分组的效率会更高 - 如果不需要ORDER BY,进行GROUP BY时使用ORDER BY NULL,MySQL不会再进行文件排序 - WITH ROLLUP超级聚合,可以挪到应用程序处理 优化LIMIT分页: - LIMIT偏移量大的时候,查询效率较低 - 可以记录上次查询的最大ID,下次查询时直接根据该ID来查询 优化UNION查询: - UNION ALL的效率高于UNION ### 解题方法 对于此类考题,先说明如何定位低效SQL语句,然后根据SQL语句可能低效的原因做排查,先从索引着手,如果索引没有问题,考虑以上几个方面,数据访问的问题,长难查询句的问题还是一些特定类型优化的问题,逐一回答。 ### 一网打尽 SQL语句优化的有些方法 ## 5-5 MySQL的高可扩展和高可用考察点 ## ### 回顾真题 简述MySQL分表操作和分区的工作原理,分别说说分区和分表的使用场景和各自优缺点。 ### 考官考点 - 分区表的原理 - 分库分表的原理 - 延伸:MySQL的复制原理及负载均衡 #### 分区表的原理: 工作原理: 对用户而言,分区表是一个独立的逻辑表,但是底层MySQL将其分成了多个物理子表,这对用户来说是透明的,每一个分区表都会使用一个独立的表文件。 创建表时使用partition by子句定义每个分区存放的数据,执行查询时,优化器会根据分区定义过滤那些没有我们需要数据的分区,这样查询只需要查询所需数据在的分区即可。 分区的主要目的是将数据按照一个较粗的粒度分在不同的表中,这样可以将相关的数据存放在一起,而且如果想一次性删除整个分区的数据也很方便。 适用场景: 1. 表非常大,无法全部存在内存,或者只在表的最后有热点数据,其他都是历史数据 2. 分区表的数据更易维护,可以对独立的分区进行独立的操作 3. 分区表的数据可以分布在不同的机器上,从而高效使用资源 4. 可以使用分区表来避免某些特殊的瓶颈 5. 可以备份和恢复独立的分区 限制: 1. 一个表最多只能有1024个分区 2. 5.1版本中,分区表表达式必须是整数,5.5可以使用列分区 3. 4. 分区表中无法使用外键约束 5. 需要对现有表的结构进行修改 6. 所有分区都必须使用相同的存储引擎 7. 分区函数中可以使用的函数和表达式会有一些限制 8. 某些存储引擎不支持分区 9. 对于MyISAM的分区表,不能使用load index into cache 10. 对于MyISAM表,使用分区表时需要打开更多的文件描述符 #### 分库分表的原理: 工作原理: 通过一些HASH算法或者工具实现将一张数据表垂直或者水平进行物理切分。 适用场景: 1. 单表记录条数达到百万到千万级别时 2. 解决表锁的问题 分表方式:水平分割 表很大,分割后可以降低在查询时需要读的数据和索引的页数,同时也降低了索引的层数,提高查询速度。 图1 适用场景: 1. 表中的数据本身就有独立性,例如表中分别记录各个地区的数据或者不同时期的数据,特别是有些数据常用,有些不常用 2. 需要把数据存放在多个介质上 水平分表缺点: 1. 给应用增加复杂度,通常查询时需要多个表名,查询所有数据都需UNION操作。 2. 在许多数据库应用中,这种复杂性会超过它带来的优点,查询时会增加读一个索引层的磁盘次数 分表方式:垂直分表 把主键和一些列放在一个表,然后把主键和另外的列放在另一个表中 图2 使用场景: 1. 如果一个表中某些列常用,而另外一些列不常用 2. 可以使数据行变小,一个数据页能存储更多的数据,查询时减少I/O次数 垂直分表缺点: 管理冗余列,查询所有数据需要JOIN操作 分表缺点: - 有些分表的策略基于应用层的逻辑算法,一旦逻辑算法该表,整个分表逻辑都会改变,扩展性较差 - 对于应用层来说,逻辑算法无疑增加开发成本 #### 延伸:MySQL的复制原理及负载均衡: MySQL主从复制工作原理: - 在主库上把数据更改记录到二进制日志 - 从库将主库的日志复制到自己的中继日志 - 从库读取中继日志中的事件,将其重放到从库数据中 MySQL主从复制解决的问题: - 数据分布:随意停止或开始复制,并在不同地理位置分布数据备份 - 负载均衡:降低单个服务器的压力 - 高可用和故障切换:帮助应用程序避免单点失败 - 升级测试:可以使用更高版本的MySQL作为从库 ### 解题方法 充分掌握分区和分表的工作原理和适用场景,在面试中,此类考题通常比较灵活,会给一些现有公司遇到的问题的场景,大家可以根据分区和分表以及MySQL复制、负载均衡的适用场景来根据情况进行回答。 ### 一网打尽 设定网站的用户数量在千万级,但是活跃用户的数量只有1%,如何通过优化数据库提高活跃用户的访问速度? ## 5-6 MySQL的安全性考察点 ## ### 回顾真题 SQL语句应该考察哪些安全性? ### 考官考点 - SQL查询的安全方案 - 延伸:MySQL的其他安全设置 #### SQL查询的安全方案 1. 使用预处理语句防止SQL注入 2. 写入数据库的数据要进行特殊字符的转义 3. 查询错误信息不要返回给用户,将错误记录到日志 delete from user where id=1 or 1=1; /user/delete?id=1 /user/delete?id=1 or 1=1 注意: PHP端尽量使用PDO对数据库进行相关操作,PDO拥有对预处理语句很好的支持的方法,MySQLi也有,但是可扩展性不如PDO,效率略高于PDO,MySQL函数在新版本中已经趋向于淘汰,所以不建议使用,而且它没有很好的支持预处理的方法。 #### 延伸:MySQL的其他安全设置 1. 定期做数据备份 2. 不给查询用户root权限,合理分配权限 3. 关闭远程访问数据库权限 4. 修改root口令,不用默认口令,使用较复杂的口令 5. 改变root用户的名称 6. 限制一般用户浏览其他库 7. 限制用户对数据文件的访问权限 ### 解题方法 通常情况下,SQL安全的考点都在防SQL注入的问题,因此只要遇到此类考点,优先考虑SQL注入的防护手段。 ### 一网打尽 为什么使用PDO和MySQLi连接数据库会比mysql函数库更加安全。 # 第6章 程序设计题考察点 # ## 6-1 程序功能设计考察点 ### 回顾真题: 编写一个在线留言本,实现用户的在线留言功能,留言信息存储到数据库,要求设计数据表内容以及使用PHP编码完成。 ### 考官考点: - 数据表设计 - 数据表创建语句 - 选择PHP连接数据库的方式 - 编码能力 #### 数据表设计 分析数据表结构: 留言板有哪些信息需要存储 留言信息:ID,留言标题,留言内容,留言时间,留言人 #### 数据表创建语句 ``` CREATE TABLE message( `id` int unsigned not null auto_increment primary key, `title` varchar(120) not null default '', `content` varchar(2500) not null default '', `create_time` int not null default 0, `user_name` varchar(32) not null default '', KEY message_user_name(user_name) )ENGINE=InnoDB DEFAULT CHARSET=utf8; ``` #### 选择PHP连接数据库的方式 PDO: 可扩展性好、支持预处理、面向对象 MySQLi: 只支持MySQL操作,支持预处理,面向对象和过程,效率较高 MySQL: 只支持MySQL数据库,没有预处理支持,面向过程 PDO操作数据库的代码 ... #### 编码能力 <?php try{ ... }catch(PDOException $e){ echo $e->getMessage(); } $pdo = new PDO($dsn,$username,$password,$attr); $sql = 'SELECT id,title,content FROM message WHERE user_name=:user_name'; $stmt = $pdo->prepare($sql); $stmt->execute([':user_name'=>$user_name]); $result = $stmt->fetchAll(PDO::FETCH_ASSOC); ### 解题方法 根据考题所出功能,先分析应该存储哪些信息,设计好数据表,这一步很关键,如果编码时才发现设计有问题,会浪费大量的时间,基本没有时间改,所以要先设计好,然后根据设计好的数据表创建数据表,通常建议大家使用PDO来连接MySQL,最终完成编码,所以一定要熟悉PDO的基本操作。 ### 真题: 设计一个无限分类表 # 第7章 PHP框架基础知识考察点 # ## 7-1 MVC框架基本工作原理考察点 ## ### 回顾真题: 谈谈你对MVC的认识,介绍几种目前比较流行的MVC框架。 ### 考官考点: - MVC工作原理 - 常见MVC框架 - 延伸:单一入口的工作原理 - 延伸:模板引擎的理解 #### MVC工作原理 M: Model V: View C: Controller 图1 图2 #### 常见MVC框架 MVC框架:ThinkPHP, Yii2, CI, Yaf, Phalcon等; 图3 #### 延伸:单一入口的工作原理 工作原理: 用一个处理程序文件处理所有的HTTP请求,根据请求时的参数的不同区分不同模块和操作的请求。 图4 优势: - 可以进行统一的安全性检查 - 集中处理程序 劣势: - URL不美观(URL重写) - 处理效率会稍低 #### 延伸:模板引擎的理解 常见模板引擎: PHP是一种HTML内嵌式的在服务端执行的脚本语言,但是PHP有很多可以使PHP代码和HTML代码分开的模板引擎,例如:Smarty, Twig, Haml, Liquid等。 工作原理: 模板引擎就是庞大的完善的正则表达式替换库。 ### 解题方法 牢记MVC思想内容,至少能背出来 尝试使用PHP的一个MVC框架完成一个小功能,例如:简单的用户管理系统,完成用户的增删改查即可。 ### 一网打尽 框架中什么是单一入口和多入口,单一入口的优缺点。 ## 7-2 常见框架特性考察点 ## ### 回顾真题 PHP框架有哪些,你用过哪些?各自的优缺点是什么? ### Yaf框架 Yaf使用PHP扩展的形式写的一个PHP框架,也就是以C语言为底层编写的,性能上要比PHP代码写的框架要快一个数量级。 优点:执行效率高』轻量级框架、可扩展性强 缺点:高版本兼容性差、底层代码可读性差、需要安装扩展、功能单一、开发需要编写大量的插件。 ### Yii2框架 YII2是一款非常优秀的通用Web后端框架,结构优雅简单,实用功能丰富,扩展性强,性能高是它最突出的优点。 缺点:学习成本高、相比Yaf,量级较重 #### 常见框架特性: 根据自己的框架使用经验,理解所使用框架的特性 例如:Yii2框架的路由配置等; ### 解题方法 此类题目中,说明的最好是自己真正用过的框架,最好结合自己的简历,简历当中提到的框架,要着重准备,可以说说在开发过程中,你使用该框架最让你印象深刻的功能和特性,最好多进行框架间的对比,展现你对PHP框架的理解,侧面说明你的开发经验。 ### 一网打尽 Yii2框架如何实现数据的自动验证? # 第8章 算法、逻辑思维考察点 # ## 8-1 常见算法考察点 ## 回顾真题: 请写出常见的排序算法,并用PHP实现冒泡排序,将数组按照从小到大的方式进行排序。 ## 8-2 常见数据结构考察点 ## ## 8-3 其他逻辑算法考察点 ## ## 8-4 模拟内置函数实现考察点 ## # 第9章 高并发解决方案类考察点 # ## 9-1 高并发和大流量解决方案考察点 ## 回顾真题: PHP如何解决网站大流量和高并发的问题? 考官分析: - 高并发架构相关概念 - 高并发解决方案案例 ### 高并发架构相关概念 并发: 并发,在操作系统中,是指一个时间段内有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。 我们说的高并发是什么? 上面的定义明显不是我们通常所言的并发,在互联网时代,所讲的并发、高并发,通常是指并发访问。也就是在某一个时间点,有多少个访问同时到来。 通常如果一个系统在日PV在千万以上,有可能是一个高并发的系统有的公司完全不走技术路线,全靠机器堆,这不在我们的讨论范围。 高并发的问题,我们具体该关心什么? - QPS:每秒钟请求或者查询的数量,在互联网领域,指每秒响应请求数(指HTTP请求)。 - 吞吐量:单位时间内处理的请求数量(通常由QPS与并发数决定) - 响应时间:从请求发出到收到响应发费的时间。例如系统处理一个HTTP请求需要100ms,这个100ms就是系统的响应时间。 - PV:综合浏览量(Page View),即页面浏览量或者点击量,一个访客在24小时内访问的页面数量。同一个人浏览你的网站同一页面,只记作一次PV。 - UV:独立访客(Unique Vistor),即一定时间范围内相同访客多次访问网站,只计算为1个独立访客。 - 带宽:计算带宽大小需关注两个指标,峰值浏览和页面的平均大小。 日网站带宽=PV/统计时间(换算成秒) * 平均页面大小(单位KB) * 8 峰值一般是平均值的倍数,根据实际情况来定。 - QPS不等于并发连接数 QPS是每秒HTTP请求数量,并发连接数是系统同时处理的请求数量 (总PV数*80%)/(6小时秒数*20%)=峰值每秒请求数(QPS) 80%的访问量集中在20%的时间 - 压力测试 - 测试能承受的最大并发 - 测试最大承受的QPS值 ### 常用的性能测试工具 ab,wrk,http_load,Web Bench,Siege,Apache JMeter #### ab 全称是apache benchmark,是apache官方推出的工具创建多个并发访问线程,模拟多个访问者同时对某一URL地址进行访问。它的测试目标是基于URL的,因此,它既可以用来测试apache的负载压力,也可以测试nginx, lighthttp, tomcat, iis等其他Web服务器的压力。 ab的使用: 模拟并发请求100次,总共请求5000次。 ab -c 100 -n 5000 待测试网站 注意事项: - 测试机器与被测试机器分开 - 不要对线上服务做压力测试 - 观察测试工具ab所在机器,以及被测试的前端机的CPU,内存,网络等都不超过最高限度的75% ### QPS达到极限 QPS达到极限:随着QPS的增长,每个阶段需要根据实际情况来进行优化,优化的方案也与硬件条件、网络带宽息息相关。 - QPS达到50:可以称为小型网站,一般的服务器就可以应付。 - QPS达到100:假设关系型数据库的每次请求在0.01秒完成。假设单页面只有一个SQL查询,那么100QPS意味着1秒钟完成100次请求,但是此时我们并不能保证数据库查询能完成100次。 方案:数据库缓存、数据库的负载均衡。 - QPS达到800:假设我们使用百兆带宽,意味着网站出口的实际带宽是8M左右。假设每个页面只有10K,在这个并发条件下,百兆带宽已经吃完。 方案:CDN加速,负载均衡 - QPS达到1000:假设使用Memcache缓存数据库查询数据,每个页面对Memcache的请求远大于直接对DB的请求 Memcache的悲观并发数在2W左右,但有可能在之前内网带宽已经吃光,表现出不稳定 方案:静态HTML缓存 - QPS达到2000:这个级别下,文件系统访问锁都成为了灾难。 方案:做业务隔离,分布式存储。 ### 流量优化 - 防盗链处理 - 前端优化 - 减少HTTP请求 - 添加异步请求 - 启用浏览器缓存和文件压缩 - CDN加速 - 建立独立图片服务器 - 服务端优化 - 页面静态化 - 并发处理 - 队列处理 - 数据库优化 - 数据库缓存 - 分库分表、分区操作 - 读写分离 - 负载均衡 - Web服务器优化 - 负载均衡 ## 9-2 web资源防盗链 ## 相关概念: - 什么是防盗链 - 防盗链的工作原理 - 防盗链的实现方法 ### 什么是防盗链? 盗链是指在自己的页面上展示一些并不在自己服务器上的内容,获得他人服务器上的资源地址,绕过别人的资源展示页面,直接在自己的页面上向最终用户提供此内容。 常见的是小站盗用大站的图片、音乐、视频、软件等资源 通过盗链的方法可以减轻自己服务器的负担,因为真实的空间和流量均是来自别人的服务器 防盗链概念: 防止别人通过一些技术手段绕过本站的资源展示页面,盗用本站的资源,让绕开本站资源展示页面的资源链接失效 可以大大减轻服务器及带宽的压力 ### 工作原理: 通过Referer或者签名,网站可以检测目标网页访问的来源网页,如果是资源文件,则可以跟踪到显示它的网页地址。 一旦检测到来源不是本站即进行组织或者返回指定的页面 通过计算签名的方式,判断请求是否合法,如果合法则显示,否则返回错误信息。 ### 防盗链的实现方法 Referer Nginx模块 ngx_http_referer_module用来阻挡来源非法的域名请求: Nginx指令 valid_referers, 全局变量$invalid_referer valid_referers none|blocked|server_names|string...; none: "Referer"来源头部为空的情况 blocked: "Referer"来源头部不为空,但是里面的值被代理或者防火墙删除了,这些值都不以http://或者https://开头 server_names:"Referer"来源头部包含当前的server_names 代码实例... ``` location ~ .*\.(gif|jpg|png|flv|swf|rar|zip)&{ valid_referers none blocked imooc.com *.imooc.com; if($invalid_referer) { #return 403; rewrite ^/ http://www.imooc.com/403.jpg; } } ``` ### 传统防盗链遇到的问题 伪造Referer:可以使用加密签名解决 加密签名: 使用第三方模块HttpAccessKeyModule实现Nginx防盗链。 accesskey on|off 模块开关 accesskey_hashmethod md5|sha-1 签名加密方式 accesskey_arg GET参数名称 accesskey_signature 加密规则 代码实例: ``` location ~ .*\.(gif|jpg|png|flv|swf|rar|zip)$ { accesskey on; accesskey_hashmethod md5; accesskey_arg "key"; accesskey_signature "mypass$remote_addr"; } ``` ``` <?php $sign = md5('jason'.$_SERVER['REMOTE_ADDR']); echo '<img src="./long_new.png?sign="' . $sign . '>'; ``` ## 9-3 减少HTTP请求 ## 相关概念: - 为什么要减少HTTP请求 - 减少HTTP请求的方式 ### 为什么要减少HTTP请求 性能黄金法则 只有10%-20%的最终用户响应时间花在接收请求的HTML文档上,剩下的80%-90%时间花在HTML文档所引用的所有组件(图片, script, css, flash等等)进行的HTTP请求上。 如何改善 改善响应时间的最简单途径就是减少组件的数量,并由此减少HTTP请求的数量 HTTP连接产生的开销 域名解析-TCP连接-发送请求-等待-下载资源-解析时间 疑问? - DNS缓存 - Keep-Alive 打破谣言 - 查找DNS缓存也需要时间,多个缓存就要查找多次有可能缓存会被清除 - HTTP1.1协议规定请求只能串行发送,也就是说一百个请求必须依次逐个发送,签名的一个请求完成才能开始下个请求 ### 减少HTTP请求的方式 1. 图片地图 图片地图允许你在一个图片上关联多个URL,目标URL的选择取决于用户单击了图片上的哪个位置。 我们可以通过使用五个分开的图片,然后每个图片对应一个超链接。产生了5个HTTP请求,我们的目标是要减少HTTP请求。将五个图片合并为一张图片,然后以位置信息定位超链接。把HTTP请求减少为一个,可以保证设计的完整性和功能的齐全性。 http://stevesouders.com/hpws/imagemap-no.php 2. CSS Sprites CSS Sprites中文的意思是CSS精灵,通过使用合并图片,通过指定CSS的 background-image 和 background-position 来显示元素。 background-position 属性: background-position: x, y; x和y可以写负值也可以写正值,我们可以想象图片的左上方为(0,0),以(0,0)左边向右是为负数的x轴,以(0,0)坐标向下是负数的y轴。 性能影响:图片地图与CSS精灵的响应时间基本上相同,但比使用各自独立图片的方式要快50%以上。 3. 合并脚本和样式表文件 使用外部的JS和CSS文件引用的方式,因为这要比直接写在页面中性能要更好一点。 独立的一个js比用多个js文件组成的页面载入要快38%。 4. 图片使用Base64编码减少页面请求数 采用Base64的编码方式将图片直接嵌入到网页中,而不是从外部载入。 <img src="data:image/gif;base64,/9j/4AAQSkZJ..."> ## 9-4 浏览器缓存和压缩优化技术 ## 相关概念: - HTTP缓存机制 - Nginx配置缓存策略 - 前端代码和资源的压缩 ### HTTP缓存机制 高并发下只能通过提升服务器负载解决? 缓存只能做数据库缓存吗? 启用浏览器缓存 缓存分类: HTTP缓存模型中,如果请求成功会有3种情况 - 200 from cache:直接从本地缓存中获取响应,最快速,最省流量,因为根本没有向服务器发送请求 - 304 Not Modified:协商缓存,浏览器在本地没有命中的情况下请求头中发送一定的校验数据到服务端,如果服务端数据没有改变浏览器从本地缓存响应,返回304。 快速,发送的数据很少,只返回一些基本的响应头信息,数据量很小,不发送实际响应体。 - 200 OK:以上两种缓存全部都失败,服务器返回完整响应。没有用到缓存,相对最慢。 本地缓存: 浏览器认为本地缓存可以使用,不会去请求服务端。 相关Header: Pragma:Http1.0时代的遗留产物,该字段被设置为no-cache时,会告知浏览器禁用本地缓存,即每次都向服务器发送请求。 Expires:HTTP1.0时代用来启用本地缓存的字段,expires值对应一个形如Thu, 31 Dec 2037 23:55:55 GMT的格林威治时间,告诉浏览器缓存实现的时刻,如果还没到该时刻,标明缓存有效,无需发送请求。 浏览器与服务器的时间无法保持一致,如果时间差距大,就会影响缓存结果。 Cache-Control:HTTP1.1针对Expires时间不一致的解决方案,运用Cache-Control告知浏览器缓存过期的时间间隔而不是时刻,即使具体时间不一致,也不影响缓存的管理。 - no-store:禁止浏览器缓存响应 - no-cache:不允许直接使用本地缓存,先发起请求和服务器协商 - max-age=delta-seconds:告知浏览器该响应本地缓存有效的最长期限,以秒为单位 优先级:Pragma>Cache-Control>Expires 协商缓存: 当浏览器没有命中本地缓存,如本地缓存过期或者响应中声明不允许直接使用本地缓存,那么浏览器肯定会发起服务端请求。 服务端会验证数据是否修改,如果没有通知浏览器使用本地缓存 相关Header Last-Modified:通知浏览器资源的最后修改时间 Last-Modified:Mon, 28 Sep 2015 08:06:43 GMT If-Modified-Since:得到资源的最后修改时间后,会将这个信息通过If-Modified-Since提交到服务器做检查,如果没有修改,返回304状态码 ETag:HTTP1.1推出,文件的指纹标识符,如果文件内容修改,指纹会改变 ETag:"78437822c-6739" If-None-Match:本地缓存失效,会携带此值去请求服务端,服务端判断该资源是否改变,如果没有改变,直接使用本地缓存,返回304 ### 缓存策略的选择 适合缓存的内容: - 不变的图像,如LOGO、图标等 - js, css静态文件 - 可下载的内容,媒体文件 建议使用协商缓存: - HTML文件 - 经常替换的图片 - 经常修改的JS,CSS文件 - js, css文件的加载可以加入文件的签名来拒绝缓存 - index.css?签名 - index.签名.js 不建议缓存的内容: - 用户隐私等敏感数据 - 经常改变的api接口数据 ### Nginx配置缓存策略 本地缓存配置: - add_header指令:添加状态码为2XX和3XX的响应头信息; - add_header name value [always]; - 可以设置Pragma/Expires/Cache-Control,可以继承; - expires指令:通知浏览器过期时长 - expires time:为负值时表示Cache-Control: no-cache; 当为正或者0时,就表示Cache-Control: max-age=指定的时间; 当为max时,会把Expires设置为:"Thu, 31 Dec 2037 23:55:55 GMT",Cache-Control设置到10年; ### 前端代码和资源的压缩 优势: 让资源文件更小,加快文件在网络中的传输,让网页更快的展现,降低带宽和流量开销。 压缩方式: - JS, CSS, 图片, HTML代码的压缩 - Gzip压缩 JavaScript代码压缩: - JavaScript压缩的原理一般是去掉多余的空格和回车,替换长变量名,简化一些代码写法等; - JavaScript代码压缩工具很多,有在线工具,有应用程序,有编辑器插件等 - 常用压缩工具:UglifyJS, YUI Compressor, Closure Compiler - UglifyJS代码压缩:压缩、语法检查、美化代码、代码缩减、转化 - YUI Compressor:来自Yahoo,只有压缩功能 - Closure Compiler:来自Google,功能和UglifyJS类似,压缩的方式不一样 CSS代码压缩: - 原理跟JavaScript压缩原理类似,同样是取出空白符,注释并且优化一些CSS语义规则等 - 常用压缩工具:YUI Compressor,CSS Compressor - CSS Compressor:压缩时可以选择模式 HTML代码压缩: - 不建议使用代码压缩,有时会破坏代码结构,可以使用Gzip压缩,当然也可以使用htmlcompressor工具,不过转换后一定要检查代码结构 图片压缩: - 除了代码的压缩外,有时对图片的压缩也是很有必要的,一般情况下,图片在Web系统的比重都比较大。 - 压缩工具:tinypng, JpegMini, ImageOptim Nginx配置: - gzip on|off:#是否开启gzip - gzip_buffers 32 4k|16 8k #缓冲(在内存中缓冲几块?每块多大) - gzip_comp_level[1-9] #推荐6 压缩界别(级别越高,压的越小,越浪费CPU计算资源) - gzip_disabled #正则匹配UA 什么样的URL不进行gzip - gzip_min_length 200 #开始压缩的最小长度 - gzip_http_version 1.0|1.1 #开始压缩的http协议版本 - gzip_proxied #设置请求者代理服务器,该如何缓存内容 - gzip_types text/palin application/xml #对哪些类型的文件用压缩 如txt,xml,html,css - gzip_vary on|off #是否传输gzip压缩标志 ![Nginx配置](./img/01.jpg) 其他工具: - 自动化构建工具Grunt ## 9-5 CDN加速 ## 相关概念: - 什么是CDN - 使用CDN的优势 - CDN的工作原理 - CDN的适用场景 - CDN的实现 ### 什么是CDN CDN的全称是Content Delivery Network,即内容分发网络。尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快,更稳定。 在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络。 CDN系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上 ### 使用CDN的优势 本地Cache加速,提高了企业站点(尤其含有大量图片和静态页面站点)的访问速度 跨运营商的网络加速,保证不同网络的用户都能够得到良好的访问质量 远程访问用户根据DNS负载均衡技术只能选择Cache服务器 自动生成服务器的远程Mirror(镜像)cache服务器,远程用户访问时从cache服务器上读取数据,减少远程访问的带宽,分担网络流量、减轻原站点WEB服务器负载等功能 广泛分布的CDN节点加上节点之间的只能冗余机制,可以有效地预防黑客入侵 ### CDN的工作原理 传统访问: 用户在浏览器输入域名发起请求 - 解析域名获取服务器IP地址 - 根据IP地址找到对应的服务器 - 服务器响应并返回数据 使用CDN访问: 用户发起请求 - 智能DNS的解析(根据IP判断地理位置,接入网类型,选择路由最短和负载最轻的服务器) - 取得缓存服务器IP - 把内容返回给用户(如果缓存中有) - 向源站发起请求 - 将结果返回给用户 - 将结果存入缓存服务器 ![CDN的工作原理](./img/02.jpg) ### CDN的适用场景 - 站点或者应用中大量静态资源的加速分发,例如:CSS, JS, 图片和HTML - 大文件下载 - 直播网站等 ### CDN的实现 - BAT等都有提供CDN服务 - 可用LVS做4层负载均衡 - 可用Nginx,Varnish,Squid,Apache Traffic Server做7层负载均衡和Cache - 使用squid反向代理或者Nginx等的反向代理 ## 9-6 建立独立的图片服务器 ## 相关概念: - 独立的必要性 - 采用独立域名 - 独立后的问题 ### 独立的必要性 - 分担Web服务器的I/O负载-将耗费资源的图片服务分离出来,提高服务器的性能和稳定性 - 能够专门对图片服务器进行优化-为图片服务设置有针对性的缓存方案,减少带宽成本,提高访问速度 - 提高网站的可扩展性:通过增加图片服务器,提高图片吞吐能力 ### 采用独立域名 同一域名下浏览器的并发连接数有限制,突破浏览器连接数的限制由于cookie的原因,对缓存不利,大部分「Web Cache」都只缓存不带cookie的请求,导致每次的图片请求都不能命中cache。 ### 独立后的问题 - 如何进行图片上传和图片同步 - NFS共享方式 ## 9-7 动态语言静态化 ## 相关概念: - 什么是动态语言静态化 - 为什么要静态化 - 静态化的实现方式 ### 什么是动态语言静态化 - 将现有PHP等动态语言的逻辑代码生成为静态HTML文件,用户访问动态脚本重定向到静态HTML文件的过程。 - 对实时性要求不高的页面。 ### 为什么要静态化 - 动态脚本通常会做逻辑计算和数据查询,访问量越大,服务器压力越大 - 访问量大时可能会造成CPU负载过高,数据库服务器压力过大 - 静态化可以减低逻辑处理压力,降低数据库服务器查询压力 ### 静态化的实现方式 使用模板引擎: 可以使用Smarty的缓存机制生成静态HTML缓存文件。 ``` $smarty->cache_dir = $ROOT."/cache"; //缓存目录 $smarty->cache = true; //是否开启缓存 $smarty->cache_lifetime = "3600"; //缓存时间 $smarty->display(string template[, string cache_id[, string compile_id]]); $smarty->clear_all_cache(); //清除所有缓存 $smarty->clear_cache('file.html); //清除指定的缓存 $smarty->clear_cache('article.html',$art_id); //清除同一个模板下的指定缓存号的缓存 ``` 利用ob系列的函数: ``` ob_start() 打开输出控制缓存 ob_get_contents() 返回输出缓冲区内容 ob_clean() 清空输出缓冲区 ob_end_flush() 冲刷出(送出)输出缓冲区内容并关闭缓冲 ``` 可以判断文件的inode修改时间,判断是否过期,使用filectime函数 ## 9-8 动态语言层的并发处理 ## 相关概念: - 什么是进程、线程、协程 - 什么是多进程、多线程 - 同步阻塞模型 - 异步非阻塞模型 - PHP并发编程实践 ### 什么是进程、线程、协程 - 进程是计算机中的程序关于某数据集合上的一次运行获得,是系统进行资源分配和调度的基本单位,是操作系统机构的基础。 - 进程是一个执行中的程序。 - 进程的三态模型:多道程序系统中,进程在处理器上交替运行,状态不断的发生变化:运行、就绪、阻塞 - 运行:当一个进程在处理机上运行时,则称该进程处于运行状态。处于此状态的进程的数目小于等于处理器的数目,对于单处理机系统,处于运行状态的进程只有一个。在没有其它进程可以执行时(如所有进程都在阻塞状态),通常会自动执行系统的空闲进程。 - 就绪:当一个进程获得了除处理机以外的一切所需资源,一旦得到处理机即可运行,则称此进程处于就绪状态。就绪状态可以按多个优先级来划分队列。例如当一个进程由于时间片用完而进入就绪状态时,排入低优先级队列;当进程由I/O操作完成而进入就绪状态时,排入高优先级队列。 - 阻塞:也称为等待或睡眠状态,一个进程正在等待某一事件发生(例如请求I/O而等待I/O完成等)而暂时停止运行,这时即使把处理机分配给进程也无法运行,故称该进程处于阻塞状态。 进程的五态模型:对于一个实际的系统,进程的状态及其转换更为复杂。 新建态、活跃就绪/静止就绪、运行、活跃阻塞/禁止阻塞、终止态 - 新建态:对于进程刚刚被创建时没有被提交的状态,并等待系统完成创建进程的所有必要信息。 - 终止态:进程已结束运行,回收除进程控制块之外的其它资源,并让其它进程从进程块中收集有关信息。 - 活跃就绪:是指进程在主存并且可被调度的状态。 - 静止就绪(挂起就绪):是指进程被对换到辅存时的就绪状态,是不能被直接调度的状态,只有当主存中没有活跃就绪态进程,或者是挂起就绪态进程具有更高的优先级,系统将把挂起就绪态进程调回主存并转换为活跃就绪。 - 活跃阻塞:是指进程已在主存,一旦等待的事件产生便进入活跃就绪状态。 - 静止阻塞:进程对换到辅存时的阻塞状态,一旦等待的事件产生便进入静止就绪状态。 用户用户的并发请求,为每一个请求都创建一个进程显然是行不通的,从系统资源开销方面或是响应用户请求的效率方面来看。因此操作系统中线程的概念便被引进了。 线程,有时被称为轻量级进程,是程序执行流的最小单元。 线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源。但它可与同属一个进程的其它线程共享进程所拥有的全部资源。 一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行。 线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。 在单个程序中同时运行多个线程完成不同的工作,称为多线程。 每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。 线程的状态:就绪、阻塞、运行 就绪状态:线程具备运行的所有条件,逻辑上可以运行,在等待处理机。 运行状态:线程占有处理机正在运行。 阻塞状态:线程在等待一个事件(如某个信号量),逻辑上不可执行。 协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。 线程与进程的区别: 线程与协程的区别: ### 什么是多进程、多线程 ### 同步阻塞模型 ### 异步非阻塞模型 ### PHP并发编程实践 ## 9-9 数据库缓存层的优化 ## 相关概念: - 什么是数据库缓存 - 为什么要使用缓存 - 使用MySQL查询缓存 - 使用Memcache缓存 - 使用Redis缓存 ## 9-10 Mysql数据层的优化 ## ## 9-11 Web服务器的负载均衡、请求分发 ##