记一次Web开发工程师面试记录

记录一次某游戏公司的PHPWeb开发工程师的面试记录(苦逼的应届毕业生)

(1)面试官:请你描述一下请求一个PHP的完成过程(Nginx)

我的回答:发起一个PHP请求,Nginx服务器会监听到这个PHP请求,反向代理的PHP-FPM容器进行解析,最终将解析结果返回。(因为只是大概了解一下,讲的不是很清晰)。

PHP+Nginx的具体实现原理
php工作原理

首先先了解下常听说的cgi,php-cgi,fastcgi,php-fpm到底是什么关系,帮助了解php的工作原理

cgi协议

cgi协议用来确定webserver(例如nginx),也就是内容分发服务器传递过来什么数据,什么样格式的数据

php-cgi进程解释器

php-cgi是php的cgi协议进程解释器,每次启动时,需要经历加载php.ini文件->初始化执行环境->处理请求->返回内容给webserver->php-cgi进程退出的流程

fastcgi协议

fastcgi协议是对cgi协议效率提升的补充,主要是针对每次请求过来时都需要启动一个cgi解释器进程的优化,不再需要cgi解释器进程每次收到webserver请求后都需要重新加载php.ini文件和初始化执行环境

php-fpm进程管理器

php-fpm是对fastcgi协议的实现,是进程管理器,启动时包括master和worker进程俩部分,master进程负责管理worker进程,worker进程一般具有多个,用来监听端口,接收来自webserver请求,且每个worker进程都有一个cgi进程解释器,用来执行php代码

php启动和工作原理

启动phpfpm时,会启动master进程,加载php.ini文件,初始化执行环境,并启动多个worker进程。每次请求来时监听端口的worker进程会进行处理

php平滑重启原理

每次修改完php.ini配置并重启后,会启动新的worker进程加载新的配置,而之前已经存在的进程会在工作完成之后销毁,因此实现平滑重启

nginx工作原理

如果想弄明白nginx和php配合的原理,还需要先了解nginx的配置文件中的server部分
`server {
listen 80; #监听80端口,接收http请求
server_name www.example.com; #一般存放网址,表示配置的哪个项目
root /home/wwwroot/zensmall/public/; # 存放代码的根目录地址或代码启动入口
index index.php index.html; #网站默认首页

#当请求网站的url进行location的前缀匹配且最长匹配字符串是该配置项时,按顺序检查文件是否存在,并返回第一个找到的文件
location / {
      #try_files,按顺序检查文件是否存在,返回第一个找到的文件
      #$uri代表不带请求参数的当前地址
      #$query_string代表请求携带的参数
      try_files   $uri $uri/ /index.php?$query_string; #按顺序检查$uri文件,$uri地址是否存在,如果存在,返回第一个找到的文件;如果都不存在,发起访问/index.php?$query_string的内部请求,该请求会重新匹配到下面的location请求
}

 #当请求网站的php文件的时候,反向代理到php-fpm去处理
location ~ \.php$ {
      include       fastcgi_params; #引入fastcgi的配置文件
      fastcgi_pass   127.0.0.1:9000; #设置php fastcgi进程监听的IP地址和端口
      fastcgi_index  index.php; #设置首页文件
      fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name; #设置脚本文件请求的路径
}

} `

总结

下面总结下最简单的用户请求流程:

用户访问域名->域名进行DNS解析->请求到对应IP服务器和端口->nginx监听到对应端口的请求->nginx对url进行location匹配->执行匹配location下的规则->nginx转发请求给php->php-fpm的worker进程监听到nginx请求->worker进程执行请求->worker进程返回执行结果给nginx->nginx返回结果给用户

链接:https://segmentfault.com/a/1190000018265488
来源:SegmentFault 思否

(2)面试官:Nginx在这其中是担任什么样的角色?

我的回答:中间件。Nginx监听到请求反向代理给PHP-FPM,充当一个中间件的角色。

(3)面试官:Nginx参数配置好之后,如何让参数重新生效

我的回答:sudo nginx restart
面试官:万一是在线上配置文件出错了怎么办?
面试官:可以使用nginx -t 进行配置检查,如果没出错在执行热加载 nginx reload -s

(4)面试官:Redis可以存储的数据类型有哪些?

我的回答:String、Set、Hash、List、zSet等数据类型

(5)面试官:有没有了解过Redis雪崩、击穿和穿透?

我的回答: 有了解过,但是具体没去深究(内心怂的一批,就听过这个名词)
面试官:可以去看看那个Redis小白手册,里面讲的很清楚

redis雪崩、击穿、穿透

1、redis雪崩效应

由于redis设置失效时间,当所有key在同一时间失效,并发直接打入DB,导致DB崩溃。

举个简单的例子:如果所有首页的Key失效时间都是12小时,中午12点刷新的,我零点有个秒杀活动大量用户涌入,假设当时每秒 6000 个请求,本来缓存在可以扛住每秒 5000 个请求,但是缓存当时所有的Key都失效了。此时 1 秒 6000 个请求全部落数据库,数据库必然扛不住,它会报一下警,真实情况可能DBA都没反应过来就直接挂了。此时,如果没用什么特别的方案来处理这个故障,DBA 很着急,重启数据库,但是数据库立马又被新的流量给打死了。这就是我理解的缓存雪崩。

我刻意看了下我做过的项目感觉再吊的都不允许这么大的QPS直接打DB去,不过没慢SQL加上分库,大表分表可能还还算能顶,但是跟用了Redis的差距还是很大。

解决:
处理缓存雪崩简单,在批量往Redis存数据的时候,把每个Key的失效时间都加个随机值就好了,这样可以保证数据不会在同一时间大面积失效,我相信,Redis这点流量还是顶得住的。

如果Redis是集群部署,将热点数据均匀分布在不同的Redis库中也能避免全部失效的问题,不过本渣我在生产环境中操作集群的时候,单个服务都是对应的单个Redis分片,是为了方便数据的管理,但是也同样有了可能会失效这样的弊端,失效时间随机是个好策略。

或者设置热点数据永远不过期,有更新操作就更新缓存就好了(比如运维更新了首页商品,那你刷下缓存就完事了,不要设置过期时间),电商首页的数据也可以用这个操作,保险。

2、缓存穿透

缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,我们数据库的 id 都是1开始自增上去的,如发起为id值为 -1 的数据或 id 为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大,严重会击垮数据库。

解决:
接口层增加校验,比如用户鉴权校验,参数做校验,不合法的参数直接代码Return

3、缓存击穿

这个跟缓存雪崩有点像,但是又有一点不一样,缓存雪崩是因为大面积的缓存失效,打崩了DB,而缓存击穿不同的是缓存击穿是指一个Key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个Key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个完好无损的桶上凿开了一个洞。

解决:
从缓存取不到的数据,在数据库中也没有取到,这时也可以将对应Key的Value对写为null、位置错误、稍后重试这样的值具体取啥问产品,或者看具体的场景,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。
这样可以防止攻击用户反复用同一个id暴力攻击,但是我们要知道正常用户是不会在单秒内发起这么多次请求的,那网关层Nginx本渣我也记得有配置项,可以让运维大大对单个IP每秒访问次数超出阈值的IP都拉黑。

原文链接:https://www.cnblogs.com/ling-diary/p/9292595.html

面试官:(6) Redis的持久化有哪些?

我的回答:内存快照、以及日志追加方式(我大概记得是这两个,但是具体名不太记得)

Redis的RDB跟AOF

RDB(内存快照):Redis每隔一段时间将进行一次内存快照操作,客户端使用save或者bgsave命令告诉Redis需要做一次内存快照操作。save命令在主线程中保存内存快照,Redis由单线程处理所有请求,执行save命令可能会阻塞其他客户端的请求,从而不能导致快速相应请求,所以不建议使用save。闪存快照每次都是把内存数据完整的写入硬盘,如果数据量大,严重影响性能。
AOF(日志追加)是把增加、修改的数据的命令通过wirte函数追加到文件尾部,Redis重启动时读取文件中的所有命令并执行,从而将数据保存到内存中(默认的文件为appendonly.aof。另外操作系统内核的I/O接口可能存在缓存,所以追加日志的方式不可能立即写入文件中,这样就有可能丢失一部分数据。但是Redis提供了解决方法,通过修改配置文件可以告诉Redis什么时候进行强制写入磁盘(每秒、每修改、不同步)。

(7)面试官:线程跟进程有什么区别?

我的回答:(内心大概知道他们之前的区别,但是文字组织描述起来贼乱,说的很乱)进程包含了线程,一个进程可以由多个线程执行

线程跟进程的区别

进程是资源分配最小单位,线程是程序执行的最小单位;

进程有自己独立的地址空间,每启动一个进程,系统都会为其分配地址空间,建立数据表来维护代码段、堆栈段和数据段,线程没有独立的地址空间,它使用相同的地址空间共享数据;

CPU切换一个线程比切换进程花费小;

创建一个线程比进程开销小;

线程占用的资源要⽐进程少很多。

线程之间通信更方便,同一个进程下,线程共享全局变量,静态变量等数据,进程之间的通信需要以通信的方式(IPC)进行;(但多线程程序处理好同步与互斥是个难点)

多进程程序更安全,生命力更强,一个进程死掉不会对另一个进程造成影响(源于有独立的地址空间),多线程程序更不易维护,一个线程死掉,整个进程就死掉了(因为共享地址空间);

进程对资源保护要求高,开销大,效率相对较低,线程资源保护要求不高,但开销小,效率高,可频繁切换;
————————————————
版权声明:本文为CSDN博主「码上寒山石径斜」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wsq119/article/details/82154305

总结:

2020年应届生找一个合适且不错的工作是真的难,各种公司要求不断上升,岗位也不断缩少。但是归根到底,还是自己的技术水平还是停留到很基础的水平,这次面试的题目总体来说难度都是很一般,但是我回答也不是特别好。对于这次面试,了解到当一个PHPer并不是说学号PHP以及Mysql数据就好的,还要了解之外的很多东西。要去深入理解原理,并不能停留的表面,不的话就会像我今天面试一样,知道是什么但是说不出,学习最大的进步就是要不断实践、不断总结。总体来说,这次面试的收获还是不少的,希望自己能查缺补漏、持续学习!加油!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值