Nginx相关
简介
Nginx 是一个开源的“高性能代理服务器 (可以处理数千个并发且迅速响应)“,采用异步非阻塞的事件驱动模型实现了高可用(高性能、低消耗、可靠稳定)。常用于 Web 服务器、负载均衡、反向代理以及静态资源缓存等。
重要的配置文件
①、nginx.conf:主要的 Nginx 配置文件,包含全局性的设置,例如进程数、工作模式等。该文件位于 /etc/nginx/ 目录下。
②、sites-available/default:默认的虚拟主机配置文件。该文件位于 /etc/nginx/sites-available/ 目录下。
③、sites-available/:存放了用于配置不同虚拟主机的配置文件,每个文件对应一个虚拟主机。可以在该文件夹下创建新的配置文件以配置更多的虚拟主机。
④、sites-enabled/:存放了启用的虚拟主机的配置文件的符号链接。通常使用 ln -s 命令将 sites-available / 目录下的配置文件链接到 sites-enabled / 目录,从而启用该虚拟主机。
⑤、conf.d/:该文件夹下存放了其他 Nginx 配置文件的目录,这些配置文件可以包含在主配置文件中。可以在该文件夹下创建新的配置文件以添加其他配置选项。
常用的命令
①、停止 Nginx: nginx -s stop
②、重启 Nginx: nginx -s restart
③、检查 Nginx 配置文件是否正确: nginx -t
④、关闭 Nginx:并在处理完当前请求后退出: nginx -s quit
⑤、重新加载配置文件:nginx -s reload
配置反向代理服务器
打开 Nginx 的配置文件: /etc/nginx/nginx.conf
配置反向代理:在 Nginx 配置文件中找到 http 部分,并配置反向代理:
http {
server {
listen 80;
# 域名
server_name demo.com;
# 代理的后端服务器地址
location / {
proxy_pass http://backend-server;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwardeed_for;
}
}
# 后端服务器地址,可以按需添加多个
upstream backend-server {
server backend1.demo.com;
server backend2.demo.com;
}
}检查nginx中的配置是否有错误:nginx -t ,并重新加载nginx的配置文件:nginx -s reload,反向代理服务器配置成功!
负载均衡配置
解决问题: 在并发或服务繁忙等场景下,实现速度和稳定性(高可用)
原理:通过反向代理来实现的负载均衡
负载均衡的 策略 / 算法 如下:
①、轮询(默认)
②、IP_HASH 算法(保持会话,解决会话问题)
③、Weighted 算法(按权重比例分配服务器,解决差异性的服务器性能问题)
④、URL_HASH 算法(通常用于静态资源代理,配合缓存命中来使用,类似 cdn)
IP/IP 段控制
限制特定 IP 地址或 IP 地址段的访问,使用 Nginx 的 ngx_http_access_module 模块提供的 allow 和 deny 指令。
具体配置示例参考:nginx配置系列(二)访问控制(ngx_http_access_module)
HTTP 与 HTTPS 的区别以及 nginx 如何支持?
区别:
①、端口:http 80, https :443
②、状态:http 无状态,https 是有 http + ssl 身份验证
③、传输方式:http 明文传输,https 加密传输
④、连接速度:http 更快(三次握手),https 需要 12 个包(http 的 3 次握手 + 9 个 ssl 握手包)
nginx配置https配置示例参考:nginx开启https配置
静态文件缓存与压缩
①、缓存相关的配置项,proxy_cache_*
②、gzip 压缩的配置项,gzip_*
nginx日志
①、配置日志: access_log,error_log
②、自定义日志格式(可配置变量参考手册),如自定义 testnginxlog格式:
log_format testnginxlog '$time_local $remote_addr $request_method $request_uri'; #定义日志使用自定义的格式 access_log /var/log/nginx/access.log testnginxlog;
限流与优化
①、反向代理服务器,可以隐藏真实服务器的 IP 地址,有一定的保护作用。
②、HTTP 限制:使用 limit_req 和 limit_conn,对客户端进行合理的请求限制。
③、访问限制:使用 GeoIP 和 IP 黑名单等,对恶意 IP 进行拦截或限制。可以基于地理位置、IP 地址段等限制。
④、负载均衡:通过反向代理功能,将请求分散到多个后端服务器上,从而分摊请求压力。
⑤、动静分离:将动态和静态资源分开,静态可用 Nginx 的缓存功能缓存,减轻后端服务器压力。
⑥、配置防火墙:结合 Nginx 与防火墙工具(如 iptables),对流量进行控制,只允许合法的,阻止恶意流量。
⑦、监控分析:监控(Nginx Stub Status 模块 + 第三方工具),分析(ELK)。问题及时发现处理
PHP相关
cgi
cgi(通用网关接口)是一个标准,它定义了web服务器与外部程序之间的通信接口,允许服务器将客户端请求转发给外部程序进行处理,并将处理结果返回给客户端。
用在php和nginx之间的话那就是:cgi 是 nginx 和 php 通讯的协议。nginx 服务器在接受请求后,如果是静态请求(图片,文件等无需 php 处理的)则会直接返回给浏览器。如果是一个动态的 php 请求,nginx 就会通过 cgi 协议与 php 通信,将请求数据转换成 php 能理解的信息,php 处理完成也通过 cgi 协议返给 nginx,最后 nginx 再返回给浏览器。
注意:任何支持cgi协议的web server服务器都可以和php进行数据通讯,不仅仅是上面说的nginx。因为cgi协议定义的是一个标准接口,只要满足这个接口规定的数据输入输出格式,就可以进行通讯。在php和nginx当中 CGI其实相当于是php和nginx之间进行沟通的一座桥梁,php和nginx进行数据交互通讯的话 需要借助于 这座桥梁(nginx) 来实现数据交互通讯。
fast-cgi
传统的 cgi 协议在每次连接请求时,会开启一个进程进行处理,处理完毕会关闭该进程。下次请求又重复开启与关闭。频繁的进程启动与关闭,消耗大量的资源和内存。而 fast-cgi 每次处理完请求后,不会 kill 掉这个进程,而是保留进程,使进程可以处理多次请求,不用重新 fork 一个进程,大大提高效率。
注意:fast-cgi由于使用的是多进程模型,因为它能更有效地处理并发请求。不过,由于fast-cgi是多进程的,so 他会消耗更多的服务器内存。
php-cgi
php-cgi 是 php 提供给 web serve 的 cgi 协议接口程序,每次请求都会开启一个 php-cgi 进程进行处理,而且开启 php-cgi 会先重载配置,数据结构以及初始化运行环境,如果更新了 php 配置,那么就需要重启 php-cgi 才能生效。
所以 这也就是为什么 每次改了php的配置文件之后 我们都需要重启web server的原因 就是这种原因。(这种时候 php的运行模式 应是非cli模式下运行的。注意 并不是说 php在cli命令行模式下运行php脚本后,如果更改了php的配置文件就不需要重启php进程了,这个不是绝对的,但是大多数情况下 不需要重启php的! 只需要重新在cli模式下运行php脚本文件即可使更改的配置文件生效)
php-fpm
①、php-fpm(FastCGI Process Manager)是一个PHP fast-cgi管理器,它专门用于管理php-cgi进程。与php-cgi不同,php-fpm是一个进程管理器,而php-cgi只是一个解释器。这意味着php-fpm可以管理多个php-cgi进程,而不仅仅是一个。此外,当使用FastCGI协议时,php-cgi的启动不受Web Server的控制,而是直接受php-fpm的调度。
②、php-fpm 常驻内存,会开启多个 php-cgi 进程,请求来的时候,php-fpm 将连接分配给一个 php-cgi 子进程处理,处理完毕后 php-cgi 并不会关闭,而是等待处理下一个连接,这也是 fast-cgi 加速的原理。
③、php-fpm 是多进程的,一个 php-cgi 大概消耗 7-25M 内存,需注意连接过多导致内存消耗过大的问题。
④、php-fpm 支持平滑启动,如果更新了 php 配置可使用 /you_path/php-fpm reload 平滑过渡。
cgi、fast-cgi、php-cgi、php-fpm之间的关系:cgi是一个通信标准,php-cgi是php语言的cgi协议的具体实现,fast-cgi是cgi的进阶版本并使用多进程模型,而php-fpm是一个专门用于管理php-cgi进程的管理器。在搭建高性能的服务器时,理解这些概念之间的关系是非常重要的。
php-fpm优化
php-fpm 默认使用静态进程管理模式(启动时创建固定数量的进程)
在高负载环境下,推荐使用动态进程管理模式(动态创建 / 销毁进程以提高性能)
php-fpm的配置文件
vim /etc/php-fpm.conf
# 增加进程数 pm.max_children = 50 //pm.max_children表示最大的进程数 pm.start_servers = 20 //pm.start_servers表示启动时的进程数 # 调整进程空闲时间 pm.max_spare_servers = 10 //pm.max_spare_servers表示空闲进程的最大数量 pm.min_spare_servers = 5 //pm.min_spare_servers表示空闲进程的最小数量 # 每个进程允许处理的最大请求次数。到该次数后进程重启,释放资源(大了可能会内存溢出,小了频繁重启) pm.max_requests = 1000 # 使用动态进程管理模式(static和dynamic) pm = dynamic pm.max_children = 50 pm.start_servers = 20 pm.min_spare_servers = 5 pm.max_spare_servers = 10
Nginx和php之间的通信
tcp socket :面向连接的协议,更好的保证通信的正确性和完整性
unix socket:不需要网络协议打包拆包,开销小效率高,但高并发时候不稳定,可能返回异常。
网络 7 层协议模型
应用层、表示层、会话层、传输层、网络层、(数据)链路层、物理层。快记:应表会传(物链网)
tcp和 udp 的特点和区别
①、都是属于传输层协议
②、tcp:面向连接,一对一,数据可靠不丢失
③、udp:无连接,一对多 / 多对多,速度更快但不可靠
tcp的三次握手和四次挥手
三次握手:
第一次:客户端发送 SYN = 1,seq = client_isn
第二次:服务端发送 SYN = 1,seq = server_isn,ACK =client_isn +1
第三次:客户端发送 SYN = 0, ACK = server_isn+1,seq =client_isn+1
四次挥手:
第一次:客户端发送 FIN
第二次:服务端发送 ACK
第三次:服务端发送 FIN
第四次:客户端发送 ACK
HTTP 状态码
1xx:请求进行中,服务器收到请求,需要请求者继续操作
2xx:成功
3xx:重定向
4xx:客户端错误
5xx:服务端错误
oop 是什么?
面向对象编程是一种计算机编程架构思想,指程序由一个个能够起到子程序作用的单元或对象组成。 面向对象 3 大特性:继承、封装、多态。
php 垃圾回收机制
“引用计数方式(is_ref_gc=0 时回收)” + “标记清除方式(解决循环引用时回收)”来进行垃圾回收。
什么是引用传递?
引用传递:函数内对值的任何改变在函数外部也生效(传递地址)
值传递:函数内对值的任何改变在函数外部不生效(复制值) 对大型字符串和对象来说,复制操作代价很大。引用传递会有不错的性能提升(对象默认为引用传递)。
设计模式五大原则
①、单一职责原则:单一职责原则可以看做是低耦合、高内聚在面向对象原则上的引申,将职责定义为引起变化的原因,以提高内聚性来减少引起变化的原因。
②、开放封闭原则:核心理念 “对扩展开放,对修改封闭”。设计时要允许现有代码进行扩展,而不是通过修改现有代码来实现新的功能。这样做可以避免对现有代码造成不必要的破坏和风险,同时也可以提高代码的复用性和可维护性,从而降低开发和维护成本。
③、接口隔离原则:不要强迫客户使用它们不用的方法,如果强迫用户使用它们不使用的方法,那么这些客户就会面临由于这些不使用的方法的改变所带来的改变。
④、依赖倒置原则:面向对象而不是面向过程。程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。
⑤、里氏替换原则:子类可以扩展父类的功能,但不能改变父类原有的功能。
附:迪米特原则:一个对象应该对其他对象保持最少的了解。
常见的设计模式
单例模式、工厂模式、策略模式、观察者模式、外观模式、代理模式…...
①、创建型模式共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
②、结构型模式共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
③、行为型模式共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
单例模式:确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
public static function getInstance()
{
return new static();
}观察者模式:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并且有所作为。即出版者 + 订阅者 = 观察者模式。
工厂模式 :调用者和创建者分离,调用者直接向工厂类请求获取对象,减少代码耦合,提高系统的维护性和扩展性。
适配器模式:把对某些相似的类的操作转化为一个统一的 “接口”(比喻的说法)–适配器,或者比喻为一个 “界面”,统一或屏蔽了那些类的细节。适配器模式还构造了一种 “机制”,使 “适配” 的类可以很容易的增减,而不用修改与适配器交互的代码,符合 “减少代码间耦合” 的设计原则。
冒泡排序 / 快速排序
冒泡排序:是一种交换排序。对数组进行多轮冒泡,每一轮对数组中的元素两两比较,调整位置,冒出一个最大的数来。
/**
* 冒泡排序
* @param array $arr
*/
function bubbleSort(array $arr)
{
$length = count($arr);
//外层循环,从数组首部开始,每完成一次循环,可确定 $arr[$i] 位置的元素
for($i = 0; $i < $length; $i++)
{
//内层循环,$j 从后往前循环
for($j = $length - 1; $j > $i; $j--)
{
//若前面的值大于后面的值,则互换位置
if($arr[$j] < $arr[$j - 1])
{
[$arr[$j], $arr[$j - 1]] = [$arr[$j - 1], $arr[$j]];
}
}
}
return $arr;
}快速排序:递归算法。先选择数组的第一个元素作为标准,然后把小于或等于它和大于它的数分别放入两个数组中,对这两个数组也进行相同的处理,最后合并这两个数组和第一个元素。
/**
* 快速排序
* @param $arr
*/
function quickSort(&$arr)
{
$length = count($arr);
//若数组为空,则不需要运行
if($length <= 1)
{
return;
}
$middle = $arr[0]; //选定一个中间值
$left = []; //接收小于中间值
$right = []; //接收大于中间值
//循环比较
for($i = 1; $i < $length; $i++)
{
if($middle < $arr[$i])
{
$right[] = $arr[$i]; //大于中间值
}
else
{
$left[] = $arr[$i]; //小于或等于中间值
}
}
//递归排序划分好的左右两边
quickSort($left);
quickSort($right);
$arr = array_merge($left, [$middle], $right);
}单点登录
单点登录(Single Sign On, SSO)是指一次登录即可访问所有相互信任的应用系统。本质是多个应用系统共享登录状态。
实现方式一:父域 cookie
①、cookie 的作用域由 domain 属性和 path 属性共同决定。所以可以通过把登录状态的 seesion_id 存在主域名域下 (当前域的父域),所有子域名就都可以共享了。
②、此种实现方式比较简单,但不支持跨主域名。
实现方式二:认证中心
①、部署一个认证中心,专门负责处理登录请求的独立的 Web 服务。
②、用户统一在认证中心进行登录,登录成功后,认证中心记录用户的登录状态,并将 Token 写入 Cookie。(注意这个 Cookie 是认证中心的,应用系统是访问不到的)
③、应用系统检查当前请求有没有 Token,如果没有,那么就跳转至认证中心。而认证中心通过自动携带的 Cookie 判断是否已经登录。
④、如果认证中心发现用户尚未登录,则返回登录页面,等待用户登录。如果发现用户已经登录过了,就跳转回目标 URL (目标应用系统),并携带回传一个认证中心的 Token。
⑤、应用系统拿到 Token 之后,后端向认证中心确认下 Token 的合法性,防止用户伪造的同时 check 用户登录状态。确认无误后,应用系统记录用户的登录状态,并将 Token 写入 Cookie,访问放行。(此时 Cookie 是当前应用系统的)当用户再次访问当前应用系统时,就会自动带上这个 Token,应用系统验证 Token,就实现了单点登录。
⑥、此种实现方式相对复杂,但支持跨域,扩展性好,是单点登录的标准做法。
实现方式三:LocalStorage 跨域。
①、在这样的场景下,单点登录完全可以在前端实现。前端拿到 Session ID (或 Token )后,除了将它写入自己的 LocalStorage 中之外,还可以通过特殊手段将它写入多个其他域下的 LocalStorage 中。
②、前端将同一份 Token 写入到了多个域下的 LocalStorage 中,前端每次在向后端发送请求之前,都会主动从 LocalStorage 中读取 Token 并在请求中携带,这样就实现了同一份 Token 被多个域所共享。
③、此种实现方式完全由前端控制,几乎不需要后端参与,同样支持跨域。但扩展性不好,不利于维护。
php 的堆与栈
①、heap 是堆,stack 是栈。
②、heap 上的空间手动分配 / 释放(程序运行时分配的内存),stack 的空间由操作系统自动分配 / 释放(程序执行时为函数、局部变量等分配的内存空间)。
③、zendVM 中的 malloc 函数分配的内存空间即在堆上 (mm_heap)
在 PHP 中,Zend 引擎通过内存分配器来管理堆内存的分配和释放。当 PHP 执行过程中需要分配更多内存时,内存分配器会从堆中分配一块足够大的空间,供变量和数据结构使用。而当某个变量或数据结构不再使用时,内存分配器会将相应的内存空间返回给堆。
php 底层相关理解
通常就是问:符号表(hashTable)、zvalue 结构体、zend vm 的内存分配等。
php的几种运行模式
①、CGI 模式(wnmp等)
②、FastCGI 模式(lnmp 最常见的环境)
③、CLI 模式(php 命令行)
④、web 模块模式( Apache )
php实现静态化
①、PHP 的静态化分为:纯静态和伪静态。其中纯静态又分为:局部纯静态和全部纯静态。
②、PHP 伪静态:利用 Apache mod_rewrite,niginx rewrite 实现 URL 重写的方法。
③、PHP 纯静态:生成 HTML 文件的方式,须开启 PHP 自带的缓存机制,即 ob_start 来开启缓存。
session 和 cookie
session 和 cookie 是一种会话管理技术,通常把 session_id 存在 cookie 来匹配管理会话。
存储位置:cookie 存储在客户端,session 存储在服务器
存储容量:单个 cookie 数据 <=4KB,一个站点最多保存 20 个 Cookie; session 理论没有限制(存重要信息即可)
安全性与其他:cookie 在客户端不安全(占用客户端资源),session 在服务器安全(占用服务器资源)
CSRF 攻击,XSS 攻击
CSRF(Cross-site request forgery)跨站请求伪造,黑客建立一个伪造网站或发送邮箱带了一个正常 URL 链接来让正常用户访问,来让用户通过自己浏览器里的 cookie 权限来执行一些非法请求。
防范方法:验证 HTTP Referer 字段、添加 token 并验证等。
XSS攻击
主要将 XSS 代码提交存储在服务器端(数据库,内存,文件系统等),下次请求目标页面时不用再提交 XSS 代码。当目标用户访问该页面获取数据时,XSS 代码会从服务器解析之后加载出来,返回到浏览器做正常的 HTML 和 JS 解析执行,XSS 攻击就发生了。
防范方法:通过过滤是针对非法的 html 代码包括单双引号等,使用 htmlspecialchars()函数
抽象类和接口分别是什么?
抽象类:就是一种特殊的类,不能被实例。可以定义方法,属性。类似于模版,规范后让子类去实现具体的详细功能。
接口:主要基于方法 / 对象的规范。可以让某个类通过实现多个接口来形成新的类。
抽象类与接口的相同点:
①、都是用于声明某一种事物,规范名称、参数,形成模块,未有详细的实现细节。
②、都是通过类来实现相关的细节。
③、语法上,抽象类的抽象方法与接口一样,不能有方法体,即{}符号。
④、都可以用继承,接口继承接口形成新的接口,抽象类继承抽象类形成新的抽象类。
抽象类与接口的不同点:
①、抽象类可以有属性、普通方法、抽象方法,但接口不能有属性、普通方法(可以有常量)。
②、抽象类内未必有方法定义(可以都是普通方法),但接口内一定会有 “方法定义”。
③、抽象类用 abstract 关键字,class 声明为类,接口用 interface 声明。
④、抽象类的抽象方法一定要用 abstract 来声明,而接口不需要。
⑤、抽象类是用 extends 关键字让子类继承,接口用 implements 关键字来实现接口
网站性能优化 / 高并发解决方法
前端优化
①、减少 HTTP 请求 [将 css、js 等合并]
②、添加异步请求 (非必须数据先不展示,用户触发某个事件才会异步请求数据)
③、CDN 加速,建立独立的文件 / 图片服务器 (减少 I/O)
web 服务器优化
①、防盗链处理 (去除恶意请求)
②、反向代理实现负载均衡
③、静态资源缓存和 gzip 压缩
④、流量过滤,ip限制及黑白名单
应用程序优化
①、业务代码逻辑检查优化,sql 查询优化
②、常驻内存 swoole,opcache 缓存技术,连接池技术
数据库优化
①、读写分离,负载均衡
②、redis 缓存、数据库缓存策略
③、分表分区分库,数据拆分
④、表结构优化,索引优化
防止 sql 注入
①、验证数据,可以根据相应类型进行严格的验证。比如 int 类型直接同过 intval 进行转换。
②、参数化绑定,PDO 参数绑定。
③、禁止使用 sql 拼接。
④、mysql 开启严格模式。
大魔术常量
①、LINE:文件中 本常量所在行的 行号(即处于第几行)。
②、FELE:本文件的完整路径和文件名。如果被用在 被包含文件中,则返回被包含文件的文件名。本常量总是包含一个绝对路径(如果是符号链接,则是解析后的绝对路径)。
③、DIR:本文件所在目录。如果被用在 被包含文件中,则返回被包含文件的所在目录。它等价于 dirname (FILE)。除非是根目录,否则目录名中不包含末尾的斜杠。
④、FUNCTION:函数名称。自 PHP5 起本常量返回函数被定义时的名称(区分大小写)。
⑤、CLASS:类名称。自 PHP5 起本常量 返回类被定义时的名称(区分大小写,包括其命名空间。如:Foo\Bar)。
⑥、TRAIT:trait 的名称。自 PHP5.4 起本常量返回 trait 被定义时的名称(区分大小写)。
⑦、METHOD:类的方法名。返回该方法被定义时的名称(区分大小写)。
⑧、NAMESPACE:当前命名空间的名称(区分大小写)。本常量是在编译时定义的。
9个超全局变量
①、$_GLOBALS :储存全局作用域中的变量
②、$_SERVER :获取服务器相关信息
③、$_REQUEST:获取 POST 和 GET 请求的参数
④、$_POST : 获取表单的 POST 请求参数
⑤、$_GET: 获取表单的 GET 请求参数
⑥、$_FILES :获取上传文件的的变量
⑦、$_ENV : 获取服务器端环境变量的数组
⑧、$_COOKIE:获取浏览器的 cookie
⑨、$_SESSION : 获取 session
php中的魔术方法
__constuct 创建一个类的对象的时候被调用。
__destruct 明确销毁对象或脚本结束时被调用。
__set 当给不可访问或不存在属性赋值时被调用。
__get 读取不可访问或不存在属性时被调用。
__isset 对不可访问或不存在的属性调用 isset () 或 empty () 时被调用。
__unset 对不可访问或不存在的属性进行 unset 时被调用。
__call 调用不可访问或不存在的方法时被调用。
__callStatic 调用不可访问或不存在的静态方法时被调用。
__sleep 当使用 serialize 时被调用,当你不需要保存大对象的所有数据时很有用。
__wakeup 当使用 unserialize 时被调用,可用于做些对象的初始化操作。
__clone 进行对象 clone 时被调用,用来调整对象的克隆行为。
__toString 当一个类被转换成字符串时被调用。
__invoke 当以函数方式调用对象时被调用。
__set_state 当调用 var_export () 导出类时,此静态方法被调用。用 set_state 的返回值做为 var_export 的返回值。
__debuginfo 当调用 var_dump () 打印对象时被调用(当你不想打印所有属性)。
一次http请求的生命周期
构建请求->查找本地缓存->域名解析->与服务器建立连接(TCP 的三次握手)->发起 HTTP 请求->服务器处理请求->服务器响应 HTTP 请求->客户端解析返回数据->与服务器断开连接(TCP 的四次挥手)
网站打开慢怎么排查?
①、打不开,则 ping 域名,看是否能请求成功。
②、慢,说明能打开,直接 free/top 命令查看服务器内存和 CPU 使用情况,iftop 等工具查看带宽
③、浏览器的network 查看响应慢的请求
④、排查响应慢的接口代码,看 php,mysql,redis 等的日志看错误信息(mysql 的慢查询日志,php-fpm 慢日志,需要配置开启)
什么是 MQ?
mq 是一个消息队列,通常是解决传统的消息传输上管理困难,效率不高的问题。
mq 有三大优点:解耦,异步,削峰。
缺点: 增加了中间件,就提高了系统复杂度,增加了维护的成本。比如:要保证消息不丢失 (一致性) 和消息幂等性问题,还要保证 mq 的高可用等。
MySQL相关
数据库三大范式是什么?
第一范式:1NF 要求每个数据表的每个属性都是原子性的,即 不能包含多个值或重复的数据。
第二范式:要求在满足第一范式的基础上,非主键属性必须完全依赖于候选键(候选键是能够唯一标识一条记录的属性或属性组合)。如果存在部分依赖,需要将其独立出来作为一个新的表。
第三范式:要求在满足第二范式的基础上,非主键属性不能相互依赖,即不能存在传递依赖。如果存在传递依赖,需要将其独立出来作为一个新的表。
总结:第一范式(1NF)要求原子性,第二范式(2NF)要求非主键属性完全依赖于候选键,第三范式(3NF)要求消除非主键属性之间的传递依赖。这三个范式是在数据库设计中用于规范化数据结构的原则。
MyISAM存储引擎 与 InnoDB 存储引擎的区别
①、MyISAM 不支持事务与外键,InnoDB 支持。
②、MyISAM 是表锁,InnoDB 行锁 (InnoDB提高了并发性能)。
③、MyISAM 表是保存成独立文件的形式,在数据转移、备份 MyISAM 更具有优势。
④、AUTO_INCREMENT:MyISAM 可以和其他字段一起建立联合索引,InnoDB 中必须是只有该字段的索引。
⑤、MyISAM 支持 FULLTEXT 类型的全文索引,InnoDB 不支持,但插件 sphinx 支持全文索引 (效果更好)。
⑥、MyISAM 允许没有任何索引和主键的表存在,InnoDB 没有主键会选择非空唯一索引,或自动生成一个 6 位的 uuid 主键。
⑦、MyISAM 的 SELECT 性能更好,InnoDB 的 INSERT、UPDATE、DELETE 更好(删除全表使用 truncate table)。
索引区别
聚簇索引:索引和数据都存储在一个节点。
非聚簇索引:索引和数据分开存储,通过索引找到数据实际存储的地址。
innodb 使用的聚簇索引,主键索引为聚簇索引(没有主键索引会选择一个非空唯一索引或隐式的创建一个主键索引),辅助索引指向主键索引,然后再找到实际存储地址。
myisam 使用非聚簇索引(辅助索引和主键索引一样),都只需要查询一次就能找到数据。
聚簇索引的优势和略势
①、索引和数据在一起,同一页的数据会被缓存到(buffer)内存中,所以查看同一页数据的时候只需要从内存中取出。
②、数据更新之后之只需要维护主键索引即可,辅助索引不受影响。
③、辅助索引存的是主键索引的值,容易产生回表。
④、使用隐式的 uuid 主键时,数据分布不均匀,导致聚簇索引可能扫全表,效率低下(强制使用自增主键 id )。
b-tree(mongodb) 和 b+tree (mysql)的区别
①、b+tree 的数据全部存储在叶子节点,主节点只存 key,一次磁盘 IO 能获取到更多的节点。
②、b+tree 增加了叶子节点到相邻节点的指针,数据是有序双向链表 ,方便返回查询范围(顺序性)。
③、b-tree 的主节点和叶子节点都存储 key 和数据,查找数据不需要找到叶子节点,主节点可以直接返回数据。
事务的ACID 与隔离级别
事务遵循包括原子性在内的 ACID 四大特性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。
①、原子性 :数据提交工作时,要么保证所有的修改都能够提交,要么就所有的修改全部回滚。
②、一致性:数据库从一个一致性状态变换到另一个一致性状态。
③、隔离性: 如果多个事务并发执行,应像各个事务独立执行一样。
④、持久性:一个成功执行得事务对数据库得作用是持久的,即使数据库发生故障出错,也应该能够恢复。
四种隔离级别:
①、未提交读(read-uncommitted)所有事务都可以看到其他未提交事务的执行结果。很少用于实际应用,因为它的性能也不比其他级别好多少。会产生脏读,不可重复读以及幻读。
②、已提交读(read-committed)这是大多数数据库系统的默认隔离级别(但不是 MySQL 默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。会产生幻读。
③、可重复读(repeatable-read)这是 MySQL 的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,也会导致幻读 (Phantom Read)。幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的 “幻影” 行。InnoDB 存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。
④、串行化(serializable)这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
MyISAM表锁
①、共享读锁(S)之间是兼容的,但共享读锁(S)和排他写锁(X)之间,以及排他写锁之间(X)是互斥的,也就是说读和写是串行的。
②、在一定条件下,MyISAM 允许查询和插入并发执行,利用这一点来解决应用中对同一表和插入的锁竞争问题。
③、MyISAM 默认锁调度机制是写优先,不一定适合所有应用,可以通过设置 LOW_PRIPORITY_UPDATES 参数,或在 INSERT、UPDATE、DELETE 语句中指定 LOW_PRIORITY 选项来调节读写锁的争用。
④、由于表锁的锁定粒度大,读写之间又是串行的,因此,如果更新操作较多,MyISAM 表可能会出现严重的锁等待,可以考虑采用 InnoDB 表来减少锁冲突。
InnoDB表
①、InnoDB 的行锁是基于索引实现的,如果不通过索引访问数据,InnoDB 会使用表锁。
②、在不同的隔离级别下,InnoDB 的锁机制和一致性读策略不同。
③、MySQL 的恢复和复制对 InnoDB 锁机制和一致性读策略也有较大影响。
④、注意死锁,锁冲突甚至死锁很难完全避免。
减少锁冲突和死锁
①、尽量使用较低的隔离级别。
②、精心设计索引,尽量使用索引访问数据,使加锁更精确,从而减少锁冲突的机会。
③、选择合理的事务大小,小事务发生锁冲突的几率也更小。
④、给记录集显示加锁时,最好一次性请求足够级别的锁。比如要修改数据的话,最好直接申请排他锁,而不是先申请共享锁,修改时再请求排他锁,这样容易产生死锁。
⑤、不同程序访问一组表时,应尽量约定以相同的顺序访问,这样可以减少死锁的机会。
⑥、尽量用相等条件访问数据,这样可以避免间隙锁对并发插入的影响。
⑦、不要申请超过实际需要的锁级别;除非必须,查询时不要显示加锁。
分表 (分库) 的策略
根据业务数据量和业务复杂度来拆分。
业务拆分可参考:取余、hash、range 范围。
表结构拆分:垂直、水平。
binlog日志
通常用与:数据恢复、主从复制
可设置格式: statement 、 row 、 mixed(通常使用 row 或者 mixed )
主从同步
可用于: 实现读写分离 、 数据备份高可用、负载均衡提高性能、版本升级测试
流程:
①、从节点开启 start slave 命令之后,创建一个 IO 进程连接到主节点。
②、连接成功之后,主节点创建一个 log dump 线程 (主节点会为每一个从节点创一个 log dump 线程)。
③、当 binlog 发生变化时,主节点的 dump log 线程会读取 bin-log 内容并发送给从节点。
④、主节点 dump log 线程读取 bin-log 的内容时会对主节点的 bin-log 加锁,读取完成在发送给从节点之前释放锁。
⑤、从节点的 IO 线程接收主节点发送的 binlog 内容,并将其写入本地 relay log 文件中。
⑥、主从节点通过 binlog 文件 + position 偏移量定位主从同步的位置,从节点会保存接收到的 position 偏移量,如果从节点发生宕机重启,自动从 postion 位置发起同步。
⑦、从节点的 SQL 线程复制读取本地 relay log 的内容,解析成具体的操作并执行,保证主从数据一致性。
模式: 异步模式(默认方式) 、 全同步模式 、 半同步模式 (几乎不用)
limit优化
①、主键阈值法: 通过条件推算出符合条件的主键最大值 & 最小值来避免
②、配合 es 来分页
redis 缓存 和 mysql 数据保持一致性
①、先更新 redis 再更新数据库。
②、先更新数据库,再更新redis。
③、先删除缓存再更新数据库。
问题:以上解决方案在遇到并发同时请求时,都有可能出现数据不一致的情况。
解决: 1. 延时双删除 ;2. 串行获取(队列化),如:查询队列 + 更新队列
A 字段分组且 B 字段最大的数据?
# 表结构:name,type,age select * from users where (type, age) in (select type, max(age) from users group by type) order by age desc; # join操作 SELECT u.* FROM users u JOIN ( SELECT type, Max(age) AS max_age FROM users GROUP BY type ) t ON u.type = t.type AND u.age = t.max_age order by age desc;
字段值置换更新
对字段值置换更新,如:字段 status 为 0、1,需把 1 更新为 0,0 更新为 1。
# 数学置换 x = 0 + 1 update `table` set status = 1 - status where 1=1; # 语法 case when then UPDATE users SET type = CASE WHEN type = 1 THEN 2 WHEN type = 2 THEN 1 ELSE type END WHERE 1=1;
Redis相关
redis的数据结构
常见的数据结构类型有:String、List、Hash、Set、ZSet
redis为什么快?
Redis采用的是基于内存的单线程 / 多路 IO 复用模型的 KV 数据库, 由 C 语言编写,官方数据 QPS 达到 100000+。
完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,查找和操作的时间复杂度都是 O (1); Redis 中的数据结构简单,对数据操作也简单; 采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或多线程的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,因为没有可能出现死锁而导致的性能消耗; 使用多路 I/O 复用模型,非阻塞 IO;多路 I/O 复用模型是利用 select、poll、epoll 可以同时监察多个流的 I/O 事件的能力。在空闲时,会阻塞当前线程,当有一个或多个流有 I/O 事件时,就从阻塞态中唤醒,于是程序就会轮询一遍所有的流(epoll 是只轮询那些真正发出了事件的流),并且只依次顺序的处理就绪的流,这种做法就避免了大量的无用操作。 这里 “多路” 指的是多个网络连接,“复用” 指的是复用同一个线程。采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络 IO 的时间消耗),且 Redis 在内存中操作数据的速度非常快,也就是说内存的操作不会成为影响 Redis 性能的瓶颈, 所以造就了 Redis 具有很高的吞吐量。
redis的持久化
RDB 快照(每隔一段时间写入快照的方式)
AOF( 将每一个收到的写命令都通过 write 函数追加到 appendonly.aof 文件)
redis内存满了的解决方法
增加内存,内存淘汰策略,搭集群
缓存穿透,雪崩,预热 / 更新
①、缓存穿透:是指用户查询数据库没有的数据,缓存中也不会有。缓存中找不到,都要去数据库再查一遍,然后返回空(进行了两次无用的查询)。绕过缓存直接查数据库,也是缓存命中率的问题。
解决:拦截查询或空结果缓存
②、缓存雪崩:同一时间大量缓存失效,从而数据库查询压力暴增导致服务不可用或宕机。
解决:缓存过期策略、做多级缓存、缓存标记等等,总之就是避免同一时间出现大量缓存数据过期。
③、预热 / 更新:手动或定时对缓存数据进行清理、加载或更新操作。
redis的主从哨兵和集群的区别?
一、架构不同
redis主从:一主多从。
redis集群:多主多从。
二、存储不同
redis主从:主节点和从节点都是存储所有数据。
redis集群:数据的存储是通过一定的hash算法 计算16384 的槽位,算出要将数据存储的节点,然后进行存储。
三、选举不同
redis主从:通过启动 redis 自带的哨兵(sentinel)集群进行选举,也可以是一个哨兵。
选举流程:先发现主节点 fail 的哨兵,将成为哨兵中的 leader,之后的主节点选举将通过这个 leader 进行故障转移操作,从存活的 slave 中选举新的 master,新的 master 选举同集群的 master 节点选举类似。
redis集群:集群可以自己进行选举。
选举流程:
①、当主节点挂掉,从节点就会广播该主节点 fail。
②、延迟时间后进行选举(延迟的时间算法为:延迟时间 + 随机数 + rank*1000,从节点数据越多,rank 越小,因为主从数据复制是异步进行的,所以 所有的从节点的数据可能会不同),延迟的原因是等待主节点 fail 广播到所有存活的主节点,否则主节点会拒绝参加选举。
③、参加选举的从节点向所有的存活的节点发送 ack 请求,但只有主节点会回复它,并且主节点只会回复第一个到达参加选举的从节点,一半以上的主节点回复,该节点就会成为主节点,广播告诉其他节点该节点成为主节点。
四、节点扩容不同
redis主从:只能扩容从节点,无法对主节点进行扩容。
redis集群:可以扩容整个主从节点,但是扩容后需要进行槽位的分片,否则无法进行数据写入。
ElasticSearch相关
es简介
一个高扩展、生态化、开源的全文检索引擎,它可以准实时地快速存储、搜索、分析海量的数据。全文检索是指计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置。当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户。
es查询流程
①、客户端请求发给某个节点
②、节点转发给每个分片,查询每个分片上的前 n 条
③、结果返回给节点,合并整合数据,提取前 n 条
④、最后返回给请求客户端
es为什么比mysql快
es 索引存于内存之中,采用倒序索引,结构为“分词 <=>id” 的方式,能通过分词快速定位文档(分词索引 vs b+tree)
声明:禁止任何非法用途使用,凡因违规使用而引起的任何法律纠纷,本站概不负责。


精彩评论