PHP面试-复习知识点整理

2022-07-11 11:45:21 浏览数 (1)

大家好,又见面了,我是全栈君。

false的七种情况

  1. 整型0
  2. 浮点0.0
  3. 布尔false
  4. 空字符串”,””
  5. 字符串’0′
  6. 空数组[]
  7. NULL

超全局数组

  1. $GLOBALS,包含下面8个超全局数组的值
  2. $_GET
  3. $_POST
  4. _REQUERT,包含_GET,_POST,_COOKIE
  5. $_SEESION
  6. $_COOKIE
  7. $_SERVER
代码语言:javascript复制
$_SERVER['SERVER_ADDR'] //服务器地址
$_SERVER['SERVER_NAME'] //服务名称
$_SERVER['REQUEST_TIME'] //请求时间
$_SERVER['QUERY_STRING'] //请求地址中问号后的内容
$_SERVER['HTTP_REFERER'] //上次请求地址
$_SERVER['HTTP_USER_AGENT'] //浏览器信息
$_SERVER['REMOTE_ARRR'] //客户端请求ip
$_SERVER['REQUEST_URI'] // 请求中脚本名称
$_SERVER['PATH_INFO'] // 请求中路径
  1. $_FIELS
  2. $_ENV

null的三种情况

  1. 直接赋值NULL
  2. 未定义变量
  3. unset销毁后的变量

常量

一定定义,不可删除和修改

  1. const 更快,是语言结构,可定义类常量
  2. define 是函数

预定义常量

  1. FILE 文件所在路径 文件名
  2. LINE 所在代码行
  3. DIR 所在文件夹路径
  4. FUNCTION 方法名
  5. CLASS 类名
  6. TRAIT TRAIT的名称
  7. METHOD 类名 方法名
  8. NAMESPACE 命名空间名

引用变量

用不同名字访问同一个变量内容,用『&』符号表示

抽象类和接口

抽象类:

  1. 定义为抽象的类不能被实例化.
  2. 任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的。
  3. 被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现。
  4. 继承一个抽象类的时候,子类必须定义父类中的所有抽象方法;另外,这些方法的访问控制必须和父类中一样(或者更为宽松)。
  5. 例如某个抽象方法被声明为受保护的,那么子类中实现的方法就应该声明为受保护的或者公有的,而不能定义为私有的。此外方法的调用方式必须匹配,即类型和所需参数数量必须一致。例如,子类定义了一个可选参数,而父类抽象方法的声明里没有,则两者的声明并无冲突。
  6. 这也适用于 PHP 5.4 起的构造函数。在 PHP 5.4 之前的构造函数声明可以不一样的.

接口:

  1. 使用接口(interface),可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容。
  2. 接口是通过 interface 关键字来定义的,就像定义一个标准的类一样,但其中定义所有的方法都是空的。
  3. 接口中定义的所有方法都必须是公有,这是接口的特性。
  4. 要实现一个接口,使用 implements 操作符。类中必须实现接口中定义的所有方法,否则会报一个致命错误。类可以实现多个接口,用逗号来分隔多个接口的名称。
  5. 实现多个接口时,接口中的方法不能有重名。
  6. 接口也可以继承,通过使用extends操作符.
  7. 类要实现接口,必须使用和接口中所定义的方法完全一致的方式。否则会导致致命错误.

区别:

  1. 对接口的继承使用implements,抽象类使用extends.
  2. 接口中不可以声明变量,但可以声明类常量.抽象类中可以声明各种变量
  3. 接口没有构造函数,抽象类可以有
  4. 接口中的方法默认为public,抽象类中的方法可以用public,protected,private修饰
  5. 一个类可以继承多个接口,但只能继承一个抽象类

运算符优先级

优先级由高到低排序

  1. ==递增/递减==
  2. 非(!)
  3. ==算术运算符==
  4. ==大小比较==
  5. (不)相等比较
  6. 引用
  7. 位运算符(^)
  8. 位运算符(|)
  9. ==逻辑与==
  10. ==逻辑或==
  11. ==三目==
  12. ==赋值==
  13. and
  14. oxr
  15. or

浮点数值得精度丢失问题

原因:因为计算机存储是二进制,准换进制时会有精度丢失

解决方案:先将浮点字符串化,再进行整数获取,输出可通过print

代码语言:javascript复制
$f = 0.57;
$f = $f * 100;
// 输入可通过print
print('%d', $f);

// 用于存储或二次计算,先将浮点字符串化,再进行整数获取
$f = strval($f);
var_dump($f);
echo floor($f);
echo intval($f);
echo (int)($f);

switch 只能判断整型、浮点、字符

变量类型

  1. 普通变量
  2. 全局变量,通过 global 定义,可以在局部域调用全局变量,可通过 $_GLOBAL['XXX'] 读取变量的值
  3. 静态变量,通过 static 定义,仅在局部域中存在,执行函数离开作用域,其值也不会消失

ip处理函数

  1. ip2long()
  2. long2ip()

时间日期处理函数

  1. date()
  2. strtotime()
  3. mktime()
  4. time()
  5. microtime()
  6. date_default_timezone_set()

打印处理

  1. print() 仅输出单个变量
  2. printf() 按格式输出
  3. print_r() 格式化输出
  4. echo 输出多个变量
  5. sprintf() 按格式返回
  6. var_dump() 格式化输出,并输出变量类型
  7. var_export() 将格式化输出,加true可返回,返回内容可直接做变量使用

序列化

  1. serialize()
  2. unserialize()

字符串处理

  1. implode(),join()
  2. explode()
  3. strrev() 反转字符
  4. trim(),ltrim(),rtrim()
  5. strstr() 获取第一次出现指定字符串的字符串
  6. number_format() 数字格式化为金钱格式

数组处理

  1. array_keys()
  2. array_values()
  3. array_diff()
  4. array_megre()
  5. array_shift()
  6. array_unshift()
  7. array_pop()
  8. array_push()
  9. sort(), rsort() 对数组升降序排序
  10. asort(),arsort() 对数组键值升降序排序
  11. ksort(),krsort() 对数组键名升降序排序

文件操作

fopen() 打开文件并指定模式

  1. r/r 只读打开/读写打开,指针在文件开头
  2. w/w 只写打开/读写打开,文件存在会清空,不存在会创建
  3. a/a 写入追加写入/读写的追加写入,指针在文件末尾
  4. x/x 写入/读写打开,指针开头,文件存在返回false,不存在就直接创建
  5. b 二进制打开

写入

  1. fwrite()
  2. fputs()

读取

  1. fread() 获取指定长度字符
  2. fgets() 获取一行字符
  3. fgetc() 获取一个字符

关闭 fopen()

文件大小 filesize()

文件复制 copy()

文件删除 unlink()

文件类型 filetype()

重命名或移动 rename()

文件属性

  1. file_exist()
  2. is_readable()
  3. is_writable()
  4. is_executable()
  5. filectime() 创建时间
  6. fileatime() 访问时间
  7. filemtime() 更新时间

其他不需要fopen()打开的函数

  1. file_get_contents()
  2. file_put_contents()

其他

  1. file()整个文件内容按行读取到一个数组里
  2. readfile()整个文件读取出来,并输出

远程访问

php.ini 中打开 allow_url_fopen 配置,http协议只能使用只读,ftp协议,只能只读或只写

目录操作

名称相关

  1. basename() 文件基础名称
  2. dirname() 文件夹名称
  3. pathinfo() 文件信息数组

目录读取

  1. opendir()
  2. readdir()
  3. closedir()
  4. rewinddir() 重置句柄
  5. disk_free_space()
  6. disk_total_space()

目录删除 rmdir()

目录必须为空

目录创建 mkdir()

重命名或移动 rename()

设计模式

  1. 工厂模式
  2. 单例模式
  3. 适配器模式
  4. 观察者模式
  5. 策略模式
  6. 注册树模式

魔术方法

  1. __construct()
  2. __destruct()
  3. __call()
  4. __callStatic()
  5. __get()
  6. __set()
  7. __isset()
  8. __unset()
  9. __sleep()
  10. __wakeup()
  11. __toString()
  12. __close()

网络协议

http状态码

  1. 200 请求成功
  2. 204 not content
  3. 206 reset content
  4. 301 永久重定向
  5. 302 临时重定向
  6. 307 临时重定向
  7. 400 错误请求
  8. 401 缺少认证信息
  9. 403 拒绝
  10. 404 不存在
  11. 500 服务器异常
  12. 502 Bad Gateway
  13. 503 服务器超负载或停机维护

OSI七层协议

  1. 物理层 建立、维护、断开物理连接
  2. 数据链路层 建立逻辑连接,进行硬件地址寻址,差错校验等功能
  3. 网络层 进行逻辑地址寻址,师兄不同网络之间的路径选择
  4. 传输层 定义传输数据的协议端口号,一级流控和差错校验。协议有TCP/UDP,数据包一旦离开网卡即进入网络传输层
  5. 会话层 建立、管理、终止会话
  6. 表示层 数据的表示、安全、压缩
  7. 应用层 网络服务与最终用户的一个借口,协议有:http(80),ftp(21),tftp,smtp(25),snmp,dns(53),telnet(23),https(443),pop3(110),dhcp

HTTP协议的工作特点和工作原理

工作特点:

  1. 基于B/S模式
  2. 通信开销小,简单快速,传输成本低
  3. 使用灵活,可使用超文本传输协议
  4. 节省传输时间
  5. 无状态

工作原理:

客户端发送请求给服务器,建立一个TCP连接,指定端口号,默认80,连接到服务器,服务器监听到浏览器的请求,一旦监听到客户端的请求,分析请求类型后,服务器会向客户端发送状态信息和数据内容

HTTP协议常见请求头/响应头

  1. Content-Type 指定数据内容类型
  2. Accept 指定客户端能接受数据内容类型
  3. Origin 最初请求来源(POST)
  4. Cookie
  5. Cache-Control 指定请求的缓存机制
  6. User-Agent 用户浏览器信息
  7. Referrer 上级请求路径
  8. X-Forwarded-For 请求端真实ip
  9. Access-Control-Allow-Origin 允许其他请求域名,用于跨域
  10. Last-Modified 最后响应时间

HTTPS的工作原理

HTTPS是一种基于SSL/TLS的HTTP协议,所有的HTTP数据都是SSL/TLS协议封装之上传输的

HTTPS是在HTTP协议的基础上,添加了SSL/TLS握手一级数据加密传输,也属于应用层协议

mysql相关知识

数据表引擎

  1. innodb引擎

默认事务型引擎,最重要最广泛的存储引擎,性能非常优秀

数据存储在共享表空间,可通过配置分开

对主键查询的性能高于其他类型的存储引擎

内部做了很多优化,从磁盘读取数据时自动在内存构建hash索引,插入数据时自动构建插入缓冲区

通过一些机制和工具支持真正的热备份

支持崩溃后的安全恢复

支持行级锁

支持外键

  1. MyISAM引擎

5.1版本前是默认引擎

拥有全文索引、压缩、空间函数

不支持事务和行级锁,不支持奔溃后安全恢复

表存储在两个文件,MYD和MYI

设计简单,某些场景下性能很好

  1. 其他引擎:

Archive、Blackhole、CSV、Memory

MySQL锁机制

当多个查询同一时刻进行数据修改时,会产生并发控制的问题

  1. 共享锁(读锁)
  2. 排他锁(写锁)

锁粒度

  1. 表锁

系统性能开销最小,会锁定整张表,myisam使用表锁

  1. 行锁

最大程度的支持并发处理,但是也带来了最大的锁开销,innodb实现行级锁

char与varchar

  1. char
代码语言:javascript复制
char是定长的,根据定义的字符串长度分配足量空间
char会根据需要采用空格进行填充以方便比较
char适合存储很短的字符串,或者所有值都接近同一个长度
char长度超过设定的长度,会被截断
  1. varchar
代码语言:javascript复制
varchar用于存储可变长字符串,比定长类型更加节省空间
varchar使用1或2个额外字节记录字符串的长度,列长度小于255字节用1个字节表示,否则用2个
varchar长度超过设定的长度,会被截断
  1. 比较
代码语言:javascript复制
对于经常变更的数据,char比varchar更好,char不容易产生碎片
对于非常短的列,char比varchar在存储空间上更有效率
只分配真正需要的空间,更长的列会消耗更多的内存

索引

  1. 大大减少服务器需要扫描的数据量
  2. 帮助服务器避免排序和临时表
  3. 将随机I/O变顺序I/O
  4. 大大提高查询速度,降低写的速度,占用磁盘空间
索引类型
  1. 普通索引
  2. 主键索引
  3. 唯一索引
  4. 组合索引
  5. 外键索引
  6. 全文索引

索引创建原则

  1. 最适合索引的列是出现在where子句的列,或连接子句中的列,而不是出现在select的关键字后的列
  2. 索引列的基数越大,索引效果越好
  3. 对字符串进行索引,应指定一个前缀长度,可以节省大量的索引空间
  4. 根据情况创建复合索引,复合索引可以提高查询效率
  5. 避免创建过多索引,索引会额外占用磁盘空间,减低写操作效率
  6. 主键尽可能选择较短的数据类型,可以有效减少索引的磁盘占用,提高效率

索引的注意事项

  1. 复合索引遵循前缀原则
  2. like查询,%不能在前,可以使用全文索引
  3. column is null 可以使用索引
  4. 如果MySQL估计使用索引比全表扫描更慢,会放弃使用索引

mysql优化

查询速度慢的原因

  1. 打开慢查询日志,通过pt-query-dugest分析
  2. show profile,通过 set profiling=1; 开启,服务器上执行的所有语句消耗时间都会记录到临时表。 show profile for query QUERY_ID 查询指定查询
  3. show status,查询一些计数器,猜出哪些代价高或消耗时间多
  4. show processlist,查询线程状态进行分析
  5. explain,分析单个SQL语句查询

优化查询过程中的数据访问

  1. 访问数据太多导致性能下降
  2. 确定应用程序是否检索大量超过需要的数据,可能是太多列或者行
  3. 确定mysql是否分析大量不必要的数据行
  4. 查询不需要的记录,使用limit限制
  5. 夺标关联返回全部列指定A.id,A.name
  6. 总数取出全部列,select * 会让优化器无法完成所有覆盖扫码的优化
  7. 重复查询相同的数据,可以缓存数据
  8. 改变数据库和表的结构,修改数据表范式
  9. 重写SQL语句,让优化器可以更优的执行

优化长难得查询语句

  1. MySQL内部每秒能扫描内存中上百万行数据,相比之下,响应数据给客户端就要慢得多
  2. 使用尽可能少的查询是好的,但是有时将一个大的查询分解为多个小的查询是很有必要的
  3. 分解关联查询,将一个关联查询分解为多个sql来执行,让缓存效率更高,执行单个查询可以减少锁的竞争,在应用层做关联可以更容易对数据库进行拆分,查询效率会有大幅提升,较少冗余记录的查询

优化特定类型的查询语句

  1. 优化count()查询, count(*) 会忽略所有列,直接统计所有列数,因此不要用 count(列名)
  2. 优化关联查询,确定ON或者USING子句的列上有索引;确保 GROUP BYORDER BY 中只有一个表的列,这样MySQL才有可能使用索引
  3. 优化子查询 建议使用关联查询替代
  4. 优化 GROUP BYDISTINCT ,建立索引进行优化
  5. 优化 LIMIT 分页,可以通过记录上次查询的最大ID,如果根据id排序时,下次查询根据该ID来查询(如:ID > maxID)
  6. 优化 UNION 查询, UNION ALL 性能比 UNION

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. 水平切分:表很大,分割后可以减低在查询时需要读的数据和索引的页数,同时也减低了索引的层数,提高查询速度
代码语言:javascript复制
使用场景:
1. 表中数据本身就有独立性,例如表中分别记录各个地区的数据或者不同时期的数据,特别是有些数据常用,有些不常用
2. 需要把数据存放在多个介质

缺点:
1. 给应用增加复杂度,通常查询时需要多个表名,查询所有数据都需要UNION操作
2. 在许多数据库应用中,这种复杂性会超过他带来的优点,查询时会增加读一个索引层的磁盘次数
  1. 垂直分表:把主键和一些列放在一个表,然后把主键和另外的列放在另一张表中
代码语言:javascript复制
使用场景:
1. 如果一个表中某些列常用,而另外一些列不常用
2. 可以使数据行变小,一个数据页能存储更多数据,查询时减少I/O次数

缺点:
1. 管理冗余列,查询所有数据需要JOIN操作
2. 有些分表的策略基于应用层的逻辑算法,一旦逻辑算法改变,整个分表逻辑都会改变,扩展性较差
3. 对于应用层来说,逻辑算法无疑增加开发成本

主从复制

工作原理
  1. 在主库上把数据更改记录到二进制日志
  2. 从库将主库的日志复制到自己的中继日志
  3. 从库读取中继日志中的事件,将其重放到从库数据中
解决问题
  1. 数据分布:随意停止或开始复制,并在不同地理位置分布数据备份
  2. 负载均衡:减低单个服务器压力
  3. 高可用和故障切换:帮助应用程序避免单点失败
  4. 升级测试:可以使用更高版本的MySQL作为从库

MySQL安全

安全操作

  1. 使用预处理语句防SQL这几日
  2. 写入数据库的数据要进行特殊字符转移
  3. 查询错误信息不要返回给用户,将错误记录到日志

安全设置

  1. 定期做数据备份
  2. 不给查询用户root权限,合理分配权限
  3. 关闭远程访问数据库权限
  4. 修改root口令,不用默认口令,使用较复杂的口令
  5. 删除多余的用户
  6. 改变root用户的名称
  7. 限制一般用户浏览其他库
  8. 限制用户对数据文件的访问权限

MVC

MVC工作原理

  1. model 数据模型操作层,是应用程序中用于处理应用程序数据逻辑的部分
  2. view 视图层,是应用程序中处理数据显示的部分。
  3. controller 业务处理层,是应用程序中处理用户交互的部分。

单一入口

工作原理

用一个处理程序文件处理所有的HTTP请求,根据请求时的参数的不同区分不同的模块和操作请求

优势

  1. 可以进行统一的安全性检查
  2. 集中处理程序

劣势

  1. URL不美观(解决方法:URL重写)
  2. 处理效率会降低(可忽略)

模板引擎

PHP是一种HTML内嵌式在服务端执行的脚本语言,但是PHP又很多可以使PHP代码和HTML代码分开的模板引擎,例如:smarty

工作原理

模板引擎就是庞大的完善的正则表达式替换库

算法

排序算法

冒泡排序

原理:两两相邻的数进行比较,如果反序就交换,否则不交换

时间复杂度:最坏(O(n^2)), 平均(O(n^2))

空间复杂度:O(1)

快速排序

原理:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据和另一部分的所有数据都要笑,然后按照此方法对这两部分数据分别进行快速排序,整个排序过程可以递归完成

时间复杂度:最坏(O(n^2)), 平均(O(nlog2n))

空间复杂度:最差(O(n)),平均(O(log2n))

直接插入排序

原理:每次从无序表中取出第一个元素,把他插入到有序表的合适位置,使有序表仍然有序

时间复杂度:最坏(O(n^2)), 平均(O(n^2))

空间复杂度:O(1)

选择排序

原理:每次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,知道全部待排序的数据元素排外

时间复杂度:最坏(O(n^2)), 平均(O(n^2))

空间复杂度:O(1)

希尔排序

原理:把待排序的数据根据增量分成几个子序列,对子序列进行插入排序,知道增量为1,直接插入进行插入排序;增量的排序,一般是数组的长度的一半,再变为原来增量的一半,直到增量为1

时间复杂度:最坏(O(n^2)), 平均(O(nlog2n))

空间复杂度:O(1)

堆排序

原理:把待排序的元素按照大小在二叉树位置上排序,排序好的元素要满足:父节点的元素要大于子节点;这个过程叫做堆化过程,如果根节点存放的最大的数,则叫做大根堆,如果是最小,就叫小跟堆,可以把根节点拿出来,然后再堆化,循环到最后一个节点

时间复杂度:最坏(O(nlog2n)), 平均(O(nlog2n))

空间复杂度:O(1)

归并排序

原理:将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个有序的子序列,再把有序的子序列合并为整体有序序列

时间复杂度:最坏(O(nlog2n)), 平均(O(nlog2n))

空间复杂度:O(n)

查找算法

二分查找

原理:从数组的中间元素开始,如果中间元素正好是要查找的元素,搜索结果,如果某一个特定元素大于或者小于中间元素的那一半中查找,而且跟开始一样从中间开始比较,如果某一步骤数组为空,代表找不到

时间复杂度:最坏(O(nlog2n)), 平均(O(nlog2n))

空间复杂度:迭代(O(1)), 递归(O(log2n))

顺序查找

原理:按一定的顺序检查数组中每一个元素,直到要找到锁要寻找的特定指为止

时间复杂度:最坏(O(n)), 平均(O(n))

空间复杂度:O(1)

优化

高并发和大流量解决方案

高并发的问题,应关注

  1. QPS:每秒钟请求或查询数量,在互联网领域指每秒响应的请求数(指HTTP请求)
  2. 吞吐量:单位时间内处理的请求数量(通常由QPS和并发数决定)
  3. 响应时间:从请求发出到收到响应花费时间
  4. PV:综合浏览量(Page View),即页面浏览量或者点击量,一个访客在24小时内访问的页面数量。同一个人浏览你的网站同一个页面,只记作一次PV
  5. UV:独立访客(UniQue Visitor),即一定时间范围内相同访客多次访问网站,只能计算为1个独立访客
  6. 带宽:计算带宽大小需关注两个指标,峰值流量和页面的平均大小
  7. 日网站带宽=PV/统计时间(秒) 平均页面大小(KB) 8
  8. 峰值一般是平均值的倍数
  9. QPS不等于并发并发连接数。QPS是每秒HTTP请求数量,并发连接数是系统同时处理的请求数量
  10. 二八定律(80%的访问量集中在20%的时间):(总PV数 80%)/(6小时秒速 20%)=峰值每秒请求数(QPS)
  11. 压力测试:能承受最大的并发数和最大承受的QPS值

常用性能测试工具

ab,wrk,Apache JMeter, http_load, Web Bench, Siege

ab
使用方法:
代码语言:javascript复制
# 模拟并发请求100次,总请求5000次
ab -c 100 -n 5000 http://example.com
注意事项:
  1. 测试机器与被测机器分开
  2. 不要对线上服务做压力测试
  3. 观察测试工具所在机器,以及被测试的前端机的CPU、内存、网络等都不超过最高限度的75%

QPS指标

  1. QPS达到50,可以称之为小型网站,一般服务器都可以应付
  2. QPS达到100;瓶颈:MySQL查询达到瓶颈;优化方案:数据库缓存层,数据库负载均衡
  3. QPS达到800;瓶颈:带宽速度达到瓶颈;优化方案:CDN加速,负载均衡
  4. QPS达到1000;瓶颈:缓存服务器的带宽达到瓶颈;优化方案:静态HTML缓存
  5. QPS达到2000;瓶颈:文件系统访问锁成为灾难;优化方案:做业务分离,分布式存储

高并发优化方案

流量优化
  1. 防盗链处理
前端优化
  1. 减少HTTP请求
  2. 添加异步请求
  3. 启用浏览器缓存和文件压缩
  4. CDN加速
  5. 建立独立的图片服务器
服务端优化
  1. 页面静态化
  2. 并发处理
数据库优化
  1. 数据库缓存
  2. 分库分表、分区操作
  3. 读写分离
  4. 负载均衡
web服务器优化
  1. 负载均衡

web资源防盗链

盗链定义

  1. 倒链是指在自己的页面上展示一些并不在服务器上的内容
  2. 获得他人服务器上的资源地址,绕过别人的资源展示页面,直接在自己的页面上向最终用户提供此内容
  3. 常见的是小站盗用大站的图片、音乐、视频、软件等资源
  4. 倒链可以减轻自己的服务器负担

防盗链定义

防止别人通过一些技术手段绕过本站的资源展示页面,盗用本站的资源,让绕开本站资源展示页面的资源链接失效,可以大大减轻服务器及带宽的压力

防盗链的工作原理

  1. 通过Referer或者计算签名,网站可以检测目标网页访问的来源网页,如果是资源文件,则可以跟踪到显示他的网页地址
  2. 一旦检测到来源不是本站即进行阻止或返回指定的页面

防盗链实现方法

Referer
  1. NGINX模块ngx_http_referer_module用来阻挡来源非法的域名请求
  2. NGINX指令valid_referers,全局变量$invalid_referer
配置:
代码语言:javascript复制
valid_referers none|blocked|server_names|string...;
  1. none: Referer来源头部为空的情况,比如直接打开
  2. blocked: Referer来源头部不为空,但是里面的值被代理或者防火墙删除了,这些值都不以 http://或者https ://开头
  3. server_names: Referer来源头部包含当前的server_names

配置例子:

代码语言:javascript复制
location ~.*.(gif|jpg|png|flv|swf|rar}zip)$
{
  
  
    valid_referers none blocked imooc.com *.imooc.com;
    if ($invalid_referer)
    {
  
  
        #return 403;
        rewrite ^/ https://img.yuanmabao.com/zijie/pic/2022/07/11/mjvthpw4k1p.jpg;
    }
}

减少HTTP请求

HTTP连接产生的开销

  1. 域名解析
  2. TCP连接
  3. 发送请求
  4. 等待
  5. 下载资源
  6. 解析

解决方案

  1. 减少组件的数量,并由此减少HTTP请求的数量
  2. 图片地图:图片地图允许你在一个图片上关联多个URL。目标URL的选择取决于用户蛋鸡了图片上的哪个位置
  3. CSS Sprites:css 精灵,通过使用合并图片,通过指定css的background-image和background-position来显示元素
  4. 合并脚本和样式表适
  5. 图片使用base64编码减少页面请求数

浏览器缓存和数据压缩

HTTP缓存机制分类

  1. 200 from cache:直接从本地缓存中获取响应,最快速,最省流量,因为根本没有向服务器发送请求
  2. 304 Not Modified:协商缓存,浏览器在本地没有命中的情况下,请求头中发送一定的校验数据到服务端,如果服务端的数据没有改变,浏览器从本地缓存响应,返回304。特点:快速,发送的数据很少,只返回一些基本的响应头信息,数据量很小,不发送实际响应体
  3. 200 OK:以上两种缓存全部失败,服务器返回完整响应。没有用到缓存,相对最慢
header设置HTTP缓存机制
  1. pragma:HTTP1.0时代的遗留产物,该字段被设置为no-cache时,会告知浏览器禁用本地缓存,即每次都向服务器发送请求
  2. Expires:HTTP1.0时代用来启用本地缓存的字段,设置值如‘Thu, 31 Dec 2037 23:55:55 GMT’的格林威治的时间。但浏览器与服务器的时间无法保持一致,如果差距大就会影响缓存结果
  3. Cache-Control:HTTP1.1针对Expires时间不一致的解决方案,运用Cache-Control告知浏览器缓存过期的时间间隔而不是时刻,即使具体时间不一致,也不影响缓存的管理

优先级:Pragma > Cache-Control > Expires

Cache-Control配置
  1. no-store:禁止浏览器缓存响应
  2. no-cache:不允许直接使用本地缓存,先发起请求和服务器协商
  3. max-age=delta-seconds:告知浏览器该响应本缓存的有效的最长期限,以秒为单位

协商缓存

  1. 当浏览器没有命中本地缓存,如本地缓存过期或者响应中声名不允许直接使用本地缓存,那么浏览器肯定会发起服务端请求
  2. 服务端会验证数据是否修改,如果没有就通知浏览器使用本地缓存
header设置协商缓存
  1. Last-Modified:通知浏览器资源的最后修改时间,设置值如‘Thu, 31 Dec 2037 23:55:55 GMT’的格林威治的时间
  2. If-Modified-Since:得到资源的最后修改时间后,会将这个信息通过If-Modified-Since提交到服务器做检查,如果没有修改,返回304状态码,设置值如‘Thu, 31 Dec 2037 23:55:55 GMT’的格林威治的时间
  3. ETag:HTTP1.1推出,文件的指纹标识符,如果文件内容修改,指纹也会改变,设置值如‘5a643fc7-38a3’
  4. If-None-Match:本地缓存失效,会携带此值去请求服务端,服务端判断该资源是否改变,如果没有改变,直接使用本地缓存,返回304

缓存策略的选择

适合缓存的内容
  1. 不变的图像,如logo,图标等
  2. js、css静态文件
  3. 可下载的内容,媒体文件
适合协商缓存
  1. HTML文件
  2. 经常替换的图片
  3. 经常修改的js、css文件,js、css文件的加载可以加入文件的签名来拒绝缓存,如‘index.css?签名’,‘index.签名.js’
不建议缓存的内容
  1. 用户隐私等敏感数据
  2. 经常改变的API数据接口

NGINX配置缓存策略

本地缓存配置

代码语言:javascript复制
add_header name value [always];
expires time;
etag on|off

前端代码和资源压缩

优势

  1. 让资源文件更小,加快文件在网络中的传输,让网页更快的展现,降低带宽和流量的开销

压缩方式

  1. js、css、图片、html代码的压缩
  2. gzip压缩
gzip配置
代码语言:javascript复制
gzip on|off; #是否开启gzip
gzip_buffers 32 4K|16 8K; #缓冲(在内存中缓存几块?每块多大)
gzip_comp_level [1-9] #推荐6,压缩级别(级别越高,压得越小,越浪费CPU计算资源)
gzip_disable #正则匹配UA,什么样的Uri不进行gzip
gzip_min_length 200 #开始压缩的最小长度
gzip_http_version 1.0|1.1 #开始压缩的http协议版本
gzip_proxied #设置请求者代理服务器,该如何缓存内容
gzip_types text/plain application/xml image/png #对哪些类型的文件压缩,如txt、xml、css
gzip_vary on|off #是否传输gzip压缩标志

CDN加速

定义

  1. CDN的全称content delivery network,内容分发网络
  2. 尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定
  3. 在网络各处放置节点服务器所构成的有的互联网基础之上的一层智能虚拟网络
  4. CDN系统能够实现地根据网络流量和各节点的连接、负载状况以及到用户距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上

优势

  1. 本地cache加速,提高了企业站点(尤其含有大量图片和静态页面站点)的访问速度
  2. 跨运营商的网络加速,保证不同网络的用户都能得到良好的访问质量
  3. 远程访问用户根据DNS负载均衡技术只能选择cache服务器
  4. 自动生成服务器的远程Mirror(镜像)cache服务器,远程用户访问时从cache服务器上读取数据,减少远程访问的带宽、分担网络流量、减轻原站点web服务器负载等功能
  5. 广泛分布的cdn节点加上节点之间的智能冗余机制,可以有效地预防黑客入侵

工作原理

  1. 用户发起请求
  2. 智能DNS的解析(根据IP判断地理位置、接入网类型、选择路由最短和负载最轻的服务器)
  3. 取得缓存服务器ip
  4. 把内容返回给用户(如果缓存中有,没有就执行5、6、7)
  5. 向源站发起请求
  6. 将结果返回给用户
  7. 将结果存入缓存服务器

适用场景

  1. 站点或者应用中大量静态资源的加速分发,例如css、js、图片和HTML
  2. 大文件下载
  3. 直播网站

独立图片服务器

必要性

  1. 分担web服务器的I/O负载,将耗费资源的图片服务器分离出来,提高服务器的性能和稳定性
  2. 能够专门对图片服务器进行优化,为图片服务器设置针对性的缓存方案,减少带宽成本,提高访问速度
  3. 提高网站的可扩展性,通过增加图片服务器,提高图片吞吐能力

采用独立域名

原因:
  1. 同一域名下浏览器的并发连接数有限制,突破浏览器连接数的限制
  2. 由于cookie的原因,对缓存不利,大部分web cache都只缓存不带cookie的请求,导致每次的图片请求都不能命中cache

如何图片上传和同步

  1. NFS共享方式
  2. 利用FTP同步

动态语言静态化

将现有的PHP等动态语言的逻辑代码生成为静态的HTML文件,用户访问动态脚本重定向到静态HTML文件的过程。对实时性要求不高

原因:

  1. 动态脚本通过会做逻辑计算和数据查询,访问量越大,服务器压力越大
  2. 访问量大时可能会造成CPU负载过高,数据库服务器压力过大
  3. 静态化可以减低逻辑处理压力,降低数据库服务器查询压力

实现方法

  1. 使用模板引擎
  2. 利用ob系列函数
代码语言:javascript复制
ob_start();//打开输出控制缓冲
ob_get_content();//返回输出缓冲区内容
ob_clean();//清空输出缓冲区
ob_end_flush();//冲刷出(送出)输出缓冲区内容并关闭缓冲

并发处理

进程(Process)

是计算机中程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单元,是操作系统结构的基础。进程是一个执行中的程序

进程的三态模型:运行、就绪、阻塞

进程的五态模型:新建态、活跃就绪/静止就绪、运行、活跃阻塞/静止阻塞、终止态

  1. 新建态:对应于进程刚刚被创建时没有被提交的状态,并等待系统完成创建进程的所有必要信息
  2. 终止态:进程已结束运行,回收除进程控制块之外的其他资源,并让其他进程从进程控制块中收集有关信息。
  3. 活跃就绪:是指进程在主存并且可被调度的状态。
  4. 静止就绪(挂起就绪):是指进程被对换到辅存时的就绪状态,是不能被直接调度的状态,只有当主存中没有活跃就绪态进程,或者是挂起就绪态进程具有更高的优先级,系统将把挂起就绪态进程调回主存并转换为活跃就绪。
  5. 活跃阻塞:是指进程已在主存,一旦等待的事件产生便进入活跃就绪状态。
  6. 静止阻塞:进程对换到辅存时的阻塞状态,一旦等待的事件产生便进入静止就绪状态。

线程

线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源但它可与同属一个进程的其它线程共享进程所拥有的全部资源。

一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。

线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。

在单个程序中同时运行多个线程完成不同的工作,称为多线程。

协程

协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

区别

线程与进程
  1. 线程是进程内的一个执行单元,进程内至少有一个线程,它们共享进程的地址空间,而进程有自己独立的地址空间
  2. 进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源
  3. 线程是处理器调度的基本单位但进程不是
  4. 二者均可并发执行
  5. 每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口,但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制
协程和线程
  1. 一个线程可以多个协程,一个进程也可以单独拥有多个协程
  2. 线程进程都是同步机制,而协程则是异步
  3. 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态

例子

  1. 单进程单线程:一个人在一个桌子上吃菜
  2. 单进程多线程:多个人在同一个桌子上一起吃菜
  3. 多进程单线程:多个人每个人在自己的桌子上吃菜

同步阻塞

多进程模式
  1. 创建一个 socket
  2. 进入 while循环,阻塞在进程accept操作上,等待客户端连接进入主进程在多进程模型下通过fork刨建子进程
  3. 收到数据后服务器程序进行处理然后使用send向客户端发送响应
  4. 当客户端连接关闭时,子进程/线程退出并销毁所有资源。主进程/线程会回收掉此子进程/线程。
多线程模式
  1. 多线程模型下可以创建子线程
  2. 子进程/线程创建成功后进入while循环,阻塞在recv调用上,等待客户端向服务器发送数据
  3. 收到数据后服务器程序进行处理然后使用send向客户端发送响应
  4. 当客户端连接关闭时,子进程/线程退出并销毁所有资源。主进程/线程会回收掉此子进程/线程。
缺点
  1. 这种模型严重依赖进程的数量解决并发问题
  2. 启动大量进程会带来额外的进程调度消耗

异步非阻塞

现在各种高并发异步IO的服务器程序都是基于epoll实现的

IO复用异步非阻塞程序使用经典的Reactor模型,Reactor顾名思义就是反应堆的意思,它本身不处理任何数据收发。只是可以监视一个 socket句柄的事件变化

reactor模型
  • Add:添加一个 SOCKET到 Reactor
  • Set:修改 SOCKET对应的事件,如可读可写
  • Del:从 Reactor中移除
  • Callback:事件发生后回调指定的函数

常见reactor模型

  1. Nginx:多线程 Reactor
  2. Swoole:多线程 Reactor 多进程Worker

数据库缓存

mysql查询缓存

查询缓存可以看做是SQL文本和查询结果的映射,第二次查询的SQL和第一次查询的SQL全相同,则会使用缓存

表的结构或数据发生改变时,查询缓存中的数据不再有效

配置:
query_cache_type

查询缓存类型,有0、1、2三个取值。0则不使用查询缓存。1表示始终使用查询缓存。2表示按需使用查询缓存。

query_cache_size

默认情况下 query_cache_size 为0,表示为查询缓存预留的内存为0,则无法使用查询缓存

代码语言:javascript复制
SET GLOBAL query_cache_size= 134217728
使用

querycache_type 为1时,亦可关闭查询缓存

代码语言:javascript复制
SELECT SQL_NO_CACHE FROM my_table WHERE condition;

query_cache_type 为2时,可按需使用查询缓存

代码语言:javascript复制
SELECT SQL_CACHE FROM my_table WHERE condition;
其他

查看命中次数

代码语言:javascript复制
SHOW STATUS LIKE'Qcache_hits';

清理缓存

代码语言:javascript复制
FLUSH QUERY CACHE∥清理查询缓存内存碎片
RESET QUERY CACHE∥从查询缓存中移出所有查询
FLUSH TABLES;//关闭所有打开的表,同时该操作将会清空查询
缓存中的内容

redis / memcache 缓存

  • Redis,依赖客户端来实现分布式读写
  • Memcache本身没有数据冗余机制
  • Redis支持(快照、AOF),依赖快照进行持久化,aof增强了可靠性的同时,对性能有所影响
  • Memcache不支持持久化,通常做缓存,提升性能;
  • Memcache在并发场景下,用cas保证一致性, redis事务支持比较弱,只能保证事务中的每个操作连续执行
  • Redis支持多种类的数据类型
  • Redis用于数据量较小的高性能操作和运算上
  • Memcache用于在动态系统中减少数据库负载,提升性能;适合做缓存,提高性能

mysql 优化

数据表数据类型优化

  • tinyint、 smallint、 bigint 考虑空间的问题,考虑范围的问题
  • char、varchar
  • enum 特定、固定的分类可以使用enum存储,效率更快
  • ip地址 ip2long() 转成长整型存储

索引优化

索引创建原则
  • 索引不是越多越好,在合适的字段上创建合适的索引
  • 复合索引的前缀原则
索引注意事项
  • 复合索引的前缀原则
  • like查询%的问题
  • 全表扫描优化
  • or条件索引使用情况
  • 字符串类型索引失效的问题

SQL语句的优化

优化查询过程中的数据访问
  • 使用 Limit
  • 返回列不用*
优化长难句的查询语句
  • 变复杂为简单
  • 切分查询
  • 分解关联查询
优化特定类型的查询语句
  • 优化 count()
  • 优化关联查询
  • 优化子查询
  • 优化 Group by和 distinct
  • 优化 limit和 union

存储引擎的优化

尽量使用 Inno DB存储引擎

数据表结构设计的优化

分区操作
  • 通过特定的策略对数据表进行物理拆分
  • 对用户透明
  • partition by
分库分表
  • 水平拆分
  • 垂直拆分

数据库服务器架构的优化

  • 主从复制
  • 读写分离
  • 双主热备
  • 负载均衡
负载均衡
  • 通过LVS的三种基本模式实现负载均衡
  • MyCat数据库中间件实现负载均衡

web服务器的负载均衡、请求分发

七层负载均衡实现

基于URL等应用层信息的负载均衡

Nginx的 proxy是它一个很强大的功能,实现了7层负载均衡

nginx负载均衡
优点

功能强大,性能卓越,运行稳定

配置简单灵活

能够自动剔除工作不正常的后端服务器

上传文件使用异步模式

支持多种分配策略,可以分配权重,分配方式灵活

Nginx负载均衡策略

内置策略: IP Hash、加权轮询

扩展策略:fair策略、通用hash、一致性hash

加权轮询策略

首先将请求都分给高权重的机器,直到该机器的权值降到了比其他机器低,才开始将请求分给下一个高权重的机器

当所有后端机器都down掉时,Ngnx会立即将所有机器的标志位清成初始状态,以避免造成所有的机器都处在 timeout的状态

IP Hash策略

Nginx内置的另一个负载均衡的策略,流程和轮询很类似,只是其中的算法和具体的策略有些变化

IP Hash算法是一种变相的轮询算法

fair策略

根据后端服务器的响应时间判断负载情况,从中选出负载最轻的机器进行分流

通用Hash、一致性Hash策略

通用hash比较简单,可以以 Nginx内置的变量为key进行hash,

一致性hash采用 Nginx了内置的一致性hash环,支持 memcache

配置
代码语言:javascript复制
http {
  
  
    upstream cluster {
  
  
        server srvl;
        server srv2;
        server srv3;
    }
    server {
  
  
        listen 80;
        location /
        proxy_pass http: //cluster;
    }
}

四层负载均衡实现

通过报文中的目标地址和端口,再加上负载均衡设备设置的服务器选择方式,决定最终选择的内部服务器

LvS实现服务器集群负载均衡有三种方式,NAT,DR和TUN

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/112118.html原文链接:https://javaforall.cn

0 人点赞