• 2021年最新大厂php+go面试题集(三)


    14.快手一面

    微信公众号:码农编程进阶笔记
    关注可获得更多的视频教程及面试技巧。问题或建议,请公众号留言! 

    1.CDn工作原理
        答:CDN通过广泛的网络节点分布,提供快速、稳定、安全、可编程的全球内容分发
        加速服务,支持将网站、音视频、下载等内容分发至接近用户的节点,使用户可就近
        取得所需内容,提高用户访问的响应速度和成功率。
    
        https://blog.csdn.net/aliyunbaike/article/details/84952966
    2.go的init用过吗,主要使用场景是哪些?
        答:每一个源文件都可以包含一个 init 函数,该函数会在 main 函数执行前,
    被 Go 运行框架调用,也就是说 init 会在 main 函数前被调用。
    
    3.快速排序
    
    4.go的map怎么删除元素
        delete(map, 键)
        如果要清空map元素,直接make一个新map就可以
    
    5.go的syncmap
        1)map在并发编程中,读是线程安全的,写不是
        2)sync.map是线程安全的,不需要初始化,声明即可
        3)Store 表示存储,Load 表示获取,Delete 表示删除

    15.边锋一面

    1.redis的连接跟mysql的连接有什么区别?为什么redis可以承受
        更高的访问量?
        io多路复用
    2.dns解析的具体流程
    3.nginx访问php的方式,优缺点,怎么访问的
    4.php获取请求到生成opcode的过程 ,opcode是干什么的,跟机器码有什么区别
        答:
        本质上一个opcode由两个参数(op1,op2)、返回值和处理函数组成。它的官方解释就
        是PHP脚本编译后的中间语言,类似于java中的bytecode或者是.net中的MSL。
    
    微信公众号:码农编程进阶笔记
    关注可获得更多的视频教程及面试技巧。问题或建议,请公众号留言!
    
    5.php定义类外的 静态变量,还有类里面的静态变量有什么区别?你说到类里面的静态变量是不会立刻释放的,那么有100个请求去请求这个类,静态变量的值累加,100次之后你认为这个值是多少,为什么
    6.php定义类外的 静态变量,还有类里面的静态变量有什么区别?你说到类里面的静态变量是不会立刻释放的,那么有100个请求去请求这个类,静态变量的值累加,100次之后你认为这个值是多少,为什么
        答:都是在程序一启动时就分配了内存空间,生命周期一样,但是作用域和可见性却
        不一样
        1)类内部静态变量必须通过类名或者对象名去访问,该变量在整个程序中都可见。
        2)类外的静态变量只能在定义文件中使用,只在定义文件中可见,无法在非定义文件中使用。
    
    7.nginx发送请求到php,这个请求是什么格式的,里面都包含了哪些内容
        用户访问域名->域名进行DNS解析->请求到对应IP服务器和端口->
        nginx监听到对应端口的请求->nginx对url进行location匹配->
        执行匹配location下的规则->nginx转发请求给php->
        php-fpm的master进程监听到nginx请求->master进程将请求分配给闲置的worker进程
        ->worker进程执行请求->worker进程返回执行结果给nginx->nginx返回结果给用户
    
            nginx连接php的方式:
                1)tcp方式:ip+9000端口
                2)unix_socket:(要求nginx和php必须在同一台服务器上)
                    fastcgi_pass unix:/tmp/php-fpm.socket
    
    
    
    8.redis做队列,如果消费者挂掉了,这个数据丢失怎么办
        Redis有个命令叫做LPUSHRPOP(以及阻塞版本和不同方向的版本),即从一个队列
        弹出的同时将这个消息送入另一个队列,同时返回给客户端。原子操作。
    
    9.rebbitmq会积压到内存爆掉,kafka为什么不会
        答:当RabbitMQ收到消息时,如果是持久化消息,则会储存在内存中,同时也会写入
        磁盘;如果是非持久化消息,则只会存在内存中

    16.字节一面

    1.bitmap设置的长度是多大,用到了哪些hash函数
        bitmap底层使用的还是字符串结构,最多是512M
        ,也就是2的32次方 位
    2.渐进式hash,对渐进式的理解
        1)从dict.ht[0].table[0]的bucket进行rehash。
        2)处理完一个bucket后,将ht[0].table[dict.rehashidx] 置为 NULL。
        3)将dict.rehashidx加1,处理下一个bucket
        查询: 比较当前key的大小和 rehashidx的大小,来选择
        去h0还是h1中进行查询。
    
    3.kafka的分区和消费者的分配原则
        (1)分区数:Tt / max(Tp, Tc)
        (2) key怎么分配到分区的?
            1)有key的时候,做一次hash,根据分区数取模
            2)key为null,则随机找一个分区写入
        (3)分区和消费者的策略
            1)range :partitions的个数除于消费者线程的总数来决定每个消费者线程消费
                几个分区。如果除不尽,那么前面几个消费者线程将会多消费一个分区
           2)将所有主题的分区组成 list列表,然后对 list列表按照 hashCode 
               进行排序
    
    
    4.统计相同用户的访问次数,sort排序
    cat logs/baidu.access.log | awk '{print $(NF-1)}' | sort | uniq -c | sort -k 1 -n -r|head -10
    
    5.有n个任务,每个任务有开始和结束时间,如何安排任务的顺序,
    使得完成的任务个数是最多的

    17.b站B部门一面

    1.php实现锁
        1)静态变量(同一个请求的话,会不释放。多个请求的话会初始化)
        2)apcu 
        将PHP代码编译之后所产生的bytecode暂存在共享内存内供重复使用,以提升应用的运行效率。(Opcode Cache)
        提供用户数据缓存功能,需要显示的调用,和redis/memcache类似。(User Data Cache)
    
    2.订单表的分库,如何查询?数据量比较大的话呢
        淘宝的做法是拆分买家库和卖家库,也就是两个库:买家库、卖家库。
        买家库,按照用户的id来分库分表。卖家库,按照卖家的id来分库分表。
        写入的时候,先写入买家库,然后通过消息队列异步写入到卖家库。
    
    
    3.http304产生的原因,我们可以用它来实现什么场景
    
    4.redis的bitmqp的缺点
        数据比较松散的情况下不好用
    5.go的读写锁
    
    6.redis的list做队列,当数据比较多的时候怎么处理?
    (1)拆分法
    可以遍历list,拆分到多个list中去,多个list可以按照顺序,比如1,-1000,
    10001-2000 这样取名字
       (2)如果有范围查询的需求,可以考虑转换为zset来处理范围查询,按照时间戳
    来进行排序即可
    
    7.外部请求接口很慢,该怎么排查?服务器资源不足怎么办
        (1)服务器扩容
        (2)需要预估一个qps,扩容*120%即可
        1.内存使用过高,频繁gc导致cpu占满
        2.内存使用不高,出现了类似死循环场景
        通过第三方监控平台查看堆栈信息
    
    8.lru的加锁,在操作链表的时候需要加读写锁的

    18.货拉拉一面

    1.php-fpm的超时配置,超时之后会显示什么
        (1)Nginx 504 Gateway Time-out的含义是没有请求到可以执行的PHP-CGI。
        (2)Nginx 502 Bad Gateway的含义是请求的PHP-CGI已经执行,但是由于
        读取资源的程序没有执行完毕而导致PHP-CGI进程终止。
        (3) 502错误是php-fpm控制的,超时会终止cgi
        (4) 504是nginx报出的,代表nginx连接fastcgi超时
    
    2.codis的缺点是什么
        (1)master挂掉了,只能靠运维人员去维护
        (2)codis不保证数据一致性,不支持主从复制
    
        (3)非官方出品,后续升级没保障
        (4)codis不支持事务
    3.mysql的死锁产生,还有如何防止
        (1)按同一顺序访问对象。
        (2)保持事务简短并在一个批处理中。
        (3)使用低隔离级别。
        (4)避免长事务,将事务拆解
        (5)设置锁超时等待innodb_lock_wait_timeout
    
    4.mysql分表的查询问题,怎么不遍历所有表做一个查询
        (1)借用redis或者数据表,存储映射关系,映射查询字段和分表的关系
        (2)找到分表之后,直接执行查询,组合数据即可
    
    微信公众号:码农编程进阶笔记
    关注可获得更多的视频教程及面试技巧。问题或建议,请公众号留言!
    
    5.php5.6和7.0的区别,写代码用到什么新特性了
        (1)PHP7.0之前出现的致命错误,都改成了抛出异常
        (2)增加了空结合操作符(??)。效果相当于三元运算符
        (3) PHP7.0新增了函数的返回类型声明
        (4)define 可以定义常量数组
        为什么php7比较快:
        1、存储变量的结构体变小,尽量使结构体里成员共用内存空间,减少引用,
            这样内存占用降低,变量的操作速度得到提升。
        2、字符串结构体的改变,字符串信息和数据本身原来是分成两个独立内存块存放,
            php7尽量将它们存入同一块内存,提升了cpu缓存命中率。 
        3、数组结构的改变,数组元素和hash映射表在php5中会存入多个内存块,
            php7尽量将它们分配在同一块内存里,降低了内存占用、提升了cpu缓存命中率。
        4、改进了函数的调用机制,通过对参数传递环节的优化,减少一些指令操作,
            提高了执行效率。
    
    
    6.laravel,yii,ci的区别,laravel的特点?控制反转?依赖注入?
        (1)laravel社区最活跃,支持的扩展也多
        (2)yii的配置文件比较麻烦,不过支持多种环境配置
        (3)laravel的路由比较强大,但是基于组件式,稍微臃肿点
        (4)yii的view和model层不太好用
        控制反转:和依赖注入配合使用,只不过是用容器去绑定依赖,
        这样相当于控制权给到了容器。
        依赖注入:不用在程序里实例化类,可以通过参数的形式注入进去
        ci:CI中的超级对象就是当前控制器对象,它提供了很多属性.($this)
    
    
    7.composer的自动加载机制
        (1)autoload机制 可以使得 PHP 程序有可能在使用类时才自动包含类文件,
            而不是一开始就将所有的类文件include进来,这种机制也称为 
            Lazy loading (惰性加载)。
        (2)单个autoload也不方便,难以维护,所以就出现了composer:
            composer 会找到符合 PR4 规范的第三方库的源
            将其加载到 vendor 目录下
            初始化顶级域名的映射并写入到指定的文件里
            写好一个 autoload 函数,并且注册到 spl_autoload_register()里
     8.redis的持久化,会持久化过期的key吗       
         (1)aof是以记录命令方式,所以如果还没过期,那么不会有变更的命令,
         如果过期,会在aof日志插入一条del命令。
         (2)rdb的话是内存快照方式,如果持久化时,key已经过期,那么不会持久化,
         如果在过期之前就已经持久化了,那么在恢复数据时,会判断key是否过期,
         如果过期不会导入。
    9.redis和memcache的区别
        (1)存储数据安全--memcache挂掉后,数据没了;redis可以定期保存到磁盘(持久化);
        (2)灾难恢复--memcache挂掉后,数据不可恢复; redis数据丢失后可以通过aof恢复;
        (3)redis数据结构更丰富
        (4)Memcached单个key-value大小有限,一个value最大只支持1MB,而Redis最大支持512MB

    19.滴滴一面

    1.go的协程比线程轻到哪里了?
        (1)协程在用户态进行上下文切换,耗时是线程的30/1。
        线程需要:1,000 ~ 1,500 纳秒
        (2)协程初始2kb,线程好几m
        (3)线程切换:cpu上下文(寄存器),私有的栈,线程状态等
            协程千幻:cpu上下文(寄存器)
         缺点:cpu无法实现抢占式调用协程
    
    2.算法题:堆排序
        升序----使用大顶堆
        降序----使用小顶堆
        (1)为什么升序要用大顶堆呢
        大顶堆的特点:每个结点的值都大于或等于其左右孩子结点的值,我们把大顶堆构建
        完毕后根节点的值一定是最大的,然后把根节点和最后一个元素(也可以说最后一个节
        点)交换位置,那么末尾元素此时就是最大元素了
    3.go的runtime
        (1)在把用户写的程序翻译成可执行文件的过程中,把 runtime 代码塞进了
            可执行文件
            1)初始化全局变量,
            2)调用每个模块的init函数
            3)初始化 GC,以及初始化 Go scheduler
            4) 启用一个协程,调用用户写的 main 函数。

    20.滴滴二面

    1.php的autoload加载机制
        //根据类名找到文件
        $path = str_replace('_', '/', $class_name);
        //直接引入
      require_once $path . '.php';
    2.php的数组扩容
        (1)有个参数,当删除的数量比较多时,先进行rehash计算,去掉删除的部分
        (2)删除比较少,空间不足,则扩容+rehash,申请2倍的空间,然后rehash计算
    
    微信公众号:码农编程进阶笔记
    关注可获得更多的视频教程及面试技巧。问题或建议,请公众号留言!
    
    
    3.redis的zset结构
        (1)数据量小于128或者存储的key小于64则为ziplist
            特点是内存连续,占用空间小
        (2)正常情况下是跳跃表,存在多级索引,第一层是双向链表结构
             由许多层结构组成。
            每一层都是一个有序的链表。最底层 (Level 1) 的链表包含所有元素。
            如果一个元素出现在 Level i 的链表中,则它在 Level i 之下的链表也都会出现
        (3)为什么用跳跃表不用红黑树
            (1)跳跃表底层是双向链表,适合做范围查询
            (2)跳跃表的修改,删除只需要更改相邻节点的指针,不需要重建树
            (3)跳跃表占用的内存比红黑树少一些
     (3)zet结构
    1)由字典和跳跃表构成。字典让我们查询单个元素的时间复杂度是o(1),
    跳跃表主要是按照分值对元素排序.范围查询的时候,时间复杂度是o(loginN)
    
    
    
    4.一个请求到php程序的过程
        (1)三次握手之后,请求建立连接,进入全连接队列,accept()函数可以取到
        (2)Nginx会按照FastCGI协议的消息格式发送数据,
            worker进程再按照协议多次read()数据并解析
        (3)词法语法分析,生成语言片段
        (4)zend引擎根据opcode调用机器指令
        (5)执行用户通过register_shutdown_function()注册的关闭函数
        (6)释放资源,清理符号表,销毁超全局变量,重置max_execution_time 等等
    
    5.一个请求到go程序的过程
            golang作为常驻进程, 请求第三方服务或者资源(http, mysql, redis等)完毕后,
             需要手动关闭连接, 否则连接会一直存在;
             (1)为什么请求之后要defer关闭
             https://www.cnblogs.com/lovezbs/p/13197587.html
             如果请求不手动关闭的话,每个请求都会创建两个goroutine,y
             分别去往这个连接写入请求(writeLoop函数)和读取响应(readLoop函数),
             且请求结束不会主动释放,会导致goroutine不断增加,导致内存泄露
            (2)go的链接复用问题
                在go的源码中特意指出,需要读取rep.body才能复用链接。有时候
                我们只读取header做判断,code不是200就返回错误,这样的话该链接
                就不会复用,导致出现大量的tcp : rst.       
            --- go作为客户端
            1.创建http.Client对象client
            2.创建http.Request对象req
            3.发送请求client.do(req)
            4.关闭resp.Body.Close()
            ---- 源码部分
            (1)client.do
                主要是参数校验,设置默认值,调用client.send
           (2)client.send
               cookie的装载,获取Transport对象,调用http.send
           (3)http.send
               校验请求参数,超时取消(setRequestCancel)和请求事务: rt.RoundTrip(req)
           (4)client.setRequestCancel
               创建一个协程利用select chan机制阻塞等待取消请求
           (5)Transport.RoundTrip
               参数校验,获取缓存的或新建的连接
           (6)Transport.getConn
               连接池有空闲则取出空闲连接
               连接池无空闲则创建新连接
               达到最大数量则阻塞,等待空闲连接
               同时开启了两个goroutine,分别 读取response 和 写request
    
    
    
    
            --- go作为服务端是如何处理的
            http.HandleFunc("/hello", SayHello)
       (0)  首先调用Http.HandleFunc
            往DefaultServeMux的map[string]muxEntry中增加对应的handler和路由规则
    
        (1)http.ListenAndServe(":9090", nil) //设置监听的端口
        (2)ListenAndServe内部使用net包调用了 net.Listen("tcp", addr) 来监听端口
            --- 接收客户端请求
        (1)启动for循环,使 Listener 不断地接收来自客户端的请求,accept
        (2)给每个请求实例化一个conn,serve.NewConn
        (3)调用go c.serve启动协程,用户的每一次请求都是在一个新的 goroutine中服务,互相不影响
    
            --- 处理请求
        (1)分析请求,取出请求体resp,req
        (2)根据ServeMux 路由规则管理器map,判断请求分发给哪些handle
        (3)我们注册的函数会转化为handleFunc类型,然后通过
            handler.serveHttp(resp,req),从而实现请求处理
    
    
    6.gin框架的接口会开启协程吗
    答:会的,参照上面的请求流程
        客户端:每次请求开启两个协程,负责读写
        服务端:每次开启一个协程处理请求
    
    7.外部怎么访问k8s的pod
        (1)nodeip: service设置为nodeip类型,集群外就可以使用K8s任意一个节点
        的IP加上30000端口访问该服务了,kube-proxy会自动将流量以轮询的方式转发给
        该service的每一个pod。
        (2)LoadBalancer:公有云提供的负载均衡器。
             任意节点的IP加30051端口访问服务 10.97.121.42:30051
            使用EXTERNAL-IP来访问,这是云供应商提供的负载均衡IP
        (3)ingress
            K8s管理的负载均衡容器,它的镜像包含一个nginx或HAProxy负载均衡器和
            一个控制器守护进程
        外部访问URL,访问该服务,入口是80端口,然后Ingress controller直接将流量
        转发给后端Pod,不需再经过kube-proxy的转发,比LoadBalance方式更高效
    
    8.k8s的服务发现
        (1)通过service实现的
        (2)etcd是干什么的
            https://zhuanlan.zhihu.com/p/96721097
            etcd 是一个分布式的、可靠的 key-value 存储系统,它用于存储分布式系统
            中的关键数据。
            使用Raft 一致性算法来实现分布式一致性
         服务注册:
         (1)提交服务配置,创建service对象,创建endpoint对象
         (2)DNS监控service变化,注册服务
         服务发现:
         (1)kube-proxy 监控ep变化,通过IPVS修改路由规则,去往service流量转向pod
         (2)服务通过DNS和service name 寻找 cluster ip 
         (3)流量转发给 cluster ip,随后被路由规则转给 对应POD   
         (4)kube-proxy 监控 pod,一旦发现 pod 服务变化,将会把新的 ip 地址更新
             到 service。kube-proxy 更新的存储在 etcd 里的映射关系(ep)
    
    
    
    9.dns解析步骤
        1)操作系统会先检查自己本地的hosts文件是否有这个网址映射关系
        2)如果hosts里没有这个域名的映射,则查找本地DNS解析器缓存
        3)查找本地DNS服务器,也就是配置中的首选dns服务器
        4)转发模式:把请求转发到上一层dns服务器,不断转发
        5)非转发: 先发送到13台根服务器,根服务器返回顶级域名服务器的ip,
            客户端访问该ip,然后由顶级域名服务器进行下一级的查询
        6)为什么根域名只有13台?
            答:因为采用udp协议减小开销,dns规定512字节的传输上限,
               一次返回最多返回13个根域名记录     
    10.redis集群的分布式是什么样子的 
        不同的服务在不同的节点上。这些服务组合起来才是完整的功能,
        这就是分布式。

    21.b站B部门二面

    1.k8s的服务发现,服务注册,服务调用是为了什么
          服务注册:
         (1)提交服务配置,创建service对象,创建endpoint对象
         (2)DNS监控service变化,注册服务
          服务调用:
          (1)有两种方式,一种是RPC方式,另一种是事件驱动(Event-driven)方式,也就是发消息方式
         服务发现:
         (1)kube-proxy 监控ep变化,通过IPVS修改路由规则,去往service流量转向pod
         (2)服务通过DNS和service name 寻找 cluster ip 
         (3)流量转发给 cluster ip,随后被路由规则转给 对应POD   
         (4)kube-proxy 监控 pod,一旦发现 pod 服务变化,将会把新的 ip 地址更新
             到 service。kube-proxy 更新的存储在 etcd 里的映射关系(ep)
    
      2.k8s我们发布服务的时候,怎么进行一个平滑启动
          答:https://yuerblog.cc/2019/12/11/k8s-%E5%A6%82%E4%BD%95%E5%B9%B3%E6%BB%91%E5%8F%91%E5%B8%83%E5%BA%94%E7%94%A8%EF%BC%9F/
          上线:
              1)POD上线需要配置健康检查
              2)健康检查通过,service才会将POD加入endpoints列表,
              流量进入可以正常响应
    
         下线:
             1)POD下线时会在etcd中先标记POD状态为terminating退出中,
                 其他相关联动资源会监听到变化并采取后续动作。
            2)先关闭监听,处理完已有请求,退出进程
    
    微信公众号:码农编程进阶笔记
    关注可获得更多的视频教程及面试技巧。问题或建议,请公众号留言!
    
      3.redis集群扩容的一个过程
          (1)添加节点
          (2)分配hash槽,可以全部重新分配,
          也可以指定节点分出一部分槽出来
          (3)槽迁移
              每个节点计算自己的槽,比如原来节点负责5000个槽,现在负责4000个,
              则把多余的1000迁移到新节点。主要是迁移槽上的key,
    
      4.mysql同时读写一行会数据,会触发锁吗
          对于普通SELECT语句,InnoDB不会加任何锁,所以读写同时进行没有问题,
          读为快照读,写为当前读
    
      5.go的map的底层结构
          (1)结构:散列表+bucket
          (2)底层一个数组arr
            index = hash(key)
            arr[index] = struct{xxxx}
         (3)每个bucket中可以存储8个kv键值对,
         (4)hash值的低八位和bucket数组长度取余,定位到在数组中的那个下标,
         hash值的高八位存储在bucket中的tophash中,用来快速判断key是否存在,
    
    
      6.redis和mysql的强一致性如何实现 
          (1)两段式提交,引入一个协调者。
          事务A和事务B都分为准备和提交阶段,状态同步给协调者,任一步骤出问题则回滚
          (2)raft算法实现
    
      7.kafka在扩容的时候,怎么在不影响现有业务的情况下扩容
          (1)kafka新增节点,对其他节点来说是无感知的
          (2)在新节点上创建topic,或者迁移topic分区即可
    
      8.redis的热点key如何处理
          (1)收集热点key,比如自己写日志或者用redis提供的命令
          (2)加载到内存,直接在内存中读取
          (3)热点key分散,加个随机数进行分散,分散到多个redis机器,
          读的时候随机从有备份的redis上读取即可
    
      9.redis集群的脑裂如何避免
          min-slave解决。当脑裂之后,会有一个分区的slave升级为master,
          此时根据配置文件,当slave少于配置个数则停止写入。
          这样保证只有一个master提供写入,等网络恢复也不会有问题
    
    
      10.es的架构,index的内部实现
          https://blog.csdn.net/u013380694/article/details/101760607
          它可以将索引划分为多个分片,可以部署到集群中的任何一个节点,
          且每个分片都有副本,实现高可用
          (1)它允许水平切分内容卷。
          (2)它允许通过分片来分布和执行操作来应对日益增长的执行量。
          (3)一个索引就像数据库。而type就相当于每一张表,
          而mapping就相当于表的结构定义,定义了什么字段类型等
          往index的一个type里添加一行数据就叫做一个document
          每一个document有多个field
          查询:
              (1)客户端发送请求到协调节点
              (2)协调节点从分片上查询数据,由协协调节点进行聚合
              (3)合并数据,返回给客户端

    往期精选

    e9f47fa30b904184d8fa3da468c6fda1.gif

    详解高级PHP工程师面试题

    2020最新版MySQL数据库面试题(一)

    2020最新版MySQL数据库面试题(二)

    2020最新版MySQL数据库面试题(三)

    面试中常见的计算机网络的问题

    deb71d543bf50b6b922a144565bcf759.png

  • 相关阅读:
    JavaScript入门基础(三)
    JavaScript入门基础(二)
    Web页面该如何布局
    如何通过SQL创建删除表的索引,UNIQUE KEY
    vim使用大全
    安装vmwaretools后 真机和虚拟机仍不能复制黏贴
    php通用函数html时间文件大小生成随机数
    Centos下安装配置phpmyadmin
    [Leetcode 43] 11 Container With Most Water
    [Leetcode 39] 129 Sum Root to Leaf Numbers
  • 原文地址:https://www.cnblogs.com/lxwphp/p/15452454.html
Copyright © 2020-2023  润新知