<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          年前的最后一次面試題總結(jié)[大廠]

          共 7220字,需瀏覽 15分鐘

           ·

          2022-01-27 17:29

          開場白

          年前最后幾天,準(zhǔn)備了一場面試。是PHP開發(fā)崗位。面試題都還算是蠻基礎(chǔ),也是常被問到的問題。這里總結(jié)出來幾道蠻不錯的問題。其他的問題,我也做了一些整理,有興趣的可以看一看,都是一些經(jīng)典的面試題。

          說說php-fpm啟動進(jìn)程相關(guān)方面的設(shè)置?

          針對php-fpm進(jìn)程的管理,需要在php-fpm.conf配置文件中進(jìn)行修改。進(jìn)程運(yùn)行的模式就只有動態(tài)(dynamic)和靜態(tài)(static)。

          1. 首先,我們關(guān)注一個前提設(shè)置:pm = static/dynamic,標(biāo)識fpm子進(jìn)程的產(chǎn)生模式。
          2. static(靜態(tài)) :表示在fpm運(yùn)行時直接fork出pm.max_chindren個worker進(jìn)程。
          3. dynamic(動態(tài)):表示運(yùn)行時fork出start_servers個進(jìn)程,隨著負(fù)載的情況,動態(tài)的調(diào)整,最多不超過max_children個進(jìn)程。
          ?

          一般推薦用static,優(yōu)點(diǎn)是不用動態(tài)的判斷負(fù)載情況,提升性能,缺點(diǎn)是多占用些系統(tǒng)內(nèi)存資源。

          ?

          max_children

          1. 這個值原則上是越大越好,php-cgi的進(jìn)程多了就會處理的很快,排隊(duì)的請求就會很少。
          2. 設(shè)置”max_children”也需要根據(jù)服務(wù)器的性能進(jìn)行設(shè)定。
          3. 一般來說一臺服務(wù)器正常情況下每一個php-cgi所耗費(fèi)的內(nèi)存在20M左右。
          4. 假設(shè)“max_children”設(shè)置成100個,20M*100=2000M。
          5. 也就是說在峰值的時候所有PHP-CGI所耗內(nèi)存在2000M以內(nèi)。
          6. 假設(shè)“max_children”設(shè)置的較小,比如5-10個,那么php-cgi就會“很累”,處理速度也很慢,等待的時間也較長。
          7. 如果長時間沒有得到處理的請求就會出現(xiàn)504 Gateway Time-out這個錯誤,而正在處理的很累的那幾個php-cgi如果遇到了問題就會出現(xiàn)502 Bad gateway這個錯誤。

          start_servers

          1. pm.start_servers的默認(rèn)值為2。并且php-fpm中給的計算方式也為:
          ?

          {(cpu空閑時等待連接的php的最小子進(jìn)程數(shù)) + (cpu空閑時等待連接的php的最大子進(jìn)程數(shù) - cpu空閑時等待連接的php的最小子進(jìn)程數(shù))/ 2};用配置表示就是:min_spare_servers + (max_spare_servers - min_spare_servers) / 2;一般而言,設(shè)置成10-20之間的數(shù)據(jù)足夠滿足需求了。

          ?

          說說PHP的生命周期是怎么樣的?以及每個階段分別都做了什么操作?

          php的運(yùn)行模式有兩種:web模式和cli模式。無論是哪種公眾模式,php的工作原理都是一樣的,都是作為一種SAPI運(yùn)行。首先,認(rèn)識下SAPI,它是什么。Sapi全稱是Server Application Programming Interface,也就是服務(wù)端應(yīng)用編程接口,Sapi通過一系列鉤子函數(shù),使得PHP可以和外圍交互數(shù)據(jù),這是PHP非常優(yōu)雅和成功的一個設(shè)計,通過sapi成功的將PHP本身和上層應(yīng)用解耦隔離,PHP可以不再考慮如何針對不同應(yīng)用進(jìn)行兼容,而應(yīng)用本身也可以針對自己的特點(diǎn)實(shí)現(xiàn)不同的處理方式。SAPI運(yùn)行PHP都經(jīng)過下面幾個階段: 1、模塊初始化階段(module init) 這個階段主要進(jìn)行php框架、zend引擎的初始化操作。這個階段一般是在SAPI啟動時執(zhí)行一次,對于FPM而言,就是在fpm的master進(jìn)行啟動時執(zhí)行的。php加載每個擴(kuò)展的代碼并調(diào)用其模塊初始化例程(MINIT),進(jìn)行一些模塊所需變量的申請,內(nèi)存分配等。

          2、請求初始化階段(request init) 當(dāng)一個頁面請求發(fā)生時,在請求處理前都會經(jīng)歷的一個階段。對于fpm而言,是在worker進(jìn)程accept一個請求并讀取、解析完請求數(shù)據(jù)后的一個階段。在這個階段內(nèi),SAPI層將控制權(quán)交給PHP層,PHP初始化本次請求執(zhí)行腳本所需的環(huán)境變量。比如接收客戶端發(fā)送的post請求數(shù)據(jù)信息、http請求報文信息等。

          3、php腳本執(zhí)行階段 php代碼解析執(zhí)行的過程。Zend引擎接管控制權(quán),將php腳本代碼編譯成opcodes并順次執(zhí)行。這也我們的代碼真正執(zhí)行的階段。

          4、請求結(jié)束階段(request shutdown) 請求處理完后就進(jìn)入了結(jié)束階段,PHP就會啟動清理程序。這個階段,將flush輸出內(nèi)容、發(fā)送http響應(yīng)內(nèi)容等,然后它會按順序調(diào)用各個模塊的RSHUTDOWN方法。RSHUTDOWN用以清除程序運(yùn)行時產(chǎn)生的符號表,也就是對每個變量調(diào)用unset函數(shù)。比如清除請求初始化階段獲取到的post請求參數(shù)、一些代碼變量等。

          5、模塊關(guān)閉階段(module shutdown) 該階段在SAPI關(guān)閉時執(zhí)行,與模塊初始化階段對應(yīng),這個階段主要是進(jìn)行資源的清理、php各模塊的關(guān)閉操作,同時,將回調(diào)各擴(kuò)展的module shutdown鉤子函數(shù)。這是發(fā)生在所有請求都已經(jīng)結(jié)束之后,例如關(guān)閉fpm的操作。(這個是對于CGI和CLI等SAPI,沒有“下一個請求”,所以SAPI立刻開始關(guān)閉。)

          說說fastcgi與cgi之間的區(qū)別是什么?

          定義 CGI:通用網(wǎng)關(guān)接口協(xié)議(CGI)是一種對接應(yīng)用程序和網(wǎng)絡(luò)服務(wù)器的接口協(xié)議。CGI使外部程序與Web服務(wù)器之間交互成為可能。CGI程序運(yùn)行在獨(dú)立的進(jìn)程中,并對每個Web請求創(chuàng)建一個進(jìn)程,這種方法非常容易實(shí)現(xiàn),但效率較差,難以擴(kuò)展。CGI程序運(yùn)行在獨(dú)立的進(jìn)程中,并對每個Web請求創(chuàng)建一個進(jìn)程,在結(jié)束時銷毀。這種“每個請求一個新進(jìn)程”的模型使得CGI程序非常容易實(shí)現(xiàn),但效率較差,難以擴(kuò)展。在高負(fù)載情況下,進(jìn)程創(chuàng)建和銷毀進(jìn)程的開銷變得很大。此外,由于地址空間無法共享,CGI進(jìn)程模型限制了資源重用方法,如重用數(shù)據(jù)庫連接、內(nèi)存緩存等。

          FastCGI:快速通用網(wǎng)關(guān)接口(Fast Common Gateway Interface/FastCGI)是一種讓交互程序與Web服務(wù)器通信的協(xié)議。FastCGI是早期通用網(wǎng)關(guān)接口(CGI)的增強(qiáng)版本。FastCGI致力于減少網(wǎng)頁服務(wù)器與CGI程序之間交互的開銷,從而使服務(wù)器可以同時處理更多的網(wǎng)頁請求。

          區(qū)別

          1. CGI每一次請求都會創(chuàng)建一個進(jìn)程,在請求結(jié)束之后進(jìn)程會銷毀。每一個請求,都重復(fù)執(zhí)行這樣的邏輯。FastCGI與最大的區(qū)別在于,使用持續(xù)的進(jìn)程來處理一連串的請求,不會在請求結(jié)束之后關(guān)閉進(jìn)程,而是下一個請求來了之后繼續(xù)使用。這些進(jìn)程由FastCGI服務(wù)器管理,而不是web服務(wù)器。FastCGI具體的進(jìn)程數(shù)量可以通過php-fpm.conf中的pm配置項(xiàng)進(jìn)行操作。

          2. 當(dāng)進(jìn)來一個請求時,web服務(wù)器把環(huán)境變量和這個頁面請求通過一個socket比如FastCGI進(jìn)程與web服務(wù)器(都位于本地)或者一個TCP 請求(FastCGI進(jìn)程在遠(yuǎn)端的server farm)傳遞給FastCGI進(jìn)程。服務(wù)傳入請求時,網(wǎng)絡(luò)服務(wù)器通過Unix域套接字、命名管道或TCP連接向FastCGI進(jìn)程發(fā)送環(huán)境變量信息和頁面請求。響應(yīng)通過相同的連接從進(jìn)程返回到網(wǎng)絡(luò)服務(wù)器,然后網(wǎng)絡(luò)服務(wù)器將該響應(yīng)傳遞給最終用戶。連接可能在響應(yīng)結(jié)束時關(guān)閉,但是web服務(wù)器和FastCGI服務(wù)進(jìn)程都將持續(xù),不會被銷毀。

          3. 每個單獨(dú)的FastCGI進(jìn)程在其生命周期內(nèi)可以處理許多請求,從而避免了每個請求進(jìn)程創(chuàng)建和終止的開銷。并發(fā)處理多個請求可以通過幾種方式來完成:通過內(nèi)部多路復(fù)用使用一個連接(即一個連接上的多個請求);通過使用多個連接;或者通過這些方法的混合??梢耘渲枚鄠€FastCGI服務(wù)器,提高穩(wěn)定性和可擴(kuò)展性。

          能簡單的描述一下Nginx與PHP通信的基本流程嗎?

          1. WebServer在啟動時,載入FastCGI管理器。

          2. FastCGI會完成初始化,啟動多個CGI解釋器。并等待客戶端的連接 當(dāng)客戶端連接的時候,F(xiàn)astCGI管理器會連接其中的一個CGI解釋器。webserver 將標(biāo)準(zhǔn)輸入和cgi配置發(fā)送給cgi。

          3. FastCGI將標(biāo)準(zhǔn)輸出和錯誤輸出返回給WebServer。當(dāng)FastCGI關(guān)閉時,意味著本次請求完成。然后FastCGI等待著FastCGI管理器給他提供的下一次請求。

          4. PHP請求過來的時候,NGINX會將請求發(fā)送給FastCGI的Master,發(fā)送給Worker。將編譯后的結(jié)果發(fā)送個Nginx,然后返回給客戶端。

          能說一下PHP的垃圾回收機(jī)制是如何實(shí)現(xiàn)的嗎?

          1. 在創(chuàng)建一個PHP變量時,會將這個變量存在zavl變量容器中。這個容器存儲的是這個變量的類型和值,初次之外還會存儲is_ref和refcount兩個額外的字段。

          2. refcount表示指向變量的元素個數(shù),is_ref表示變量是否有別名(是否被引用)。

          3. 如果refcount為0時,就回收該變量容器。如果一個zval的refcount減1之后大于0,它就會進(jìn)入垃圾緩沖區(qū)。

          4. 當(dāng)緩沖區(qū)達(dá)到最大值后,回收算法會循環(huán)遍歷zval,判斷其是否為垃圾,并進(jìn)行釋放處理。

          5. 當(dāng)前請求結(jié)束之后,PHP執(zhí)行腳本結(jié)束,也會清楚所有的變量信息。

          官網(wǎng)文檔:

          引用計數(shù)基本知識

          每個php變量存在一個叫"zval"的變量容器中。一個zval變量容器,除了包含變量的類型和值,還包括兩個字節(jié)的額外信息。第一個是"is_ref",是個bool值,用來標(biāo)識這個變量是否是屬于引用集合(reference set)。通過這個字節(jié),php引擎才能把普通變量和引用變量區(qū)分開來,由于php允許用戶通過使用&來使用自定義引用,zval變量容器中還有一個內(nèi)部引用計數(shù)機(jī)制,來優(yōu)化內(nèi)存使用。第二個額外字節(jié)是"refcount",用以表示指向這個zval變量容器的變量(也稱符號即symbol)個數(shù)。所有的符號存在一個符號表中,其中每個符號都有作用域(scope),那些主腳本(比如:通過瀏覽器請求的的腳本)和每個函數(shù)或者方法也都有作用域。

          引用計數(shù)基本知識

          每個php變量存在一個叫"zval"的變量容器中。一個zval變量容器,除了包含變量的類型和值,還包括兩個字節(jié)的額外信息。第一個是"is_ref",是個bool值,用來標(biāo)識這個變量是否是屬于引用集合(reference set)。通過這個字節(jié),php引擎才能把普通變量和引用變量區(qū)分開來,由于php允許用戶通過使用&來使用自定義引用,zval變量容器中還有一個內(nèi)部引用計數(shù)機(jī)制,來優(yōu)化內(nèi)存使用。第二個額外字節(jié)是"refcount",用以表示指向這個zval變量容器的變量(也稱符號即symbol)個數(shù)。所有的符號存在一個符號表中,其中每個符號都有作用域(scope),那些主腳本(比如:通過瀏覽器請求的的腳本)和每個函數(shù)或者方法也都有作用域。

          說說php的同步模式與swoole的攜程之間的區(qū)別?

          1. 首先,Swoole 只能運(yùn)行在命令行(Cli)模式下,所以我們開發(fā)調(diào)試都是使用命令行,而不是 php-fpm/apache 等。在 Swoole 中,我們可以使用\Swoole\Coroutine::create()創(chuàng)建協(xié)程,或者你也可以使用簡寫go()
          2. 我們一直在說 Swoole 協(xié)程適合用于 I/O 密集場景,在同樣的硬件配置環(huán)境下,它會比傳統(tǒng)的同步模式承載更多的訪問量。我們熟悉的文件讀寫、網(wǎng)絡(luò)通訊請求(MySQL、Redis、Http等)都是屬于 I/O 密集型場景。假設(shè)一次 SQL 查詢?yōu)?100ms,在傳統(tǒng)同步模式下,當(dāng)前進(jìn)程在這 100ms 的時間里,是不能做其它操作的。如果要執(zhí)行十次這個 SQL,可能需要耗費(fèi) 1s 以上。而如果用協(xié)程,雖然不同協(xié)程之間也是按順序執(zhí)行,但是在前一個等待 100ms 期間,底層會調(diào)度 CPU,去執(zhí)行其它協(xié)程的操作。也就是說,可能第一個查詢還沒返回結(jié)果,其它幾個查詢就已經(jīng)發(fā)送給了 MySQL 并正在執(zhí)行中了。如果開啟十個協(xié)程,分別執(zhí)行這個 SQL,可能只需要耗費(fèi) 100+ms 即可完成。

          php-fpm與swoole之間有什么區(qū)別?

          php-fpm與swoole介紹:

          1. 早期版本的 PHP 并沒有內(nèi)置的 WEB 服務(wù)器,而是提供了 SAPI(Server API)給第三方做對接?,F(xiàn)在非常流行的 php-fpm 就是通過 FastCGI 協(xié)議來處理 PHP 與第三方 WEB 服務(wù)器之間的通信。
          2. Swoole 采用的也是 Master/Worker 模式,不同的是 Master 進(jìn)程有多個 Reactor 線程,Master 只是一個事件發(fā)生器,負(fù)責(zé)監(jiān)聽 Socket 句柄的事件變化。Worker 以多進(jìn)程的方式運(yùn)行,接收來自 Reactor 線程的請求,并執(zhí)行回調(diào)函數(shù)(PHP 編寫的)。啟動 Master 進(jìn)程的流程大致是:初始化模塊。初始化請求。因?yàn)?swoole 需要通過 cli 的方式運(yùn)行,所以初始化請求時,不會初始化 PHP 的全局變量,如 _POST, $_GET 等。執(zhí)行 PHP 腳本。包括詞法、語法分析,變量、函數(shù)、類的初始化等,Master 進(jìn)入監(jiān)聽狀態(tài),并不會結(jié)束進(jìn)程。

          Swoole 加速的原理

          由 Reactor(epoll 的 IO 復(fù)用方式)負(fù)責(zé)監(jiān)聽 Socket 句柄的事件變化,解決高并發(fā)問題。通過內(nèi)存常駐的方式節(jié)省 PHP 代碼初始化的時間,在使用笨重的框架時,用 swoole 加速效果是非常明顯的。

          php-fpm與swoole區(qū)別

          1. PHP-FPM是Master 主進(jìn)程 / Worker 多進(jìn)程模式。
          2. 啟動 Master,通過 FastCGI 協(xié)議監(jiān)聽來自 Nginx 傳輸?shù)恼埱蟆?/li>
          3. 每個 Worker 進(jìn)程只對應(yīng)一個連接,用于執(zhí)行完整的 PHP 代碼。
          4. PHP 代碼執(zhí)行完畢,占用的內(nèi)存會全部銷毀,下一次請求需要重新再進(jìn)行初始化等各種繁瑣的操作。
          5. 比較適用于HTTP Server。
          6. Swoole是Master 主進(jìn)程(由多個 Reactor 線程組成)/ Worker 多進(jìn)程(或多線程)模式。
          7. 啟動 Master,初始化 PHP 模塊,由 Reactor 監(jiān)聽 Socket 句柄的事件變化。
          8. Reactor 主線程負(fù)責(zé)子多線程的均衡問題,Manager 進(jìn)程管理 Worker 多進(jìn)程,包括 TaskWorker 的進(jìn)程。
          9. 每個 Worker 接受來自 Reactor 的請求,只需要執(zhí)行回調(diào)函數(shù)部分的 PHP 代碼。
          10. 只在 Master 啟動時執(zhí)行一遍 PHP 初始化代碼,Master 進(jìn)入監(jiān)聽狀態(tài),并不會結(jié)束進(jìn)程。
          11. 不僅可以用于 HTTP Server,還可以建立 TCP 連接、WebSocket 連接。

          索引有哪些優(yōu)缺點(diǎn)?

          索引的優(yōu)點(diǎn)

          1. 可以大大加快數(shù)據(jù)的檢索速度,這也是創(chuàng)建索引的最主要的原因。
          2. 通過使用索引,可以在查詢的過程中,使用優(yōu)化隱藏器,提高系統(tǒng)的性能。

          索引的缺點(diǎn)

          1. 時間方面:創(chuàng)建索引和維護(hù)索引要耗費(fèi)時間,具體地,當(dāng)對表中的數(shù)據(jù)進(jìn)行增加、刪除和修改的時候,索引也要動態(tài)的維護(hù),會降低增/改/刪的執(zhí)行效率;
          2. 空間方面:索引需要占物理空間。

          MySQL有哪幾種索引類型?

          1. 從數(shù)據(jù)結(jié)構(gòu)上來劃分:BTree索引(B-Tree或B+Tree索引)、Hash索引、full-index(全文索引)、R-Tree索引(空間索引)。這里所描述的是索引存儲時保存的形式。
          2. 從應(yīng)用層次來分:普通索引,唯一索引,復(fù)合索引。普通索引:即一個索引只包含單個列,一個表可以有多個單列索引。唯一索引:索引列的值必須唯一,但允許有空值。復(fù)合索引:多列值組成一個索引,專門用于組合搜索,其效率大于索引合并。聚簇索引(聚集索引):并不是一種單獨(dú)的索引類型,而是一種數(shù)據(jù)存儲方式。具體細(xì)節(jié)取決于不同的實(shí)現(xiàn),InnoDB的聚簇索引其實(shí)就是在同一個結(jié)構(gòu)中保存了B-Tree索引(技術(shù)上來說是B+Tree)和數(shù)據(jù)行。非聚簇索引:不是聚簇索引,就是非聚簇索引。
          3. 根據(jù)中數(shù)據(jù)的物理順序與鍵值的邏輯(索引)順序關(guān)系:聚集索引,非聚集索引。

          講一講聚簇索引與非聚簇索引?

          在 InnoDB 里,索引B+ Tree的葉子節(jié)點(diǎn)存儲了整行數(shù)據(jù)的是主鍵索引,也被稱之為聚簇索引,即將數(shù)據(jù)存儲與索引放到了一塊,找到索引也就找到了數(shù)據(jù)。而索引B+ Tree的葉子節(jié)點(diǎn)存儲了主鍵的值的是非主鍵索引,也被稱之為非聚簇索引、二級索引。聚簇索引與非聚簇索引的區(qū)別:

          1. 非聚集索引與聚集索引的區(qū)別在于非聚集索引的葉子節(jié)點(diǎn)不存儲表中的數(shù)據(jù),而是存儲該列對應(yīng)的主鍵(行號)
          2. 對于InnoDB來說,想要查找數(shù)據(jù)我們還需要根據(jù)主鍵再去聚集索引中進(jìn)行查找,這個再根據(jù)聚集索引查找數(shù)據(jù)的過程,我們稱為回表。第一次索引一般是順序IO,回表的操作屬于隨機(jī)IO。需要回表的次數(shù)越多,即隨機(jī)IO次數(shù)越多,我們就越傾向于使用全表掃描 。
          3. 通常情況下, 主鍵索引(聚簇索引)查詢只會查一次,而非主鍵索引(非聚簇索引)需要回表查詢多次。當(dāng)然,如果是覆蓋索引的話,查一次即可
          4. 注意:MyISAM無論主鍵索引還是二級索引都是非聚簇索引,而InnoDB的主鍵索引是聚簇索引,二級索引是非聚簇索引。我們自己建的索引基本都是非聚簇索引。

          非聚簇索引一定會回表查詢嗎?

          不一定,這涉及到查詢語句所要求的字段是否全部命中了索引,如果全部命中了索引,那么就不必再進(jìn)行回表查詢。一個索引包含(覆蓋)所有需要查詢字段的值,被稱之為"覆蓋索引"。換而言之,如果查找的字段在索引中就能夠找到,就不需要在進(jìn)行回表查詢。

          舉個簡單的例子,假設(shè)我們在員工表的年齡上建立了索引,那么當(dāng)進(jìn)行select score from student where score > 90的查詢時,在索引的葉子節(jié)點(diǎn)上,已經(jīng)包含了score 信息,不會再次進(jìn)行回表查詢。

          一線互聯(lián)大廠,常見面試真題總結(jié)。點(diǎn)擊查看。


          瀏覽 29
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  91人人人人人 | 国产777无码 | 中文字幕无码高清的A V不卡的A V | 露脸丨91丨九色露脸 | 天天摸天天碰成人免费视频 |