php面试简单整理

写在前面

休息几个月,感受了下今年求职的环境到底有多糟糕,后面有时间再吐槽当前环境的各种坑吧。。。
顺手记录下自己简单整理的php面试知识点,希望对你多有帮助!
仅供参考!!!

Nginx相关

简介

Nginx是一个开源的”高性能代理服务器(可以处理数千个并发且迅速响应)”,采用异步非阻塞的事件驱动模型实现了高可用(高性能、低消耗、可靠稳定)。常用于Web服务器、负载均衡、反向代理以及静态资源缓存等。

重要的配置文件

1.nginx.conf:主要的Nginx配置文件,包含全局性的设置,例如进程数、工作模式等。该文件位于/etc/nginx/目录下。
2.sites-available/default:默认的虚拟主机配置文件。该文件位于/etc/nginx/sites-available/目录下。
3.sites-available/:存放了用于配置不同虚拟主机的配置文件,每个文件对应一个虚拟主机。可以在该文件夹下创建新的配置文件以配置更多的虚拟主机。
4.sites-enabled/:存放了启用的虚拟主机的配置文件的符号链接。通常使用ln -s命令将sites-available/目录下的配置文件链接到sites-enabled/目录,从而启用该虚拟主机。
5.conf.d/:该文件夹下存放了其他Nginx配置文件的目录,这些配置文件可以包含在主配置文件中。可以在该文件夹下创建新的配置文件以添加其他配置选项。

常用的命令

1.启动Nginx:nginx -s start
2.停止Nginx: nginx -s stop
3.重启Nginx: nginx -s restart
4.检查Nginx配置文件是否正确: nginx -t
5.打开Nginx主进程PID文件: nginx -s reopen
6.关闭Nginx,并在处理完当前请求后退出: nginx -s quit
7.重新加载配置文件: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;
}
}

检查配置: sudo nginx -t ,并重启:sudo service nginx restart,反向代理服务器配置成功!

负载均衡配置

解决问题: 在并发或服务繁忙等场景下,实现速度和稳定性(高可用)
原理:通过反向代理来实现的负载均衡
策略/算法:
1.轮询(默认)
2.IP_HASH算法(保持会话,解决会话问题)
3.Weighted算法(按权重比例分配服务器,解决差异性的服务器性能问题)
4.URL_HASH算法(通常用于静态资源代理,配合缓存命中来使用,类似cdn)

IP/IP段控制

限制特定IP地址或IP地址段的访问,使用Nginx的ngx_http_access_module模块提供的allow和deny指令

# 注意allow, deny顺序配置
location / {
 # 允许访问
 allow 192.168.1.0/24;
 allow 10.0.0.0/16;
 # 拒绝访问
 deny all;
}

HTTP与HTTPS的区别以及nginx如何支持?

区别:
1.端口:http 80, https :443
2.状态:http无状态,https是有http + ssl身份验证
3.传输方式:http明文传输,https加密传输
4.连接速度:http更快(三次握手),https 需要12个包(http的3次握手+9个ssl握手包)
支持:nginx 直接配置证书即可。

#通过rewrite将所有HTTP请求重定向HTTPS
server {
 listen 80;
 server_name demo.com; 
 rewrite ^(.*)$ https://$server_name$1;}
#ssl证书配置有关。
server {
 #端口为443。
 listen 443 ssl;
 #证书绑定的域名。
 server_name demo.com; 
 charset utf-8;
 #证书路径配置
 ssl_certificate /home/you_path/demo.com.pem;
 ssl_certificate_key /home/you_path/demo.com.key;
 #ssl算法相关配置
 ssl_session_timeout 5m;
 ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
 ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; 
 ssl_prefer_server_ciphers on;

 # 其他配置
  ...
}

静态文件缓存与压缩

1.缓存相关的配置项,proxy_cache_*
2.gzip压缩的配置项,gzip_*

nginx日志

1.配置日志: access_log,error_log
2.自定义日志格式(可配置变量参考手册),如自定义mylog格式:

    #时间、客户端IP、请求方法和URL
    log_format mylog ‘$time_local $remote_addr $request_method $request_uri’;
    #定义日志使用自定义的格式
    access_log /var/log/nginx/access.log mylog;

限流与优化

1.反向代理服务器,可以隐藏真实服务器的IP地址,有一定的保护作用。
2.HTTP限制:使用limit_req和limit_conn,对客户端进行合理的请求限制。
3.访问限制:使用GeoIP和IP黑名单等,对恶意IP进行拦截或限制。可以基于地理位置、IP地址段等限制。
4.负载均衡:通过反向代理功能,将请求分散到多个后端服务器上,从而分摊请求压力。
5.动静分离:将动态和静态资源分开,静态可用Nginx的缓存功能缓存,减轻后端服务器压力。
6.配置防火墙:结合Nginx与防火墙工具(如iptables),对流量进行控制,只允许合法的,阻止恶意流量。
7.监控分析:监控(Nginx Stub Status模块 + 第三方工具),分析(ELK)。问题及时发现处理

PHP相关

cgi

CGI 是 nginx 和 php 通讯的协议。nginx 服务器在接受请求后,如果是静态请求(图片,文件等无需php处理的)则会直接返回给浏览器。如果是一个动态的php请求,nginx 就会通过cgi协议与 php 通信,将请求数据转换成 php 能理解的信息,php 处理完成也通过 cgi 协议返给 nginx,最后 nginx 再返回给浏览器。

fast-cgi

传统的 cgi 协议在每次连接请求时,会开启一个进程进行处理,处理完毕会关闭该进程。下次请求又重复开启与关闭。频繁的进程启动与关闭,消耗大量的资源和内存。而 fast-cgi 每次处理完请求后,不会 kill 掉这个进程,而是保留进程,使进程可以处理多次请求,不用重新 fork 一个进程,大大提高效率。

php-cgi

php-cgi 是 php 提供给 web serve 的 cgi 协议接口程序,每次请求都会开启一个 php-cgi 进程进行处理,而且开启php-cgi 会先重载配置,数据结构以及初始化运行环境,如果更新了 php 配置,那么就需要重启 php-cgi 才能生效,例如 phpstudy 就是这种情况。

php-fpm

1.php-fpm 是 php 提供给 web serve 的 fastcgi 协议接口程序,是 php-cgi 的一个管理程序。
2.php-fpm 常驻内存,会开启多个 php-cgi 进程,请求来的时候,php-fpm 将连接分配给一个 php-cgi 子进程处理,处理完毕后 php-cgi 并不会关闭,而是等待处理下一个连接,这也是 fast-cgi 加速的原理。
3.php-fpm 是多进程的,一个 php-cgi 大概消耗 7-25M 内存,需注意连接过多导致内存消耗过大的问题。
4.php-fpm支持平滑启动,如果更新了 php 配置可使用 /you_path/php-fpm reload 平滑过渡。

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 之间的通信

1.tcp socket ,面向连接的协议,更好的保证通信的正确性和完整性
2.unix socket,不需要网络协议打包拆包,开销小效率高,但高并发时候不稳定,可能返回异常。

网络7层协议模型

应用层、表示层、会话层、传输层、网络层、(数据)链路层、物理层。快记:应表会传(物链网)

TCP 和 UDP 的特点和区别

1.都是属于传输层协议
2.TCP,面向连接,一对一,数据可靠不丢失
3.UDP,无连接,一对多/多对多,速度更快但不可靠

TCP 的三次握手和四次挥手

1.三次握手:
1.第一次:客户端发送SYN = 1,seq = client_isn
2.第二次:服务端发送SYN = 1,seq = server_isn,ACK =client_isn +1
3.第三次:客户端发送SYN = 0, ACK = server_isn+1,seq =client_isn+1
2.四次挥手
1.第一次:客户端发送FIN
2.第二次:服务端发送ACK
3.第三次:服务端发送FIN
4.第四次:客户端发送ACK

HTTP 状态码

  • 1xx:请求进行中,服务器收到请求,需要请求者继续操作
  • 2xx:成功
  • 3xx:重定向
  • 4xx:客户端错误
  • 5xx:服务端错误

    oop是什么?

    面向对象编程是一种计算机编程架构思想,指程序由一个个能够起到子程序作用的单元或对象组成。 面向对象3大特性:继承、封装、多态。

    php垃圾回收机制

    “引用计数方式(is_ref_gc=0时回收)” + “标记清除方式(解决循环引用时回收)”来进行垃圾回收。

    什么是引用传递?

    引用传递:函数内对值的任何改变在函数外部也生效(传递地址)
    值传递:函数内对值的任何改变在函数外部不生效(复制值) 对大型字符串和对象来说,复制操作代价很大。引用传递会有不错的性能提升(对象默认为引用传递)。

    设计模式五大原则

单一职责原则:单一职责原则可以看做是低耦合、高内聚在面向对象原则上的引申,将职责定义为引起变化的原因,以提高内聚性来减少引起变化的原因。
开放封闭原则:核心理念“对扩展开放,对修改封闭”。设计时要允许现有代码进行扩展,而不是通过修改现有代码来实现新的功能。这样做可以避免对现有代码造成不必要的破坏和风险,同时也可以提高代码的复用性和可维护性,从而降低开发和维护成本。
接口隔离原则:不要强迫客户使用它们不用的方法,如果强迫用户使用它们不使用的方法,那么这些客户就会面临由于这些不使用的方法的改变所带来的改变。
依赖倒置原则:面向对象而不是面向过程。程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。
里氏替换原则:子类可以扩展父类的功能,但不能改变父类原有的功能 。
附:迪米特原则:一个对象应该对其他对象保持最少的了解。

常见的设计模式

单例模式、工厂模式、观察者模式、外观模式、代理模式…
1.创建型模式共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
2.结构型模式共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
3.行为型模式共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
单例模式:确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

public static function getInstance()
{
 return new static();
}

观察者模式:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并且有所作为。即出版者+订阅者=观察者模式。
工厂模式 :调用者和创建者分离,调用者直接向工厂类请求获取对象,减少代码耦合,提高系统的维护性和扩展性。
适配器模式:把对某些相似的类的操作转化为一个统一的“接口”(比喻的说法)–适配器,或者比喻为一个“界面”,统一或屏蔽了那些类的细节。适配器模式还构造了一种“机制”,使“适配”的类可以很容易的增减,而不用修改与适配器交互的代码,符合“减少代码间耦合”的设计原则。

冒泡排序/快速排序

冒泡排序是一种交换排序。对数组进行多轮冒泡,每一轮对数组中的元素两两比较,调整位置,冒出一个最大的数来。

/**
* 冒泡排序
* @param array $arr
*/
function bubbleSort(array $arr) : array
{
 $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) : void
{
 $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。
1.Cookie 的作用域由 domain 属性和 path 属性共同决定。所以可以通过把登录状态的seesion_id 存在主域名域下(当前域的父域),所有子域名就都可以共享了。
2.此种实现方式比较简单,但不支持跨主域名。
实现方式二:认证中心。
1.部署一个认证中心,专门负责处理登录请求的独立的 Web 服务。
2.用户统一在认证中心进行登录,登录成功后,认证中心记录用户的登录状态,并将 Token 写入 Cookie。(注意这个 Cookie 是认证中心的,应用系统是访问不到的)
3.应用系统检查当前请求有没有 Token,如果没有,那么就跳转至认证中心。而认证中心通过自动携带的 Cookie 判断是否已经登录。
4.如果认证中心发现用户尚未登录,则返回登录页面,等待用户登录。如果发现用户已经登录过了,就跳转回目标 URL (目标应用系统),并携带回传一个认证中心的 Token。
5.应用系统拿到 Token 之后,后端向认证中心确认下 Token 的合法性,防止用户伪造的同时check用户登录状态。确认无误后,应用系统记录用户的登录状态,并将 Token 写入 Cookie,访问放行。(此时Cookie 是当前应用系统的)当用户再次访问当前应用系统时,就会自动带上这个 Token,应用系统验证 Token,就实现了单点登录。
6.此种实现方式相对复杂,但支持跨域,扩展性好,是单点登录的标准做法。
实现方式三:LocalStorage 跨域。
1.在这样的场景下,单点登录完全可以在前端实现。前端拿到 Session ID (或 Token )后,除了将它写入自己的 LocalStorage 中之外,还可以通过特殊手段将它写入多个其他域下的 LocalStorage 中。
2.前端将同一份 Token 写入到了多个域下的 LocalStorage 中,前端每次在向后端发送请求之前,都会主动从 LocalStorage 中读取 Token 并在请求中携带,这样就实现了同一份 Token 被多个域所共享。
3.此种实现方式完全由前端控制,几乎不需要后端参与,同样支持跨域。但扩展性不好,不利于维护。

php的堆与栈

1.heap是堆,stack是栈;
2.heap上的空间手动分配/释放(程序运行时分配的内存),stack的空间由操作系统自动分配/释放(程序执行时为函数、局部变量等分配的内存空间);
3.zendVM中的malloc函数分配的内存空间即在堆上(mm_heap)
在PHP中,Zend引擎通过内存分配器来管理堆内存的分配和释放。当PHP执行过程中需要分配更多内存时,内存分配器会从堆中分配一块足够大的空间,供变量和数据结构使用。而当某个变量或数据结构不再使用时,内存分配器会将相应的内存空间返回给堆。

php底层相关理解

通常就是问:符号表(hashTable)、zvalue结构体、zend vm的内存分配等

php的运行模式

CGI 模式(phpstudy、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()函数

抽象类和接口分别是什么?

抽象类:就是一种特殊的类,不能被实例。可以定义方法,属性。类似于模版,规范后让子类实现详细功能。
接口:主要基于方法/对象的规范。可让某个类通过实现多个接口来形成新的类。
抽象类与接口的相同点:
1.都是用于声明某一种事物,规范名称、参数,形成模块,未有详细的实现细节。
2.都是通过类来实现相关的细节
3.语法上,抽象类的抽象方法与接口一样,不能有方法体,即{}符号
4.都可以用继承,接口继承接口形成新的接口,抽象类继承抽象类形成新的抽象类
抽象类与接口的不同点:
1.抽象类可以有属性、普通方法、抽象方法,但接口不能有属性、普通方法(可以有常量)
2.抽象类内未必有方法定义(可以都是普通方法),但接口内一定会有“方法定义”
3.抽象类用abstract关键字,class声明为类,接口用interface声明
4.抽象类的抽象方法一定要用abstract来声明,而接口不需要
5.抽象类是用extends关键字让子类继承,接口用implements实现接口

网站性能优化/高并发解决方法

1.前端优化
减少HTTP请求[将css,js等合并]
添加异步请求(非必须数据先不展示,用户触发某个事件才会异步请求数据)
CDN加速,建立独立的文件/图片服务器(减少I/O)
2.web服务器优化
防盗链处理(去除恶意请求)
反向代理实现负载均衡
静态资源缓存和gzip压缩
流量过滤,ip限制及黑白名单
3.应用程序优化
业务代码逻辑检查优化,sql查询优化
常驻内存swoole,opcache缓存技术,连接池技术
4.数据库优化
读写分离,负载均衡
redis缓存、数据库缓存策略
分表分区分库,数据拆分
表结构优化,索引优化

防止sql注入

验证数据,可以根据相应类型进行严格的验证。比如 int 类型直接同过 intval 进行转换; 参数化绑定,PDO参数绑定,禁止使用sql拼接;mysql开启严格模式;

8大魔术常量

1.LINE:文件中 本常量所在行的 行号(即处于第几行)。
2.FELE:本文件的完整路径和文件名。如果被用在 被包含文件中,则返回被包含文件的文件名。本常量总是包含一个绝对路径(如果是符号链接,则是解析后的绝对路径)
3.DIR:本文件所在目录。如果被用在 被包含文件中,则返回被包含文件的所在目录。它等价于 dirname(FILE)。除非是根目录,否则目录名中不包含末尾的斜杠。
4.FUNCTION:函数名称。自PHP5起本常量返回函数被定义时的名称(区分大小写)。
5.CLASS:类名称。自PHP5起本常量 返回类被定义时的名称(区分大小写,包括其命名空间。如:Foo\Bar)。
6.TRAIT:trait 的名称。自 PHP5.4 起本常量返回 trait 被定义时的名称(区分大小写)。
7.METHOD:类的方法名。返回该方法被定义时的名称(区分大小写)。
8.NAMESPACE:当前命名空间的名称(区分大小写)。本常量是在编译时定义的。

9个超全局变量

1.$_GLOBALS :储存全局作用域中的变量
2.$_SERVER :获取服务器相关信息
3.$_REQUEST:获取POST和GET请求的参数
4.$_POST : 获取表单的POST请求参数
5.$_GET: 获取表单的GET请求参数
6.$_FILES :获取上传文件的的变量
7.$_ENV : 获取服务器端环境变量的数组
8.$_COOKIE:获取浏览器的cookie
9.$_SESSION : 获取session

魔术方法

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()打印对象时被调用(当你不想打印所有属性)

请求的生命周期

1.构建请求
2.查找本地缓存
3.域名解析
4.与服务器建立连接(TCP的三次握手)
5.发起HTTP请求
6.服务器处理请求
7.服务器响应HTTP请求
8.客户端解析返回数据
9.与服务器断开连接(TCP的四次挥手)

网站打开慢怎么排查

1.打不开,则ping域名,看是否能请求成功。
2.慢,说明能打开,直接 free/top命令查看服务器内存和CPU使用情况,iftop等工具查看带宽
3.chrome的debug->network查看响应慢的请求
4.排查响应慢的接口代码,看php,mysql,redis等的日志看错误信息(mysql的慢查询日志,php-fpm慢日志,需要配置开启)

什么是MQ?

mq是一个消息队列,通常是解决传统的消息传输上管理困难,效率不高的问题。
mq有三大优点:解耦,异步,削峰
缺点: 增加了中间件,就提高了系统复杂度,增加了维护的成本。比如:要保证消息不丢失(一致性)和消息幂等性问题,还要保证mq的高可用等

Mysql相关

数据库三大范式是什么?

第一范式:1NF是对属性的原子性,要求属性具有原子性,不可再分解;
第二范式:2NF是对记录的唯一性,要求记录有唯一标识,即实体的唯一性,即不存在部分依赖;
第三范式:3NF是对字段的冗余性,要求任何字段不能由其他字段派生出来,它要求字段没有冗余,即不存

MyISAM与InnoDB的区别

1.MyISAM不支持事务与外键,InnoDB 支持。
2.MyISAM是表锁,InnoDB行锁(提高了并发性能)。
3.MyISAM表是保存成独立文件的形式,在数据转移、备份MyISAM更具有优势。
4.AUTO_INCREMENT:MyISAM 可以和其他字段一起建立联合索引,InnoDB中必须是只有该字段的索引
5.MyISAM支持 FULLTEXT类型的全文索引,InnoDB不支持,但插件sphinx支持全文索引(效果更好)。
6.MyISAM允许没有任何索引和主键的表存在,InnoDB没有主键会选择非空唯一索引,或自动生成一个6位的uuid主键
7.MyISAM的SELECT性能更好,InnoDB的INSERT、UPDATE、DELETE 更好(删除全表使用truncate table)
8.索引区别:
聚簇索引:索引和数据存储在一个节点
非聚簇索引:索引和数据分开存储,通过索引找到数据实际存储的地址
innodb 使用的聚簇索引,主键索引为聚簇索引(没有主键索引会选择一个非空唯一索引或隐式的创建一个主键索引),辅助索引指向主键索引,然后再找到实际存储地址
myisam 使用非聚簇索引(辅助索引和主键索引一样),都只需要查询一次就能找到数据
聚簇索引的优势和略势:
1.索引和数据在一起,同一页的数据会被缓存到(buffer)内存中,所以查看同一页数据的时候只需要从内存中取出
2.数据更新之后之只需要维护主键索引即可,辅助索引不受影响
3.辅助索引存的是主键索引的值,容易产生回表
4.使用隐式的uuid主键时,数据分布不均匀,导致聚簇索引可能扫全表,效率低下(强制使用自增主键id )
备注:b-tree(mongodb) 和 b+tree (mysql)的区别:
1.b+tree 的数据全部存储在叶子节点,主节点只存key,一次磁盘IO能获取到更多的节点
2.b+tree 增加了叶子节点到相邻节点的指针,数据是有序双向链表 ,方便返回查询范围(顺序性)
3.b-tree 的主节点和叶子节点都存储key和数据,查找数据不需要找到叶子节点,主节点可以直接返回数据

事务的ACID与隔离级别

事务遵循包括原子性在内的 ACID 四大特性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability);
原子性 :数据提交工作时,要么保证所有的修改都能够提交,要么就所有的修改全部回滚。
一致性:数据库从一个一致性状态变换到另一个一致性状态。
隔离性: 如果多个事务并发执行,应像各个事务独立执行一样。
持久性:一个成功执行得事务对数据库得作用是持久的,即使数据库发生故障出错,也应该能够恢复
四种隔离级别:
1.未提交读(read-uncommitted)所有事务都可以看到其他未提交事务的执行结果。很少用于实际应用,因为它的性能也不比其他级别好多少。会产生脏读,不可重复读以及幻读
2.已提交读(read-committed)这是大多数数据库系统的默认隔离级别(但不是 MySQL 默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。会产生幻读
3.可重复读(repeatable-read)这是 MySQL 的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,也会导致幻读 (Phantom Read)。幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的 “幻影” 行。InnoDB 存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。
4.串行化(serializable)这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。

MyISAM 表锁

1.共享读锁(S)之间是兼容的,但共享读锁(S)和排他写锁(X)之间,以及排他写锁之间(X)是互斥的,也就是说读和写是串行的。
2.在一定条件下,MyISAM 允许查询和插入并发执行,利用这一点来解决应用中对同一表和插入的锁竞争问题。
3.MyISAM 默认锁调度机制是写优先,不一定适合所有应用,可以通过设置 LOW_PRIPORITY_UPDATES 参数,或在 INSERT、UPDATE、DELETE 语句中指定 LOW_PRIORITY 选项来调节读写锁的争用。
4.由于表锁的锁定粒度大,读写之间又是串行的,因此,如果更新操作较多,MyISAM 表可能会出现严重的锁等待,可以考虑采用 InnoDB 表来减少锁冲突。

InnoDB 表

1.InnoDB 的行锁是基于索引实现的,如果不通过索引访问数据,InnoDB 会使用表锁。
2.在不同的隔离级别下,InnoDB 的锁机制和一致性读策略不同。
3.MySQL 的恢复和复制对 InnoDB 锁机制和一致性读策略也有较大影响。
4.注意死锁,锁冲突甚至死锁很难完全避免。

减少锁冲突和死锁

1.尽量使用较低的隔离级别
2.精心设计索引,尽量使用索引访问数据,使加锁更精确,从而减少锁冲突的机会。
3.选择合理的事务大小,小事务发生锁冲突的几率也更小。
4.给记录集显示加锁时,最好一次性请求足够级别的锁。比如要修改数据的话,最好直接申请排他锁,而不是先申请共享锁,修改时再请求排他锁,这样容易产生死锁。
5.不同程序访问一组表时,应尽量约定以相同的顺序访问,这样可以减少死锁的机会。
6.尽量用相等条件访问数据,这样可以避免间隙锁对并发插入的影响。
7.不要申请超过实际需要的锁级别;除非必须,查询时不要显示加锁。

分表 (分库) 的策略

根据业务数据量和业务复杂度来拆分,业务拆分可参考:取余、hash、range范围; 表结构拆分:垂直、水平。

binlog日志

通常用与:数据恢复、主从复制
可设置格式: statement 、 row 、 mixed(通常使用 row 或者 mixed )

主从同步

可用于: 实现读写分离 、 数据备份高可用、负载均衡提高性能、版本升级测试
流程:
1.从节点开启start slave 命令之后,创建一个IO进程连接到主节点
2.连接成功之后,主节点创建一个 log dump线程(主节点会为每一个从节点创一个log dump线程)
3.当binlog发生变化时,主节点的dump log线程会读取bin-log内容并发送给从节点
4.主节点dump log 线程读取bin-log 的内容时会对主节点的bin-log加锁,读取完成在发送给从节点之前释放锁
5.从节点的IO线程接收主节点发送的binlog内容,并将其写入本地relay log 文件中
6.主从节点通过binlog文件+position偏移量定位主从同步的位置,从节点会保存接收到的position偏移量,如果从节点发生宕机重启,自动从postion位置发起同步
7.从节点的SQL线程复制读取本地relay log的内容,解析成具体的操作并执行,保证主从数据一致性
模式: 异步模式(默认方式) 、 全同步模式 、 半同步模式 (几乎不用)

limit 优化

1.主键阈值法: 通过条件推算出符合条件的主键最大值&最小值来避免
2.配合es来分页

redis 缓存和 mysql 数据一致性

1.先更新redis 再更新数据库
2.先更新数据库,再更新redis
3.先删除缓存再更新数据库
问题:以上在并发同时请求时候都有可能出现数据不一致的情况。
解决: 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、Set、 Hash、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集群:集群可以自己进行选举
  • 选举流程:
    1.当主节点挂掉,从节点就会广播该主节点fail;
    2.延迟时间后进行选举(延迟的时间算法为:延迟时间+随机数+rank*1000,从节点数据越多,rank越小,因为主从数据复制是异步进行的,所以  所有的从节点的数据可能会不同),延迟的原因是等待主节点fail广播到所有存活的主节点,否则主节点会拒绝参加选举;
    3.参加选举的从节点向所有的存活的节点发送ack请求,但只有主节点会回复它,并且主节点只会回复第一个到达参加选举的从节点,一半以上的主节点回复,该节点就会成为主节点,广播告诉其他节点该节点成为主节点。
    四、节点扩容不同
    1.redis主从:只能扩容从节点,无法对主节点进行扩容;
    2.redis集群:可以扩容整个主从节点,但是扩容后需要进行槽位的分片,否则无法进行数据写入,命令为:

    其中的192.168.0.61:8001为新加入的主从节点;

    /usr/local/redis-5.0.3/src/redis-cli -a zhuge --cluster reshard 192.168.0.61:8001

    MongoDB相关

    mongodb是什么?

    MongoDB 是由 C++语言编写,是一个基于分布式文件存储的开源NoSQL数据库(文档数据库)。 再高负载的情况下,添加更多的节点,可以保证服务器性能。 旨在提供可扩展的高性能数据存储解决方案。

    mongodb有哪些特点?

1.MongoDB 是一个面向文档存储的数据库,操作起来比较简单和容易。
2.可以在 MongoDB 记录中设置任何属性的索引(如:FirstName=”Sameer”,Address=”8 Gandhi Road”)实现更快排序。
3.可以通过本地或者网络创建数据镜像,这使得 MongoDB 有更强的扩展性。
4.负载的增加(更多的存储空间和更强的处理能力),它可以分布在网络中的其他节点上这就是所谓的分片。
5.MongoDb 支持丰富的查询表达式。查询指令使用 JSON 形式的标记,可轻易查询文档中内嵌的对象及数组。
6.MongoDb 使用 update()命令可以实现替换完成的文档(数据)或者一些指定的数据字段 。
7.Mongodb 中的 Map/reduce 主要是用来对数据进行批量处理和聚合操作。
8.Map 和 Reduce,Map 函数调用 emit(key,value)遍历集合中的所有记录,将key与value传给Reduce函数处理。
9.Map和Reduce函数是用Javascript编写的,可以通过db.runCommand或mapreduce命令来执行MapReduce操作。
10.GridFS 是 MongoDB 中的一个内置功能,可以用于存放大量小文件。
11.MongoDB 允许在服务端执行脚本, 可以用 Javascript 编写某个函数,直接在服务端执行,也可以把函数的定义存储在服务端,下次直接调用即可。

MySQL与MongoDB之间最基本的差别是什么?

MySQL和MongoDB两者都是免费开源的数据库。MySQL和MongoDB有许多基本差别包括数据的表示(data representation),查询,关系,事务,schema的设计和定义,标准化(normalization),速度和性能。通过比较MySQL和MongoDB,实际上我们是在比较关系型和非关系型数据库(数据存储结构不同)。

MongoDB的特点/为啥是最好的Nosql数据库?

面向文件的、高可用(稳定可靠性能)、易扩展性、丰富的查询语言

MongoDB的集合collection

集合就是一组 MongoDB 文档。它相当于关系型数据库中的表概念。集合位于单独的一个数据库中。一个集合内的多个文档可以有多个不同的字段。一般来说,集合中的文档都有着相同或相关的目的。

MongoDB的文档Document

文档由一组key value组成(json)。是动态模式:同一集合里的文档可能是不同的字段和结构。文档相当于关系型数据库中table的一条记录。

什么是mongod?

mongod是处理MongoDB系统的主要进程。它处理数据请求,管理数据存储,和执行后台管理操作。当我们运行mongod命令意味着正在启动MongoDB进程,并且在后台运行。
默认端口: “27017”、默认存储路径:”/data/db”

MongoDB中的副本集

在MongoDB中副本集由一组MongoDB实例组成,包括一个主节点多个次节点,MongoDB客户端的所有数据都写入主节点(Primary),副节点从主节点同步写入数据,以保持所有复制集内存储相同的数据,提高数据可用性。

Elasticsearch相关

es简介

一个高扩展、生态化、开源的全文检索引擎,它可以准实时地快速存储、搜索、分析海量的数据。全文检索是指计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置。当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户。

es查询流程

1.客户端请求发给某个节点
2.节点转发给每个分片,查询每个分片上的前n条
3.结果返回给节点,合并整合数据,提取前n条
4.最后返回给请求客户端

ES 为什么比 mysql 快

es索引存于内存之中,采用倒序索引,结构为”分词<=>id”的方式,能通过分词快速定位文档(分词索引 vs b+tree)

本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由系统于 4个月前 自动加精
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 7

现在休息都是按半年起步,几个月不够哦 :grin:

5个月前 评论

招聘往boss一挂,简历不断

5个月前 评论

谢谢分享 正好需要

5个月前 评论

谢谢分享 正好需要

5个月前 评论

老哥牛逼,加个好友呗

4个月前 评论

今年的就业情况,一言难尽

4个月前 评论
自由与温暖是遥不可及的梦想

单点登出呢 有好的 方案么

4个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!