PHP面试八股文

面试造火箭 上班拧螺丝
“茴香豆的『回』字有几种写法你知道么”

php

php-fpm 的生命周期,创建进程方式,各自的优缺点(腾讯 百度 滴滴 陌陌)

PHP-FPM是一种多进程模型,主要由Master进程以及Worker进程组成,所有的cgi请求都会交由Worker进程处理。Master进程主要维护worker进程。
而worker进程的工作方式是抢占/竞争的方式,当一个accept请求过来的时候,谁先拿到算谁的,拿到后转化为FastCGIRequest,交由脚本处理。

php生命周期

数据初始化(MINT) => 请求初始化(RINT) => 编译脚本 (RSHUTDOWN) => 执行代码(MSHUTDOWN)

static 静态模式

启动的时候创建固定数量的worker进程,实际请求大于worker进程的时候 包warning

ondemand 按需分配模式

启动的时候不会创建worker进程, 根据需要创建,释放在idle_timeout之后

这样不能及时的释放连接和建立连接需要消耗资源

dynamic 动态模式(默认)

启动的是创建指定数量的worker进程, 根据情况合理的worker,定期检测worker,关闭闲置连接

php 数组遍历为什么能保证有序(滴滴)

为了实现插入与遍历的顺序一致性,在PHP7中,增加了一个中间映射层,它的大小与哈希表相同,存储了元素在bucket中最终存储的位置,我们把它叫做映射表

php 怎么实现的弱类型,怎么实现一个扩展(腾讯)

实现php弱类型变量

  1. 通过Zend引擎用C实现弱类型,在ZE中用结构体zval来保存
  2. 通过Zend引擎是判别、存储PHP中的多种数据类型,根据type来选择获取【zvalue_value】的值

实现一个扩展

常见魔术方法和函数(腾讯 滴滴)

  • __construct(): 类的构造函数

  • __destruct(): 类的析构函数

  • __call(): 当调用一个未定义或不可达方法时, __call () 方法将被调用。

  • __callStatic(): 当调用一个未定义或不可达的静态方法时, __callStatic () 方法将被调用。

  • __get(): 当获取一个类的成员变量时, __get () 方法将被调用。

  • __set(): 当赋值一个类的成员变量时, __set () 方法将被调用。

  • __isset(): 当调用 isset () 或 empty () 对一个未定义或不可达的成员赋值时, __isset () 方法将被调用。

  • __unset(): 当调用 reset () 对一个未定义或不可达的成员更新时, __unset () 方法将被调用。

  • __sleep(): 当执行序列化 serialize () 时,__sleep () 方法将首先被调用。

  • __wakeup(): 当执行反序列化 deserialization () 时, __wakeup () 方法将首先被调用。

  • __toString(): 当使用 echo 方法直接输出显示对象时,__toString () 方法首先被调用。

  • __invoke(): 使用调用函数(function)访问一个对象时, __invoke () 方法将首先被调用。

  • __set_state(): 当调用 var_export () 方法时,__set_state () 方法将被调用。

  • __clone(): 当对象被复制赋值时,__clone () 方法将被调用。

  • __autoload(): 试图载入一个未定义的类时调用。

  • __debugInfo(): 输出 debug 信息。

  • 16 个 PHP 开发者必知必会的魔术方法

mysql

有哪些事务隔离级别,Mysql 的事务隔离级别是怎么实现的?(每家都问)

事务的隔离性由锁来实现。 原子性、一致性、持久性通过数据库的redo log和undo log来实现。 redo log称为重做日志,用来保证事务的原子性和持久性,undo log用来保证事务的一致性。 MySQL的事务隔离级别一共有四个,分别是读未提交、读已提交、可重复读以及可串行化

索引原理(每家都问)

索引的本质是一种排好序的数据结构

索引的分类

分库分表的策略,如果要按照分表字段以外的字段作为查询条件怎么办(每家都问)

唯一主键

常见的分布式生成唯一ID的方式很多,最常见的雪花算法Snowflake、滴滴Tinyid、美团Leaf。以雪花算法举例来说,一毫秒可以生成4194304多个ID。

MVCC 和间隙锁原理(滴滴 字节 百度)

多版本并发控制(MVCC)是一种解决读-写冲突的无锁并发控制
每一行记录都有两个隐藏列:创建版本号和回滚指针。事务开启后存在一个事务id。多个并发事务同时操作某行,不同的事务对该行update操作会产生多个版本,然后通过回滚指针组成undo log链。而MVCC的快照读正是通过事务id和创建版本号从而实现的快照读。

注意:只有RR隔离级别才存在间隙锁。

explain 的 type 字段有哪些(知乎)

  • system: 系统表,少量数据,往往不需要进行磁盘IO
  • const: 常量连接
  • eq_ref: 主键索引(primary key)或者非空唯一索引(unique not null)等值扫描
  • ref: 非主键非唯一索引等值扫描
  • range: 范围扫描
  • index: 索引树扫描
  • ALL: 全表扫描(full table scan)

type扫描方式由快到慢

system > const > eq_ref > ref > range > index > ALL

update 语句的执行流程,binlog 的作用和几种格式(滴滴)

binlog 的作用和几种格式

binlog一般情况下分为三种格式,分别是row格式、statement格式、mixed格式

  • row格式: 此格式不记录sql语句上下文相关信息,仅保存哪条记录被修改。
  • statement: 该格式下每一条会修改数据的sql都会记录在binlog中。
  • mixed: 该格式是以上两种level的混合使用,一般的语句修改使用statement格式保存binlog,当statement无法完成主从复制的操作时(设计一些函数时),则采用Row格式保存binlog

主从同步的原理和问题(字节 滴滴 陌陌)

主从复制原理

  1. 在主库上把数据更改记录到二进制日志binary log中,具体是在每次准备提交事务完成数据更新前,主库将数据更新的事件记录到二进制日志中去,Mysql会按照事务提交的顺序来记录二进制日志的。日志记录好之后,主库通知存储引擎提交事务。
  2. 从库会启动一个IO线程,该线程会连接到主库。而主库上的binlog dump线程会去读取主库本地的binlog日志文件中的更新事件。发往从库,从库接收到日志之后会将其记录到本地的中继日志relay-log当中。
  3. 从库中的SQL线程读取中继日志relay-log中的事件,将其重放到从库中。(在5.6版本之前SQL线程是单线程的,使得主从之间延迟更大)

延迟问题

  • 延迟的产生:

    • 当主库的TPS并发较高时,由于主库上面是多线程写入的,而从库的SQL线程是单线程的,导致从库SQL可能会跟不上主库的处理速度(生产者比消费者快,导致商品堆积)。
  • 延迟的解决:

    • 网络方面:将从库分布在相同局域网内或网络延迟较小的环境中。
    • 硬件方面:从库配置更好的硬件,提升随机写的性能
    • 配置方面:从库配置sync_binlog=0,innodb_flush_log_at_trx_commit=2,logs-slave-updates=0,增大innodb_buffer_pool_size,让更多操作在Mysql内存中完成,减少磁盘操作。或者升级Mysql5.7版本使用并行复制
    • 架构方面:比如在事务当中尽量对主库读写,其他非事务中的读在从库。消除一部分延迟带来的数据库不一致。增加缓存降低一些从库的负载。

发生死锁的原因以及如何解决(滴滴 顺丰)

发生死锁的原因

  1. 互斥条件
  2. 不可剥夺条件(不可抢占)
  3. 部分分配
  4. 循环等待

死锁处理方法

  1. 通过协议来预防或避免死锁,确保系统不会进入死锁状态。
  2. 可以允许系统进入死锁状态,然后检测它,并加以恢复。
  3. 可以忽视这个问题,认为死锁不可能在系统内发生

如何优化大 offset(陌陌)

当offset特别大时,这条语句的执行效率会明显减低,而且效率是随着offset的增大而降低的。

MySQL并不是跳过offset行,而是取offset+N行,然后返回放弃前offset行,返回N行,当offset特别大,然后单条数据也很大的时候,每次查询需要获取的数据就越多,自然就会很慢。

  • 解决方法
    先获取主键列表,再通过主键查询目标数据,即使offset很大,也是获取了很多的主键,而不是所有的字段数据,相对而言效率会提升很多。
1
2
3
4
5
6
7
8
9
10
11
select 需要的字段 
from
(
select <a.id 或 b.id> as id
from a join b on a.id=b.id
where <筛选条件>
order by <一些字段>
limit <limit_param> offset <offset_param>
) c join a on c.id=a.id
join b on c.id=b.id
order by <一些字段>

redis

缓存如何保证一致性(每家都问)

  1. 执行顺序的问题:先更新缓存还是先更新数据库?
  2. 更新缓存的策略问题:当缓存中的内容变化时,是选择修改缓存(update),还是直接淘汰缓存(delete)?

针对这两点问题,一共可以分为四种方案:

  1. 先更新缓存,再更新数据库
  2. 先更新数据库,再更新缓存
  3. 先淘汰缓存,再更新数据库 (适用于对一致性要求高的业务)
  4. 先更新数据库,再淘汰缓存

用过 redis 哪些数据结构,使用场景是什么(每家都问)

  • string(字符串): 常见的key-value存储

  • list(列表):

    • 消息队列: lpoprpush或者反过来,lpushrpop)能实现队列的功能
    • 朋友圈点赞列表, 评论列表, 排行榜
  • hash(字典):

    • 购物车: hset [key] [field] [value] 命令, 可以实现以用户Id,商品Id为field,商品数量为value,恰好构成了购物车的3个要素。
    • 存储对象:hash类型的(key, field, value)的结构与对象的(对象id, 属性, 值)的结构相似,也可以用来存储对象。
  • set(集合):

    • 好友、关注、粉丝、感兴趣的人集合
      1. sinter命令可以获得A和B两个用户的共同好友;
      2. sismember命令可以判断A是否是B的好友;
      3. scard命令可以获取好友数量;
      4. 关注时,smove命令可以将B从A的粉丝集合转移到A的好友集合
    • 首页展示随机:美团首页有很多推荐商家,但是并不能全部展示,set类型适合存放所有需要展示的内容,而srandmember命令则可以从中随机获取几个
    • 存储某活动中中奖的用户ID ,因为有去重功能,可以保证同一个用户不会中奖两次。
  • zset(有序集合):

    • zset 可以用做排行榜,但是和list不同的是zset它能够实现动态的排序,例如: 可以用来存储粉丝列表,value 值是粉丝的用户 ID,score 是关注时间,我们可以对粉丝列表按关注时间进行排序。
  • Redis 5种数据结构 及使用场景分析

redis 的 connect 和 pconnect 的区别,pconnect 有什么问题(滴滴 陌陌)

  • connect: 脚本结束之后连接就释放了
  • pconnect: 脚本结束之后连接不释放,连接保持在php-fpm进程中

pconnect 有什么问题

  1. 当使用pconnect时,连接会被重用,连接的生命周期是fpm进程的生命周期,而非一次php的执行
  2. 如果代码中使用pconnect, close的作用仅是使当前php不能再进行redis请求,但无法真正关闭redis长连接,连接在后续请求中仍然会被重用,直至fpm进程生命周期结束。

redis 如何实现分布式锁,有什么问题(陌陌)

利用 Redis 的 SETNX 命令,此命令同样是原子性操作,只有在 key 不存在的情况下,才能 set 成功。而基于 Redis 多机实现的分布式锁 Redlock,是 Redis 的作者 antirez 为了规范 Redis 分布式锁的实现,提出的一个更安全有效的实现机制

不管是哪种实现方式,均需要实现加锁、解锁、锁超时这三个分布式锁的核心要素

redis 为什么用跳表实现有序集合?原理,用有序集合的场景(字节 滴滴)

    1. 按照区间来查找数据这个操作,红黑树的效率没有跳表高
    1. 跳表更容易代码实现
    1. 跳表更加灵活,它可以通过改变索引构建策略,有效平衡执行效率和内存消耗
  • Redis 选择用跳表来实现有序集合的原因

跳表数据结构

  • 跳表使用空间换时间的设计思路,通过构建多级索引来提高查询的效率,实现是基于“二分查找”的链表操作
  • 跳表是一种动态数据结构,支持快速的插入、删除、查找操作,时间复杂度都是 O(logn)
  • 跳表的空间复杂度是 O(n),不过,跳表的实现非常灵活,可以通过改变索引构建策略,有效平衡执行效率和内存消耗。
  • 虽然跳表的代码实现并不简单,但是作为一种动态数据结构,比起红黑树来说,实现要简单多了。所以很多时候,我们为了代码的简单、易读,比起红黑树,我们更倾向用跳表。

主从同步的原理,哨兵和集群的区别(滴滴)

  • 主从复制: 读写分离,备份,一个Master可以有多个Slaves。
  • 哨兵: 监控,自动转移,哨兵发现主服务器挂了后,就会从slave中重新选举一个主服务器。
  • 集群: 为了解决单机Redis容量有限的问题,将数据按一定的规则分配到多台机器,内存/QPS不受限于单机,可受益于分布式集群高扩展性。

哨兵(sentinel)着眼于高可用; 集群(cluster)提高并发量

redis cluster 用的什么协议同步数据,哨兵的选举呢(陌陌)

Gossip协议 又称 epidemic 协议(epidemic protocol)

哨兵选举

主节点被标记为 Fail 后,对应的从节点会发起投票,竞争升主。历经从节点拉票、主节点投票、投票裁决等环节,最终完成选举。

  1. 从节点拉票
  2. 拉票优先级
  3. 主节点投票
  4. 根据投票结果决策
  5. 选举失败
  6. 选举算法 (选举新主节点的算法是基于 Raft 算法的 Leader Election 方法来实现的)

rdb 和 aof 的原理(滴滴 高德)

  • RDB: 生成指定时间间隔内的 Redis 内存中数据快照,是一个二进制文件 dump.rdb
  • AOF: 记录 Redis 除了查询以外的所有写命令,并在Redis 服务启动时,通过重新执行这些命令来还原数据。

区别

  • RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。

  • AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式追加记录,可以打开文件看到详细的操作记录。

  • RDB 和 AOF 持久化的原理是什么?我应该用哪一个?它们的优缺点?

数据过期和淘汰策略(滴滴 高德 字节)

数据过期

Redis中主要使用 定期删除 + 惰性删除 两种数据过期清除策略

  • 定期删除:redis默认每隔100ms就随机抽取一些设置了过期时间的key,检查其是否过期,如果有过期就删除。注意这里是随机抽取的。为什么要随机呢?你想一想假如 redis 存了几十万个 key ,每隔100ms就遍历所有的设置过期时间的 key 的话,就会给 CPU 带来很大的负载。
  • 惰性删除:定期删除可能导致很多过期的key 到了时间并没有被删除掉。这时就要使用到惰性删除。在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间并且过期了,是的话就删除。

淘汰策略

Redis共提供了8中缓存淘汰策略,其中 volatile-lfu 和 allkeys-lfu 是Redis 4.0版本新增的
通常情况下推荐优先使用 allkeys-lru 策略。

  • noeviction: 不进行淘汰数据

  • volatile-ttl: 在设置了过期时间的键值对中,移除即将过期的键值对

  • volatile-random: 在设置了过期时间的键值对中,随机移除某个键值对

  • volatile-lru: 在设置了过期时间的键值对中,移除最近最少使用的键值对

  • volatile-lfu: 在设置了过期时间的键值对中,移除最近最不频繁使用的键值对

  • allkeys-random: 在所有键值对中,随机移除某个key

  • allkeys-lru: 在所有的键值对中,移除最近最少使用的键值对。

  • allkeys-lfu: 在所有的键值对中,移除最近最不频繁使用的键值对

  • Redis的数据过期清除策略 与 内存淘汰策略

缓存雪崩 击穿 穿透(滴滴 陌陌)

elasticsearch

深度分页会有什么问题(滴滴 百度 陌陌)

深度分页问题大致可以分为两类

  • 随机深度分页: 随机跳转页面
  • 滚动深度分页: 只能一页一页往下查询

from/size

es 目前支持最大的 skip 值是 max_result_window ,默认 为 10000 。也就是当 from + size > max_result_window 时,es 将返回错误

scroll

使用scroll,每次只能获取一页的内容,然后会返回一个scrollid,根据scrollid可以不断地获取下一页的内容,所以scroll并不适用于有跳页的情景。但是在真正的使用场景中,第10000条数据已经是很后面的数据了,可以“折衷”一下,不提供跳转页面功能,只能下一页的翻页。

Scroll方式通过一次查询请求后维护一个临时的索引快照的search context
此后的增删查改操作并不会影响这个快照数据信息,后续的查询只需要根据游标去取数据,直到结果集中返回的 hits 字段为空,就表示遍历结束。效率比较高。在5.x之后,还可以通过slice分片来实现并行导出。

search_after

searchAfter的方式通过维护一个实时游标来避免scroll的缺点,它可以用于实时请求和高并发场景。

它的缺点是不能够随机跳转分页,只能是一页一页的向后翻,并且需要至少指定一个唯一不重复字段来排序(注:每个文档具有一个唯一值的字段应该用作排序规范的仲裁器。否则,具有相同排序值的文档的排序顺序将是未定义的。建议的方法是使用字段_id,它肯定包含每个文档的一个唯一值)。

倒排索引的原理(字节 高德)

倒排索引由两个部分组成:单词词典和倒排文件。

  • 单词词典: 单词词典是由文档集合中出现过的所有单词构成的字符串集合,单词词典内每条索引项记载单词本身的一些信息以及指向“倒排列表”的指针。
  • 倒排文件: 所有单词的倒排列表顺序的存储在磁盘的某个文件里,这个文件即被称为倒排文件,倒排文件是存储倒排索引的物理文件。

lsm 树原理(字节)

LSM树(Log Structured Merge Tree,结构化合并树)的思想非常朴素,就是将对数据的修改增量保持在内存中,达到指定的大小限制后将这些修改操作批量写入磁盘(由此提升了写性能),是一种基于硬盘的数据结构,与B-tree相比,能显著地减少硬盘磁盘臂的开销。

kafka

kafka 的架构,大致储存结构(高德 字节 滴滴)

如果消费者数超过分区数会怎么样?(顺丰 滴滴)

怎么保证数据的可靠投递?(陌陌 字节)

消费者的 offset 存在哪里?(字节 腾讯 陌陌)

如何通过 offset 定位消息?(字节)

时间轮的原理(陌陌 顺丰)

kafka 写入高性能的原因,sendfile 和 mmap 原理,为什么不用 splice(滴滴)

网络

https 原理,tls 握手需要几个 rtt?(滴滴 百度)

HTTPS是在HTTP上建立SSL加密层,并对传输数据进行加密,是HTTP协议的安全版。

SSL(Secure Socket Layer 安全套接字层) / TLS(Transport Layer Security 传输层安全协议)
RTT(Round Trip Time 往返时间)

TLS 握手就需要消耗两个 RTT
在 TLS 1.2 中,我们需要 2-RTT 才能建立 TLS 连接10,但是 TLS 1.3 通过优化协议,将两次往返延迟降低至一次

总结一下 HTTPS 协议需要 9 倍时延才能完成通信的原因:

  1. TCP 协议需要通过三次握手建立 TCP 连接保证通信的可靠性(1.5-RTT)
  2. TLS 协议会在 TCP 协议之上通过四次握手建立 TLS 连接保证通信的安全性(2-RTT)
  3. HTTP 协议会在 TCP 和 TLS 上通过一次往返发送请求并接收响应(1-RTT)

浏览器访问某个网址的详细过程,四次挥手(腾讯 滴滴)

  1. 获得域名所对应的IP地址,若DNS缓存中没有相关数据,则浏览器向DNS服务器发出DNS请求,以获取域名所对应的IP地址。
  2. 浏览器与域名地址建立TCP连接,三次握手
  3. HTTP访问
  4. 断开TCP链接, 四次挥手

http2 和 quic 原理(字节)

HTTP2

  1. 二进制分帧(Binary Format)
  2. 多路复用(Multiplexing)/连接共享
  3. 头部压缩(Header Compression)
  4. 压缩原理
  5. 请求优先级(Request Priorities)
  6. 服务端推送(Server Push)

Quic

Quic (Quick Udp Internet Connection 快速UDP互联网连接)

Quic 相比现在广泛应用的 http2+tcp+tls 协议有如下优势

  1. 减少了 TCP 三次握手及 TLS 握手时间
  2. 改进的拥塞控制
  3. 避免队头阻塞的多路复用
  4. 连接迁移
  5. 前向冗余纠错

分布式系统

分布式事务怎么处理(高德 陌陌)

简述 raft 原理(陌陌)

分布式 id 的几种实现和优缺点(滴滴)

降级 限流 熔断实现原理(高德 陌陌)

系统设计

设计秒杀系统,需要支持 100W 以上 QPS(滴滴)

设计微博首页,需要拉取所有关注用户的最近 20 条微博(百度)

抢红包算法设计(百度 滴滴)

设计一个短链系统(百度)

其他

布隆过滤器的实现原理和使用场景(滴滴)

进程间通信有哪几种方式(腾讯)

进程线程协程区别(滴滴 知乎)

lvs 原理,如何保证高可用(滴滴)

502 504 什么原因,如何处理(滴滴 百度 腾讯 顺丰)

给你两个一模一样的玻璃球,求出 100 层楼哪一层开始玻璃球会被摔碎(腾讯)

一致性 hash 原理,怎么解决节点少数据倾斜的问题(滴滴 陌陌)

Powered by Hexo and Hexo-theme-hiker

Copyright © 2017 - 2023 Keep It Simple And Stupid All Rights Reserved.

访客数 : | 访问量 :