一、前言
最近博主也是歷盡千辛萬苦換了份作業,每次換之前不找點面試題看似乎就沒自信一樣,,奈何網上有些面試題是比較老套的,所以這里重新總結一份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判斷
(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
CSDN認證博客專家
PHP
求知者
偽全堆疊
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/241879.html
標籤:其他
