記一次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數據就好的,還要了解之外的很多東西。要去深入理解原理,並不能停留的表面,不的話就會像我今天面試一樣,知道是什麼但是說不出,學習最大的進步就是要不斷實踐、不斷總結。總體來說,這次面試的收穫還是不少的,希望自己能查缺補漏、持續學習!加油!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章