2020年PHP中级面试知识点及答案 您所在的位置:网站首页 php面试常见问题及答案解析 2020年PHP中级面试知识点及答案

2020年PHP中级面试知识点及答案

2024-07-09 18:54| 来源: 网络整理| 查看: 265

一、前言

      最近博主也是历尽千辛万苦换了份工作,每次换之前不找点面试题看似乎就没自信一样。。奈何网上有些面试题是比较老套的,所以这里重新总结一份2020年的,题目是有些是博主自己不熟悉的点,有些是boss直聘论坛找到的,有的是朋友的面试经历,仅作为记录。

      以下面试题部分带有博主自己学习时候写下的答案,也许并不全或者并不正确,大家只看题就好,希望能对大家有所帮助。

二、零散的知识点 1、laravel相关面试题 (1)什么是服务提供者 (2)什么是容器,什么是依赖注入,控制反转 (ok) (3)laravel的流程 (4)laravel的路由机制 (从index.php到router的web.php,然后找到对应的控制器和方法) 2、一个人余额有10块,买了一个8块的东西,同时点击100次,那这个订单会不会重复,并说出解决方案 (1)隔离级别串行化? (2)RR隔离级别+间隙锁next-key (3)redis的hash保证唯一性,随后再同步db 3、zookeeper是什么 配置管理,名字服务,提供分布式同步以及集群管理。目前HBase使用它来维护集群的配置信息,Kafka使用Zookeeper来维护broker的信息 zookeeper使用zab协议实现强一致性,1、选举出leader;2、同步节点之间的状态达到数据一致;3、数据的广播 4、rpc是什么? 答:RPC就是要像调用本地的函数一样去调远程函数 主要作用: (1)解决分布式系统中,服务之间的调用问题 (2)远程调用时,要能够像本地调用一样方便,让调用者感知不到远程调用的逻辑。 原理步骤: (1)call_id映射:客户端和服务端维护一个类似于的表,对应方法id和方法名。当远程调用的时候,需要的传递id过去, 这样服务端才能知道你要调用哪个方法。一般是一个哈希表 (2)序列化和反序列化。由于传输都是二进制的,所以传输前要序列化,收到数据要反序列化 (3)网络传输,一般使用tcp协议,也可以是udp 场景: 5、分布式面临的首要问题就是nginx的负载均衡 (1)什么是负载均衡 (2)负载均衡实践 1、轮询 2、权重 3、绑定ip.ip_hash算法。 可以解决session不同步问题,但是均衡性差。比如高校等局域网ip一致,不能有效区分 (3)四层,七层负载均衡? 四层:IP+端口的负载均衡 七层:基于URL等应用层信息,可以分析应用层的信息,如HTTP协议URI或Cookie信息 6、nginx面试题 Nginx 常用命令有哪些? 需要熟悉:nginx -t ,nginx -s stop 之类 Nginx 返回 502 错误的可能原因? (1)进程数不够,需要更改配置 (2)php-fpm自动重启问题 (3)php-fpm请求超时 (4)是否有大量数据库句柄没释放,导致进程卡住 Nginx的504错误一般是fastcgi的超时配置方面有问题 正向代理和反向代理之间的区别是什么? 正向代理:代理端代理的是客户端反向代理:代理端代理的是服务端 什么是负载均衡? 代理服务器将接收的请求均衡的分发到各服务器 (1)session同步问题 1、使用cookies (户端把cookie禁掉了的话,那么session就无从同步) 2、存储到数据库 (增加数据库的负担。而且数据库读写速度较慢,不利于session的适时同步) 3、存到memcache或者redis缓存(常用) (2)一般是lvs做4层负载;nginx做7层负载(也能做4层负载, 通过stream模块) 七层负载均衡基本都是基于http协议的,适用于web服务器的负载均衡。(nginx) 四层负载均衡主要是基于tcp协议报文,可以做任何基于tcp/ip协议的软件的负载均衡。(haproxy、LVS) 7、swoole必须要学习下 (1) https://blog.csdn.net/DarkAngel1228/article/details/82053360 (swoole的一些基础概念) 新建laravel项目来使用swoole做一些简单的demo (2)easyswoole的文档 http://noobcourse.php20.cn/NoobCourse/Introduction.html#%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A8 (3)swoole的文档 http://wiki.swoole.com/wiki/page/487.html (4)共享变量 (5)协成 (6)go的channel 8、linux查看性能调试等命令 top/iostat/vmstat/free/strace/tcpdump 等监控工具 top和iostat是查看cpu和硬盘的使用情况 strace是可以调试程序的,显示系统调用的步骤 free是查看内存的使用情况的 9、epoll是干什么的 (此处仅作为了解) (1)select,poll,epoll都是IO多路复用的机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。 (2)select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。 (3)epoll可以理解为event poll,不同于忙轮询和无差别轮询,epoll会把哪个流发生了怎样的I/O事件通知我们。所以我们说epoll实际上是事件驱动(每个事件关联上fd)的,此时我们对这些流的操作都是有意义的。(复杂度降低到了O(1)) (4)表面上看epoll的性能最好,但是在连接数少并且连接都十分活跃的情况下,select和poll的性能可能比epoll好,毕竟epoll的通知机制需要很多函数回调。 (5)epoll是线程安全的 (6)nginx和epoll的关系? https://www.zhihu.com/question/63193746 https://segmentfault.com/q/1010000010427586 10、部分面试题链接 https://blog.csdn.net/arvesri70299/article/details/101695117 https://blog.csdn.net/dongdonggegelovezcj/article/details/101347644 https://blog.csdn.net/lcli2009/article/details/82825890 (可以看看他的卡夫卡) https://blog.csdn.net/lxw1844912514/article/details/100028857 https://blog.csdn.net/yilukuangpao/article/details/90234348 算法题 https://zhuanlan.zhihu.com/p/147569045?utm_source=wechat_session 面试题 三、redis和mysql相关

作为一名后端人员,mysql,Redis 永远是绕不开的。。

1、redis的五大数据类型的使用场景 https://blog.csdn.net/fenghuoliuxing990124/article/details/84983694 (1)string 存储字符串,场景是简单缓存 (2)list 队列,场景是模拟队列,秒杀,点赞,回复等有一些先后顺序的 (3)set 无序的唯一列表, 场景:抽奖,去重,好友圈,共同好友之类的 (4)SortedSet 有序的 场景:排行榜,各种热度排行 (5)hash 参考:https://www.cnblogs.com/pangzizhe/p/10657801.html 购物车 2、redis是单线程的吗,可以多线程吗? (可以多线程,redis6.0可以了) 优点: (1) 绝大部分请求是纯粹的内存操作(非常快速) (2) 采用单线程,避免了不必要的上下文切换和竞争条件 (3) 非阻塞IO - IO多路复用(select,poll,epoll) (4)高效的数据结构 (5)value大小:redis最大可以达到1GB,而memcache只有1MB 3、mysql的乐观锁和悲观锁 (1)乐观锁是不加锁的方式,通过添加版本号实现。比如A事务要修改数据,此时版本号为1。B事务也要修改 ,此时读取版本号也是1. 等A事务修改的时候,此时读取version,当version=1的时候才更新version=2。 B事务要更新的时候,再次读取version发现version=2了, 和初始读取的version=1对不上,因此就会更新失败。 可以理解为:比如当前版本是1,A和B获取到version=1,此时更新,那A和B的更新条件都为“version = 1”,如果A先提交了, 此时表中该条数据version已经被A更新为2,B再提交,发现不满足“version=1”,所以无法更新,排他异常 (2)乐观锁只能防止脏读后数据的提交,不能解决脏读。 (3)悲观锁包括:共享锁,排它锁。共享锁是其它事务可以读但是不能写。排他锁是只有自己得事务有权限对此数据进行读写 (4)事务A加上排它锁,事务B在不加排它锁的情况下,是可以select数据的。 (5)乐观锁适合读比较多,写比较少的场景。 悲观锁适合写比较多的场景 (6)乐观锁的时候,当事务B更新不成功的时候,会继续重试。如果重试的多了,会造成大量资源消耗,然而不如使用悲观锁了 4、测试redis秒杀 (1)通过redis的list类型,先创建一个列表,插入10条库存。用户抢购的时候,就从这10个库存里面取,取完为止。这里因为pop操作是原子性的,可以防止超卖。 (2)如何保证每个用户都只能抢到一个呢? 采用hash的算法。首先库存还是存在列表里面。 hash部分,设置一个key,key中对应的属性名和属性值都是user_id。比如 test_key:1:1 在实际抢购的时候,通过hset($test_key, $user_id, $user_id) 判断返回,当user_id不存在hash表的时候,则hash表会自动创建并返回1。当存在这个user_id的时候,会返回0 当返回1的时候,代表是新用户,此时可以减库存,通知存入用户到hash中。 当返回0的时候,代表用户重复,此时提示已经抢购过了 5、redis的分布式锁setnx (1)先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放 (2)可以通过set命令,直接设置nx并设置过期时间,防止出现当拿到锁之后,redis挂掉导致来不及设置过期时间的问题,锁一直释放不了 (3)keys读取所有的键,会导致进程堵塞。可以用scan无阻塞的提取出指定模式的key列表,scan获取的数据可能会重复,需要手动去重 (4)RDB持久化也分两种:SAVE(阻塞)和BGSAVE(非阻塞,一般用这个)。 AOF的话,一般是1s同步一次,如果每条记录都同步的话,会非常损耗性能 (5)redis同步机制:(1)master使用bgsave生成rbd快照,同时后续的修改等操作都会记录到内存。快照生成之后,同步给从节点 (2)slave同步完快照,通知master,把后续的修改记录都同步到从节点即可 6、用redis使用场景? hash实现购物车: (1)每个用户的购物车作为一个hash表,user_id作为key,商品id作为field,商品数量作为value. (2)hset添加商品,hincrby增加数量,hlen为商品总量。hdel删除商品,hgetall获取所有商品 list实现队列,和栈: (1)栈:LPUSH + LPOP (左侧进,左侧出。即先进后出)(栈是先进后出,类似于箱子里放东西) (2)先进先出队列:LPUSH + RPOP (左侧进,右侧出) (3)先进先出,阻塞队列:LPUSH+BRPOP :brpop意思 block right pop 阻塞式右侧出队 brpop(['queue1', 'queue2'], 0),当给定多个 key 参数时,按参数 key 的先后顺序依次检查各个列表,弹出第一个非空列表的头元素 (4)先进先出,等待阻塞队列: Lpush + Brpoplpush : Brpoplpush 命令从列表中取出最后一个元素,并插入到另外一个列表的头部; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 相当于减少无用的轮询,而且每次消费队列时候,还进行了备份,比较安全 (5)优先级队列设计: 1、普通的队列,碰到优先级高的,就从右侧插入,这样会优先消费。(缺点:连续多个优先级任务的话,会先进后出,无法保证顺序) 2、使用brpop来阻塞的读:brpop(['queue1', 'queue2'], 0),先读优先级高的队列,再读优先级低的队列 3、很多优先级的话,只设置一个队列,并保证它是按照优先级排序号的。然后通过二分查找法查找一个任务合适的位置,并通过 lset 命令插入到相应的位置。 list使用场景: (1)微信公众号,后台为每个订阅用户Lpush一条消息,id为key,文件id集合为value,查看的时候,只需要Lrange指定的消息即可 四、BOSS论坛上遇到的面试题 1、滴滴的面试题 (1)mysql保存在磁盘的数据格式是什么 ,然后又是如何变异成我们能识别的数据格式? 二进制的吧 (2)mysql索引在内存中以什么格式保存? (3)B+树是怎样的树状,为什么会这样 2、一个10年经验大哥遇到的题 (1)什么是缓存穿透,什么是缓存击穿,如何解决 缓存穿透是:不论redis还是数据库,都没有这个数据 (1)布隆过滤器 (4.0之后布隆过滤器作为一个插件加载到Redis Server中,就会给Redis提供了强大的布隆去重功能。) 主要是add和exists命令,就是判断某个key在不在这个集合中 (2)判断不存在,就吧空结果写入到缓存。设置比较短的过期时间即可 缓存击穿:redis没有,mysql有 (1)利用锁,先获取这个key的锁,然后同步db数据到缓存。没获取到锁的时候,就先等待 (2)epoll和select的区别是什么 (ok) (3)单机redis与集群redis 1、集群redis解决了单机redis宕机问题 2、解决了单机性能不足,内存不足的情况 3、同时借用主从,也解决了读写之间的分离问题 4、集群比较难以维护 (4)为什么memchace只支持kv,而redis支持类型这么多 1、这是由于redis高效的数据结构。len:用于记录buf中已使用空间的长度,free:buf中空闲空间的长度,buf[]:存储实际内容 2、由数据类型来记录数据是什么方式存储的 (5)redis的过期策略是什么 整体数据的LRU,random等 有过期时间的LRU,randow等 (6)如何快速定位php程序运行慢的地方 (1)打开php-fpm慢日志:slow_log (2)使用xdebug来跟踪程序 (3)phptrace跟踪 (类似于linux下的trace命令,只不过一个是追踪系统调用,一个是追踪程序调用。也是命令行调用,需要输入php-fpm的pid) 3、其他的面试题 (1)谈谈反射的优缺点 应用场景:插件,框架开发等 优点:可以通过反射类,获取被反射类的属性,方法等 (2)如何优化in_array的性能 1、array_flip: key,value,反转之后,使用isset() 2、implode连接成字符串,直接用strpos判断(php里面字符串取位置速度非常快,尤其是在大数据量的情况下) (3)如何处理脏读 1、隔离级别设置成RC及以上 (4)大文件读取和存储 1、yield生成器,一次读取一行,返回的是生成器对象,可以防止内存溢出 2、php自带的SplFileObject类去读取,可以指定行数,指定位置读取开始读取 3、复制大文件的话还是用数据流,stream_copy_to_stream (5)b树和b+树的异同,B+树的叶子节点是双向链表吗 1、是的叶子也是根据页中用户记录的主键大小顺序排成一个双向链表 (6)redis哪些操作和方法是原子性的 1、有种说法是,redis的单个命令都是原子性的 ( 错误的) 2、还有人说,pop,push是原子性的,而len这种不是原子性的,所以判断库存会用pop去减去库存,而不是用len判断 ( `货拉拉大佬实际碰到的问题,len确实不是原子性的`) (7)mysql分区表和数据统计问题 分区和分表不一样,分区是把一个表,通过Range、List、Hash、Key,其中Range比较常用 等方法,分成不同的磁盘文件存储。 (8)yield 1、返回生成器对象,可以使用foreach进行迭代。比如读取文件的时候,返回的是一行一行的数据, 就避免了之前容易出现的数组内存溢出情况 2、占用内存极小,近似为一行数据的内存大小 (9)二分查找 (10)解决卡夫卡的rebalance问题,还有事务的使用方法 1、Rebalance本身是Kafka集群的一个保护设定,用于剔除掉无法消费或者过慢的消费者 2、当消费数据过慢,或者比较耗时,都会触发这个重平衡 3、坏处 (1)数据重复消费: 消费过的数据由于提交offset任务也会失败,在partition被分配给其他消费者的时候,会造成重复消费,数据重复且增加集群压力 (2)影响集群速度 (3)数据不能及时消费,会累积lag,在Kafka的TTL之后会丢弃数据 (4)频繁的Rebalance反而降低了消息的消费速度,大部分时间都在重复消费和Rebalance (11)redis的分布式锁不适合高并发场景,如何优化 (1)比如悲观锁,分布式锁,乐观锁,队列串行化,异步队列分散,Redis原子操作,等等,很多方案,我们对库存超卖有自己的一整套优化机制 (2)问题:分布式锁一旦加了之后,对同一个商品的下单请求,会导致所有客户端都必须对同一个商品的库存锁key进行加锁。不适合高并发,因为这个类似于串行化 (3)解决方案: 1、分段加锁。就是1000个库存,你分成20个key的库,用户请求随机分配到这20个库,这样分开加锁提升性能。(库存不足则记得手动释放锁,并重新选择其他库) (12)说一下悲观锁和互斥锁的具体区别 1、互斥锁、自旋锁、读写锁都属于悲观锁,悲观锁认为并发访问共享资源时,冲突概率可能非常高,所以在访问共享资源前,都需要先加锁。 2、互斥锁和自旋锁都是最基本的锁 3、互斥锁加锁失败后,线程会释放 CPU ,给其他线程;自旋锁加锁失败后,线程会忙等待,直到它拿到锁; (13)你pop了redis里的数据,最后进程挂了怎么办 1、redis挂了的话,数据从内存溢出,但是没有持久化到磁盘,这时候就要看持久化的策略了,是aof还是rdb,是一秒一写还是每次命令都写,然后恢复数据 2、综合使用AOF和RDB两种持久化机制,用AOF来保证数据不丢失,作为数据恢复的第一选择; 用RDB来做不同程度的冷备,在AOF文件都丢失或损坏不可用的时候,还可以使用RDB来进行快速的数据恢复 3、如果是php进程被kill了。可以通过信号机制,重新push (14)一句话描述binlog,undo log等 1、redo log是为了持久化数据,在数据还没从内存刷新到磁盘时,如果发生故障,可读取该日志持久化到磁盘。 2、binlog 是为了复制和恢复数据的,即Mysql从服务器可以读取主服务器的binlog复制数据,数据库数据丢失,也可以读取binlog恢复 3、undo log是为了保证原子性的。(为了满足事务的原子性,在操作任何数据之前,首先将数据备份到一个地方(这个存储数据备份的地方称为Undo Log)。然后进行数据的修改。如果出现了错误或者用户执行了ROLLBACK语句,系统可以利用Undo Log中的备份将数据恢复到事务开始之前的状态。) 五、部分公司面试题 1、甲公司 (1)laravel相关面试题 服务提供者是什么? :服务容器就是管理类的依赖和执行依赖注入的工具,它可以为你的类库提供一套可以重用的实例化方案。 IoC 容器是什么? (2)vue基础面试题 (3)谈谈你对闭包的理解 1、通过匿名函数实现,一般是普通函数中调用匿名函数,返回数据。匿名函数也可以作为参数传递给普通函数 2、闭包要使用外界的变量,则需要使用use关键字 (4)什么是CSRF攻击?XSS攻击?如何防范 CSRF:跨站请求伪造 。 一般是token验证的方案 XSS:跨域脚本攻击。 一般是对输入进行encode转义和过滤 sql注入: (1)pdo的预处理 (2)对用户参数进行过滤转义处理 ddos: (1 防火墙 (2)禁用过滤ip (3 使用CDN,提供一层缓冲,不会全部涌向服务器 2、乙公司 (1)设计模式 单例,工厂,观察者模式 https://www.cnblogs.com/yueguanguanyun/p/9584501.html (2)php代码优化 函数 数组 释放内存 定义方法,注意循环 (3)可以于yy的上线下线功能,长连接方面 长连接还是通过websocket最好,主要是swoole部分 3、丙公司 (1)redis集群相关 (2)mysql回表 (ok) (3)php-fpm有没有挂过,怎么处理的 1、503错误,一般是进程太多导致的。比如max_children的数量等 2、502错误,php或者php-fpm超时 3、504是nginx错误 4、至于什么错误,可以查看php-fpm的日志文件 5、通过配置max_request等配置,可以自动重启php-fpm (4)慢查询有没有通过改框架去优化 1、一般使用原生的sql多一些 2、下载laravel-debuger文件,看看慢在哪里了。也可以使用x-debug查看 (5)redis单机挂了怎么办,有什么策略:(单机的问题就是内存不够,处理能力有限,不能高可用) (1)查询前先ping一下,无响应就先去数据库 (2)定时脚本轮询,ping redis,错误了就报警出来 (3)给key设置过期时间,减小内存压力,释放部分内存出来 (4)挂了就重启,通过持久化恢复数据。业务不忙的话可以先预热,业务比较忙的话,就直接恢复redis (6)es怎么用的 (1)存储日志用的 (2)从传统的关系型表设计,改为文档json设计 (3)连表没那么方便了,可以进行聚合查询等 (7)redis问的比较多 (8)php的安全策略 1、文件系统安全(尽量不要用root权限,php权限也不能太高) 2、数据库安全(防止sql注入等) 3、用户数据安全(对用户数据进行过滤,能防止xss和csrf) 4、线上环境安全(php配置关闭错误提示,关闭危险函数等) (9)redis过期策略 定时过期:每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除。该策略可以立即清除过期的数据,对内存很友好;但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量。 惰性过期:只有当访问一个key时,才会判断该key是否已过期,过期则清除。该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。 定期过期:每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。 (10)内存淘汰策略: noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。 allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。 allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。 volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。 volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。 volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。 (11)一台服务器可以安装多个redis,主要通过修改端口号,修改配置文件路径等实现,互不干扰即可

2020最后几天了,奥利给,冲冲冲!

end



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有