PHP面試題基礎知識有哪些

這篇文章主要介紹“PHP面試題基礎知識有哪些”,在日常操作中,相信很多人在PHP面試題基礎知識有哪些問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”PHP面試題基礎知識有哪些”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

創(chuàng)新互聯(lián)專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務,包含不限于成都做網(wǎng)站、成都網(wǎng)站設計、融安網(wǎng)絡推廣、成都小程序開發(fā)、融安網(wǎng)絡營銷、融安企業(yè)策劃、融安品牌公關、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運營等,從售前售中售后,我們都將竭誠為您服務,您的肯定,是我們最大的嘉獎;創(chuàng)新互聯(lián)為所有大學生創(chuàng)業(yè)者提供融安建站搭建服務,24小時服務熱線:18980820575,官方網(wǎng)址:bm7419.com

PHP面試題基礎知識有哪些

一、php 數(shù)組底層實現(xiàn)原理

1、底層實現(xiàn)是通過散列表(hash table) + 雙向鏈表(解決hash沖突)

  • hashtable:將不同的關鍵字(key)通過映射函數(shù)計算得到散列值(Bucket->h) 從而直接索引到對應的Bucket

  • hash表保存當前循環(huán)的指針,所以foreach 比for更快

  • Bucket:保存數(shù)組元素的key和value,以及散列值h

2、如何保證有序性

  • 1. 散列函數(shù)和元素數(shù)組(Bucket)中間添加一層大小和存儲元素數(shù)組相同的映射表。

  • 2. 用于存儲元素在實際存儲數(shù)組中的下標

  • 3. 元素按照映射表的先后順序插入實際存儲數(shù)組中

  • 4. 映射表只是原理上的思路,實際上并不會有實際的映射表,而是初始化的時候分配Bucket內存的同時,還會分配相同數(shù)量的 uint32_t 大小的空間,然后將 arData 偏移到存儲元素數(shù)組的位置。

3、解決hash重復(php使用的鏈表法):

  • 1. 鏈表法:不同關鍵字指向同一個單元時,使用鏈表保存關鍵字(遍歷鏈表匹配key)

  • 2. 開放尋址法:當關鍵字指向已經(jīng)存在數(shù)據(jù)的單元的時候,繼續(xù)尋找其他單元,直到找到可用單元(占用其他單元位置,更容易出現(xiàn)hash沖突,性能下降)

4、基礎知識

  • 鏈表:隊列、棧、雙向鏈表、

  • 鏈表    :元素 + 指向下一元素的指針

  • 雙向鏈表:指向上一元素的指針 + 元素 + 指向下一元素的指針

二、冒泡排序的時間復雜度和空間復雜度

1、代碼實現(xiàn)

         $arr = [2, 4, 1, 5, 3, 6];
         for ($i = 0; $i < (count($arr)); $i++) {
             for ($j = $i + 1; $j < (count($arr)); $j++) {
                 if ($arr[$i] <= $arr[$j]) {
                     $temp = $arr[$i];
                     $arr[$i] = $arr[$j];
                     $arr[$j] = $temp;
                 }
             }
         }
     result : [6,5,4,3,2,1]

2、計算原理

  • 第一輪:將數(shù)組的第一個元素和其他所有的元素進行比較,哪個元素更大,就換順序,從而冒泡出第一大(最大)的元素

  • 第一輪:將數(shù)組的第二個元素和其他所有的元素進行比較(第一大已經(jīng)篩選出來不用繼續(xù)比較了),哪個元素更大,就換順序,從而冒泡出第二大的元素

  • ... 依次類推,冒泡從大到小排序的數(shù)組

平均時間復雜度:O(n^2)

最優(yōu)時間復雜度:O(n) ,需要加判斷,第一次循環(huán)如果一次都沒有交換就直接跳出循環(huán)

空間復雜度:O(1),交換元素的時候的臨時變量占用的空間

最優(yōu)空間復雜度:O(1),排好序,不需要交換位置

3、時間復雜度和空間復雜度

時間復雜度:全程為漸進時間復雜度,估算對處理器的使用效率(描述算法的效率趨勢,并不是指算法具體使用的時間,因為不同機器的性能不一致,只是一種效率計算的通用方法)

表示方法:大O符號表示法

復雜度量級:

  • 常數(shù)階O(1)

  • 線性階O(n)

  • 平方階O(n2)

  • 立方階O(n3)

  • K次方階O(n^k)

  • 指數(shù)階(2^n)

  • 對數(shù)階O(logN)

  • 線性對數(shù)階O(nlogN)

時間復制類型:

  • 最好時間復雜度

  • 最壞時間復雜度

  • 平均時間復雜度

  • 均攤時間復雜度

空間復雜度:全程漸進空間復雜度,估算對計算機內存的使用程度(描述算法占用的存儲空間的趨勢,不是實際占用空間,同上)

三、網(wǎng)絡七層協(xié)議及 TCP 和 TCP

應用層、表示層、會話層、傳輸層、網(wǎng)絡層、(數(shù)據(jù))鏈路層、物理層

記憶套路:

首字:應表會傳(物鏈網(wǎng))

第一個字:應用層(出現(xiàn)次數(shù)多,易憶)

前四個正向:應表 - 會傳

后三個反向:物聯(lián)網(wǎng)諧音比網(wǎng)鏈物更好記

四、TCP 和 UDP 的特點和區(qū)別

1、都是屬于傳輸層協(xié)議

2、TCP

  • 面向連接,所以只能一對一

  • 面向字節(jié)流傳輸

  • 數(shù)據(jù)可靠,不丟失

  • 全雙工通信

3、UDP(根據(jù)TCP特點反記)

  • 無連接,支持一對一,一對多,多對多

  • 面向保溫傳輸

  • 首部開銷小,數(shù)據(jù)不一定可靠但是速度更快

五、TCP 的三次握手和四次揮手

1、三次握手:

  • 1)第一次:客戶端發(fā)送SYN = 1,seq = client_isn

    作用:

    客戶端:無

    服務端:確認自己的接收功能和客戶端的發(fā)送功能

  • 2)第二次:服務端發(fā)送SYN = 1,seq = server_isn,ACK =client_isn +1

    作用:

    客戶端:確認自己發(fā)送和接收都正常,確認服務端的接收和發(fā)送正常

    服務端:確認自己的接收正常,確認服務端的發(fā)送正常(這時候服務端還不能確認客戶端接收是否正常)

  • 3)第三次:客戶端發(fā)送SYN = 0,  ACK =  server_isn+1,seq =client_isn+1

    作用:雙方確認互相的接收和發(fā)送正常,建立連接

2、四次揮手

  • 1)第一次:客戶端發(fā)送FIN

    作用:告訴服務端我沒有數(shù)據(jù)發(fā)送了(但是還能接收數(shù)據(jù))

  • 2)第二次:服務端發(fā)送ACK

    作用:告訴客戶端收到請求了,可能服務端可能還有數(shù)據(jù)需要發(fā)送,所以客戶端收到進入FIN_WAIT狀態(tài),等服務端數(shù)據(jù)傳輸完之后發(fā)送FIN

  • 3)第三次:服務端發(fā)送FIN

    作用:服務端告訴客戶端我發(fā)送完了,可以關閉連接了。

  • 4)第四次:客戶端發(fā)送ACK

    作用:客戶端收到FIN之后,擔心服務端不知道要關閉,所以發(fā)送一個ACK,進入TIME_WAIT,等待2MSL之后如果沒有收到回復,證明服務端已經(jīng)關閉了,這時候客戶端也關閉連接。

注意:

  • 當收到對方的FIN報文時,僅僅表示對方不再發(fā)送數(shù)據(jù)了但是還能接收數(shù)據(jù)

  • 最后需要等待2MSL是因為網(wǎng)絡是不可靠的,如果服務端沒有收到最后一次ACK,服務端會重新放FIN包然后等客戶端再次發(fā)送ACK包然后關閉(所以客戶端最后發(fā)送ACK之后不能立即關閉連接)

六、HTTP 狀態(tài)碼

1、狀態(tài)碼分類  

  • - 1xx:信息,服務器收到請求,需要請求者繼續(xù)操作

  • - 2xx:成功

  • - 3xx:重定向

  • - 4xx:客戶端錯誤

  • - 5xx:服務端錯誤

2、常用狀態(tài)碼

  • 200:請求成功

  • 301:永久重定向

  • 302:臨時移動

  • 400 bad request:客戶端請求語法錯誤

  • 401 unauthorized:客戶端沒有權限

  • 403 forbidden:服務器拒絕客戶端請求

  • 404 not found:客戶端請求資源不存在

  • 500 Internal Server Eerro:服務器內部錯誤

  • 502 bad gateway:作為網(wǎng)關或者代理工作的服務器嘗試執(zhí)行請求時,從上游服務器接收到無效的響應

  • 503 Service Unavailable 超載或系統(tǒng)維護

  • 504 Gateway timeout:網(wǎng)關超時

3、502 的原因及解決方法

原因:nginx將請求提交給網(wǎng)關(php-fpm)處理異常導致

1)fastcgi 緩沖區(qū)設置過小

fastcgi_buffers 8 16k;

fastcgi_buffer_size 32k;

2)php-cgi的進程數(shù)設置過少

查看FastCgi進程數(shù):netstat -anpo | grep "php-cgi"| wc -l

調整參數(shù)最大子進程數(shù):max_children

一般按照單個進程20M計算需要需要設置的子進程數(shù)

3)max_requests(內存溢出或頻繁重啟)

參數(shù)指明每個children最多能處理的請求數(shù)量,到達最大值之后會重啟children。

設置過小可能導致頻繁重啟children:

php將請求輪詢給每個children,在大流量的場景下,每一個children 到達最大值的時間差不多,如果設置過小可能多個children 在同一時間關閉,nginx無法將請求轉發(fā)給php-fpm,cpu降低,負載變高。

設置過大可能導致內存泄露

4)php執(zhí)行時間超過nginx等待時間

fastcgi_connect_timeout

fastcgi_send_timeout

fastcgi_read_timeout

5)fastcgi執(zhí)行時間

max_execution_time

七、http 和 HTTPS 的區(qū)別

1、端口:http 80; https :443

2、http無狀態(tài),https是有http + ssl構建的可進行加密傳輸?shù)膮f(xié)議

3、http明文傳輸,https加密傳輸

4、http更快,三次握手三個包,https 需要12個包(3個tcp包+9個ssl握手包)

八、redis 分布式鎖及問題

1、實現(xiàn):

加鎖:setnx

解鎖:del

鎖超時:expire

2、可能出現(xiàn)的問題

  • 1)setnx 和expire非原子性問題(加鎖之后還沒來得及設置超時就掛了)

    解決方案:

    Redis 2.6.12以上版本為set指令增加了可選參數(shù),偽代碼如下:set(key,1,30,NX),這樣就可以取代setnx指令

  • 2)超時誤刪其他進程鎖。(A進程執(zhí)行超時,導致鎖釋放,這時候B進程獲取鎖開始處理請求,這時候A進程處理完成,會誤刪B進程的鎖)

    解決方案:只能刪除自己進程的鎖 (lua腳本防止B進程獲取過期鎖之后誤刪A進程的鎖)

  • 3)并發(fā)場景,A進程執(zhí)行超時導致鎖釋放,這時候B進程獲取到鎖。

    解決方案:開啟守護進程,給當前進程要過期的鎖延時。

  • 4)單點實例安全問題

    單機宕機之后導致所有客戶端無法獲取鎖

    解決:

    主從復制,因為是異步完成的所以無法完全實現(xiàn)解決

九、redis 的數(shù)據(jù)類型及應用場景

1、string :

普通的key/value存儲

2、hash:

hashmap:鍵值隊集合,存儲對象信息

3、list:

雙向鏈表:消息隊列

4、set:

value永遠為null的hashMap:無序集合且不重復:計算交集、并集、差集、去重值

5、zset:

有序集合且不重復:hashMap(去重) + skiplist跳躍表(保證有序):排行榜

十、redis 實現(xiàn)持久化的方式及原理、特點

1、RDB持久化(快照):指定時間間隔內的內存數(shù)據(jù)集快照寫入磁盤     

1)fork一個子進程,將快照內容寫入臨時RDB文件中(dump.rdb),當子進程寫完快照內容之后新的文件替換老的文件

2)整個redis數(shù)據(jù)庫只包含一個備份文件

3)性能最大化,只需要fork子進程完成持久化工作,減少磁盤IO

4)持久化之前宕機可能會導致數(shù)據(jù)丟失

2、AOF持久化 :以日志的形式記錄服務器的所有的寫、刪除操作

1)每接收到一個寫的命令用write函數(shù)追加到文件appendonly.aof

2)持久化的文件會越來越大,存在大量多余的日志(0 自增100次到100,會產(chǎn)生100條日志記錄)

3)可以設置不同的fsync策略

  • appendfsync everysec :1s一次,最多丟失1s的數(shù)據(jù)(默認)

  • appendfsync always    :每次變動都會執(zhí)行一次

  • appendfsync no          :不處理

4)AOF文件太大之后會進行重寫:壓縮AOF文件大小

  • fork一個子進程,將redis內地數(shù)據(jù)對象的最新狀態(tài)寫入AOF臨時文件(類似rdb快照)

  • 主進程收到的變動會先寫入內存中,然后同步到老的AOF文件中(重寫失敗之后也能保證數(shù)據(jù)完整性)

  • 子進程完成重寫之后會將內存中的新變動同步追加到AOF的臨時文件中

  • 父進程將臨時AOF文件替換成新的AOF文件,并重命名。之后收到的新命令寫入到新的文件中

十一、秒殺設計流程及難點

1、靜態(tài)緩存

2、nginx 負載均衡  

三種方式:DNS輪詢、IP負債均衡、cdn

3、限流機制

方式:ip限流、接口令牌限流、用戶限流、header動態(tài)token(前端加密,后端解密)

4、分布式鎖

方式:

  • setnx + expire (非原子性,redis2.6 之后set保證原子性)

  • 釋放鎖超時 (開啟守護進程自動續(xù)時間)

  • 過期鎖誤刪其他線程(requestId驗證或者lua腳本保證查 + 刪的原子性)

5、緩存數(shù)據(jù)

方式:

  • 緩存擊穿:緩存數(shù)據(jù)預熱 + 布隆過濾器/空緩存

  • 緩存雪崩:緩存設置隨機過期時間,防止同一時間過期

6、庫存及訂單

  • 扣庫存

    • redis 自減庫存,并發(fā)場景下可能導致負數(shù),影響庫存回倉:使用lua腳本保證原子性

    • redis預扣庫存之后,然后使用異步消息創(chuàng)建訂單并更新庫存變動

    • 數(shù)據(jù)庫更新庫存使用樂觀鎖:where stock_num - sell_num > 0

    • 添加消息發(fā)送記錄表及重試機制,防止異步消息丟失

  • 創(chuàng)建訂單

    • 前端建立websocket連接或者輪詢監(jiān)聽訂單狀態(tài)

    • 消費驗證記錄狀態(tài),防止重復消費

  • 回倉

    • 創(chuàng)建訂單之后發(fā)送延時消息,驗證訂單支付狀態(tài)及庫存是否需要回倉

十二、防 sql 注入

1、過濾特殊字符

2、過濾數(shù)據(jù)庫關鍵字

3、驗證數(shù)據(jù)類型及格式

4、使用預編譯模式,綁定變量

十三、事務隔離級別

1、標準的sql隔離級別實現(xiàn)原理

  • 未提交讀:其他事務可以直接讀到?jīng)]有提交的:臟讀

    • 事務對當前被讀取的數(shù)據(jù)不加鎖

    • 在更新的瞬間加行級共享鎖到事務結束釋放

  • 提交讀:事務開始和結束之間讀取的數(shù)據(jù)可能不一致,事務中其他事務修改了數(shù)據(jù):不可重復度

    • 事務對當前讀取的數(shù)據(jù)(被讀到的時候)行級共享鎖,讀完釋放

    • 在更新的瞬間加行級排他鎖到事務結束釋放

  • 可重復讀:事務開始和結束之前讀取的數(shù)據(jù)保持一致,事務中其他事務不能修改數(shù)據(jù):可重復讀

    • 事務對當前讀到的數(shù)據(jù)從事務一開始就加一個行級共享鎖

    • 在更新的瞬間加行級排他鎖到事務結束釋放

    • 其他事務再事務過程中可能會新增數(shù)據(jù)導致幻讀

  • 串行化

    • 事務讀取數(shù)據(jù)時加表級共享鎖

    • 事務更新數(shù)據(jù)時加表級排他鎖

2、innodb的事務隔離級別及實現(xiàn)原理(??!和上面的不一樣,區(qū)分理解一個是隔離級別 一個是?。∈聞眨?!隔離級別)

1)基本概念

  • mvcc:多版本并發(fā)控制:依賴于undo log 和read view

    • 讓數(shù)據(jù)都讀不會對數(shù)據(jù)加鎖,提高數(shù)據(jù)庫并發(fā)處理能力

    • 寫操作才會加鎖

    • 一條數(shù)據(jù)有多個版本,每次事務更新數(shù)據(jù)的時候會生成一個新的數(shù)據(jù)版本,舊的數(shù)據(jù)保留在undo log

    • 一個事務啟動的時候只能看到所有已經(jīng)提交的事務結果

  • 當前讀:讀取的是最新版本

  • 快照讀:讀取的是歷史版本

  • 間隙鎖:間隙鎖會鎖住一個范圍內的索引

    • update id between 10 and 20

    • 無論是否范圍內是否存在數(shù)據(jù),都會鎖住整個范圍:insert id = 15,將被防止

    • 只有可重復讀隔離級別才有間隙鎖

  • next-key lock:

    • 索引記錄上的記錄鎖+ 間隙鎖(索引值到前一個索引值之間的間隙鎖)

    • 前開后閉

    • 阻止幻讀

2)事務隔離級別

  • 未提交讀

    • 事務對當前讀取的數(shù)據(jù)不加鎖,都是當前讀

    • 在更新的瞬間加行級共享鎖到事務結束釋放

  • 提交讀

    • 事務對當前讀取的數(shù)據(jù)不加鎖,都是快照讀

    • 在更新的瞬間加行級排他鎖到事務結束釋放

  • 可重復讀

    • 主從復制的情況下 ,如果沒有間隙鎖,master庫的A、B進程

    • A進程 delete id < 6 ;然后還沒有commit

    • B進程insert id = 3,commit

    • A進程提交commit

    • 該場景下,主庫會存在一條id =3 的記錄,但是binlog里面是先刪除再新增就會導致從庫沒有數(shù)據(jù),導致主從的數(shù)據(jù)不一致

    • 事務對當前讀取的數(shù)據(jù)不加鎖,都是快照讀

    • 事務再更新某數(shù)據(jù)的瞬間,必須加行級排他鎖(Record 記錄鎖、GAP間隙鎖、next-key 鎖),事務結束釋放

    • 間隙鎖解決的是幻讀問題

    • MVCC的快照解決的是不可重復讀問題

  • 串行化

    • 事務讀取數(shù)據(jù)時加表級,當前讀

    • 事務更新數(shù)據(jù)時加表級排他鎖

十四、索引原理

索引就是幫助數(shù)據(jù)庫高效查找數(shù)據(jù)的存儲結構,存儲再磁盤中,需要消耗磁盤IO

1、存儲引擎

  • myisam 支持表鎖,索引和數(shù)據(jù)分開存儲適合跨服務器遷移

  • innodb 支持行鎖,索引和數(shù)據(jù)存儲再一個文件

2、索引類型

  • hash索引

    • 適合精確查詢且效率高

    • 無法排序、不適合范圍查詢

    • hash沖突的情況下需要遍歷鏈表(php數(shù)組的實現(xiàn)原理、redis zset 的實現(xiàn)原理類似)

  • b-tree、b+tree

    • b+tree 的數(shù)據(jù)全部存儲在葉子節(jié)點,內部節(jié)點只存key,一次磁盤IO能獲取到更多的節(jié)點

    • b-tree 的內部節(jié)點和葉子節(jié)點都存儲key和數(shù)據(jù),查找數(shù)據(jù)不需要找到葉子節(jié)點,內部節(jié)點可以直接返回數(shù)據(jù)

    • b+tree 增加了葉子節(jié)點到相鄰節(jié)點的指針,方便返回查詢遍歷

    • b-tree 和b+tree的去區(qū)別

  • 聚簇索引和非聚簇索引

    • 聚簇索引  :索引和數(shù)據(jù)存儲在一個節(jié)點

    • 非聚簇索引:索引和數(shù)據(jù)分開存儲,通過索引找到數(shù)據(jù)實際存儲的地址

    • 概念

    • 詳解:

      • innodb 使用的聚簇索引,且默認主鍵索引為聚簇索引(沒有主鍵索引的時候,選擇一個非空索引,還沒有則隱式的主鍵索引),輔助索引指向聚簇索引位置,然后在找到實際存儲地址

      • myisam 使用非聚簇索引,所有的索引都只需要查詢一次就能找到數(shù)據(jù)

      • 聚簇索引的優(yōu)勢和略勢

        1. 索引和數(shù)據(jù)在一起,同一頁的數(shù)據(jù)會被緩存到(buffer)內存中,所以查看同一頁數(shù)據(jù)的時候只需要從內存中取出,

        2. 數(shù)據(jù)更新之后之只需要維護主鍵索引即可,輔助索引不受影響

        3. 輔助索引存的是主鍵索引的值,占用更多的物理空間。所以會受到影響

        4. 使用隨機的UUID,數(shù)據(jù)分布不均勻,導致聚簇索引可能掃全表,降低效率,所以盡量使用自增主鍵id

十五、分表 (分庫) 的策略

1、流程

評估容量和分表數(shù)量-> 根據(jù)業(yè)務選定分表key->分表規(guī)則(hash、取余、range)->執(zhí)行->考慮擴容問題

2、水平拆分

  • 根據(jù)字段水平拆分為多個表

  • 每個表的結構相同

  • 所有分表的合集是全量數(shù)量

3、垂直拆分

  • 根據(jù)字段垂直拆分

  • 表結構不一樣,分表的同一個關聯(lián)行是一條完整的數(shù)據(jù)

  • 擴展表,熱點字段和非熱點字段的拆分(列表和詳情的拆分)

  • 獲取數(shù)據(jù)時,盡量避免使用join,而是兩次查詢結果組合

4、問題

  • 跨庫join問題

    • 全局表:需要關聯(lián)部分系統(tǒng)表的場景

    • 冗余法:常用字段進行冗余

    • 組裝法:多次查詢的結果進行組裝

  • 跨節(jié)點的分頁、排序、函數(shù)問題

  • 事務一致性

  • 全局主鍵id

    • 使用uuid -> 會降低聚簇索引效率

    • 使用分布式自增id

  • 擴容問題

    • 新數(shù)據(jù)進行雙寫,同時寫進新老數(shù)據(jù)庫

    • 舊數(shù)據(jù)復制到新數(shù)據(jù)庫

    • 以老數(shù)據(jù)庫為準,驗證數(shù)據(jù)一致性之后刪除冗余數(shù)據(jù)

    • 從庫升級為主庫,數(shù)據(jù)一致,只需要刪除冗余數(shù)據(jù)即可

    • 成倍擴容:需要在加一倍從庫

    • 升級從庫

    • 雙寫遷移:

十六、select 和 update 的執(zhí)行流程

1、MySQL 構成

  • server層:連接器->緩存器->分析器(預處理器)->優(yōu)化器->執(zhí)行器

  • 引擎層  : 查詢和存儲數(shù)據(jù)

2、select 執(zhí)行過程

  • 客戶端發(fā)送請求,建立連接

  • server層查找緩存,命中直接返回,否則繼續(xù)

  • 分析七分析sql語句以及預處理(驗證字段合法性及類型等)

  • 優(yōu)化器生成執(zhí)行計劃

  • 執(zhí)行器調用引擎API查詢結果

  • 返回查詢結果

3、update執(zhí)行過程

  • 基礎概念

    • redo log大小固定,循環(huán)寫入

    • redo log 就像一個圓圈,前面是check point (到這個point就開始覆蓋老的日志),后面是write point (當前寫到的位置)

    • write point 和check point 重疊的時候就證明redo log 滿了,需要開始同步redo log 到磁盤中了

    • 記錄日志是順序IO

    • 直接寫入磁盤(刷盤)是隨機IO,因為數(shù)據(jù)是隨機的,可能分布在不同的扇區(qū)

    • 順序IO的效率更高,先寫入修改日志,可以延遲刷盤時機,提高吞吐量

    • redo log(重做日志),innodb特有的日志,物理日志,記錄修改

    • redo log是重復寫,空間固定且會用完,會覆蓋老日志

    • binlog 是server層共有的日志,邏輯日志,記錄語句的原始邏輯

    • binlog 是追加寫到一定大小切換到下一個,不會覆蓋以前的日志

    • redo log主要是用來恢復崩潰,bin log是用來記錄歸檔的二進制日志

    • redo log只能恢復短時間內的數(shù)據(jù),binlog可以通過設置恢復更大的數(shù)據(jù)

    • buffer pool(緩存池),在內存中,下次讀取同一頁的數(shù)據(jù)的時候可以直接從buffer pool中返回(innodb的聚簇索引)

    • 更新數(shù)據(jù)的時候先更新buffer pool,然后在更新磁盤

    • 臟頁:內存中的緩存池更新了,但是沒有更新磁盤

    • 刷臟:inndb 中有一個專門的進程將buffer pool的數(shù)據(jù)寫入磁盤,每隔一段時間將多個修改一次性寫入磁盤

    • redo log 和 binlog

    • WAL(write-ahead-logging)先寫日志方案

    • redo log 刷盤機制,check point

  • 執(zhí)行步驟(兩階段提交 - 分布式事務,保證兩個日志的一致性)

    • 分析更新條件,查找需要更新的數(shù)據(jù)(會用到緩存)

    • server 調用引擎層的API,Innodb 更新數(shù)據(jù)到內存中,然后寫入redo log,然后進入prepare

    • 引擎通知server層開始提交數(shù)據(jù)

    • server層寫入binlog 日志,并且調用innodb 的接口發(fā)出commit請求

    • 引擎層收到請求之后提交commit

  • 宕機后數(shù)據(jù)崩潰恢復規(guī)則

    • 如果redo log 狀態(tài)為commit ,則直接提交

    • 如果redo log 狀態(tài)為prepare,則判斷binlog 中的事務是否commit,是則提交,否則回滾

  • 如果不使用兩次提交的錯誤案例(update table_x set value = 10 where value = 9)

    • 先redo log 再寫入binlog

      1. redo log 寫完之后,binlog沒寫完,這時候宕機。

      2. 重啟之后redo log 完整,所以恢復數(shù)據(jù) value = 10

      3. bin log日志中沒有記錄,如果需要恢復數(shù)據(jù)的時候 value = 9

    • 先寫binlog 再寫redo log

      1. binlog 寫入完成,redo log 未完成

      2. 重啟之后沒有redo log ,所以value 還是9

      3. 當需要恢復數(shù)據(jù)的時候binlog 日志完整,value 更新成10

  • undo log

    • 在更新寫入buffer pool之前記錄

    • 如果更新過程中出錯,直接回滾到undo log 的狀態(tài)

十七、binlog 的作用和三種格式

作用:

1. 數(shù)據(jù)恢復

2. 主從復制

格式(二進制文件):

1)statement

  • 1. 記錄每次sql語句的原文

  • 2. 刪除一個表只需要記錄一條sql語句,不需要記錄每一行的變化,節(jié)約IO,提高性能,減少日志量

  • 3. 可能出現(xiàn)主從不一致(存儲過程、函數(shù)等)

  • 4. RC隔離級別(讀提交),因為binlog 記錄順序是按照事務commit 順序記錄的,所以可能導致主從復制不一致。通過可重復讀級別的間隙鎖的引入,可以解決。

2)row

  • 1. 記錄每條記錄的修改情況,不需要記錄sql語句的上下文記錄

  • 2. 導致binlog日志量很大

  • 3. 刪除一個表:記錄每條記錄都被刪除的狀況

3)mixed

  • 1. 前兩個格式的混合版

  • 2. 根據(jù)語句自動選擇使用哪一種:

    • 一般的sql語句修改使用statement

    • 修改表結構、函數(shù)、存儲過程等操作選擇row

    • update 和delete 還是會記錄全部記錄的變化

十八、主從同步(主從復制)的原理和問題及讀寫分離

1、解決的問題

  • 數(shù)據(jù)分布

  • 負載均衡

  • 數(shù)據(jù)備份,高可用,避免單點失敗

  • 實現(xiàn)讀寫分離,緩解數(shù)據(jù)庫壓力

  • 升級測試(使用高版本mysql當從庫)

2、支持的復制類型(binlog 的三種格式)

  • 基于sql語句的復制

  • 基于行的復制

  • 混合型復制

3、原理

1)基礎概念

  • 從庫生成兩個線程

    • I/O線程

    • SQL線程

  • 主庫生成線程

    • log dumo 線程

2)流程(主節(jié)點必須開啟bin log功能,)

  • 1. 從節(jié)點開啟start slave 命令之后,創(chuàng)建一個IO進程連接到主節(jié)點

  • 2. 連接成功之后,主節(jié)點創(chuàng)建一個 log dump線程(主節(jié)點會為每一個從節(jié)點創(chuàng)一個log dump線程)

  • 3. 當binlog發(fā)生變化時,主節(jié)點的dump log線程會讀取bin-log內容并發(fā)送給從節(jié)點

  • 4. 主節(jié)點dump log 線程讀取bin-log 的內容時會對主節(jié)點的bin-log加鎖,讀取完成在發(fā)送給從節(jié)點之前釋放鎖

  • 5. 從節(jié)點的IO線程接收主節(jié)點發(fā)送的binlog內容,并將其寫入本地relay log 文件中

  • 6. 主從節(jié)點通過binlog文件+position偏移量定位主從同步的位置,從節(jié)點會保存接收到的position偏移量,如果從節(jié)點發(fā)生宕機重啟,自動從postion位置發(fā)起同步

  • 7. 從節(jié)點的SQL線程復制讀取本地relay log的內容,解析成具體的操作并執(zhí)行,保證主從數(shù)據(jù)一致性

4、主從復制的模式

1)異步模式(默認方式)

  • 1. 可能導致主從不一致(主從延時)

  • 2. 主節(jié)點接收到客戶端提交的事務之后直接提交事務并返回給客戶端

  • 3. 如果主節(jié)點事務提交之后,log dump還沒來得及寫入就宕機就會導致主從數(shù)據(jù)不一致

  • 4. 不用關心主從的同步操作,性能最好

2)全同步模式

  • 1. 可靠更高,但是會影響主庫相應時間

  • 2. 主節(jié)點接收到客戶端提交的事務之后,必須等待binlog 發(fā)送給從庫,并且所有從庫全部執(zhí)行完事務之后才返回給客戶端

3)半同步模式

  • 1.  增加一部分可靠性,增加主庫一部分相應時間

  • 2.  主節(jié)點接收到客戶端提交的事務之后,等待binlog發(fā)送給至少一個從庫并且成功保存到本地relay log中,此時主庫提交事務并返回給客戶端

4)server-id的配置和server-uuid

  • 1. server-id用于標識數(shù)據(jù)庫實例,防止在鏈式主從、多主多從拓撲中導致SQL語句的無限循環(huán)

  • 2. server-id默認值為0,對于主機來說依然會記錄二進制日志,但是會拒絕所有的從機連接。

  • 2. server-id = 0 對于從機來說會拒絕連接其他實例

  • 3. server-id是一個全局變量,修改之hi偶必須重啟服務

  • 4. 主庫和從庫的server-id重復時

    • 默認replicate-same-server-id = 0,從庫會跳過所有主從同步的數(shù)據(jù),導致主從數(shù)據(jù)不一致

    • replicate-same-server-id = 1,可能導致無線循環(huán)執(zhí)行sql

  • 兩個從庫(B、C)server-id重復會導致主從連接異常,時斷時連

    • 主庫(A)發(fā)現(xiàn)相同的server-id會斷開之前的連接,重新注冊新的連接

    • B、C從庫的連接會周而復始的重連

  • MySQL服務會自動創(chuàng)建并生成server-uuid配置

    • 當主從同步時如果主從實例的server-uuid相同會報錯退出,不過我們可以通過設置replicate-same-server-id=1來避免報錯(不推薦)

5、讀寫分離

1)基于代碼實現(xiàn),減少硬件開支

2)基于中間代理實現(xiàn)

3)主從延時

  • 從庫性能比主庫差

  • 大量查詢導致從庫壓力大,消耗大量CPU資源,影響同步速度:一主多從

  • 大事務執(zhí)行:事務執(zhí)行完之后才會寫入binlog,從庫讀取延時

  • 主庫ddl(alter、drop、create)

十九、死鎖

1、產(chǎn)生的四個必要條件

  • 1. 互斥條件

  • 2. 請求與保持條件:一次性分配全部資源,否則一個都不分配

  • 3. 非剝奪條件:當進程獲得一部分資源等待其他資源的時候釋放占有的資源

  • 4. 循環(huán)等待條件:

    理解:一個資源只能被一個進程占用,進程獲取資源資源還能申請新的資源,并且已經(jīng)獲得的資源不能被剝奪,同時多個進程相互等待其他進程被占用的資源

2、解除死鎖

  • 1. 終止進程(全部干掉)

  • 2. 逐個種植(殺一個看一下有沒有解除)

二十、Mysql 優(yōu)化大分頁查詢 limit 100000 (offset),10 (page_sie)

1、原因

mysql查詢分頁數(shù)據(jù)時不是直接跳過offset(100000),而是取offset + page_size  = 100000 + 10 = 100010條數(shù)據(jù),然后放棄其掉前面的100000條數(shù)據(jù),所以效率地下

2、優(yōu)化方案

  • 延時關聯(lián):使用覆蓋索引

  • 主鍵閾值法:主鍵是自增的情況下,通過條件推算出符合條件的主鍵最大值&最小值(使用覆蓋索引)

  • 記錄上一頁的結果位置,避免使用 OFFSET

二十一、redis 緩存和 mysql 數(shù)據(jù)一致性

方式:

1、先更新redis 再更新數(shù)據(jù)庫

場景:update set value = 10 where value = 9

1) redis更新成功:redis value = 10

2)數(shù)據(jù)庫更新失?。簃ysql value = 9

3)數(shù)據(jù)不一致

2、先更新數(shù)據(jù)庫,再更新redis

場景: A進程update set value = 10 where value = 9 ;B進程 update set value = 11 where value = 9;

1)A 進程先更新數(shù)據(jù)庫,還未寫入緩存:mysql value = 10 ;redis value = 9

2)B 進程更新數(shù)據(jù)庫并且提交事務,寫入緩存:mysql value = 11;redis value = 11;

3)A 進程處理完請求提交事務,寫入緩存:redis value = 10;

4)最終 mysql value = 11; redis value = 10

3、先刪除緩存再更新數(shù)據(jù)庫

場景:A進程update set value = 10 where value = 9 ;B進程查詢value;

1)A 進程先刪除緩存 還沒來得及修改數(shù)據(jù)或者事務未提交

2)B 進程開始查詢,沒有命中緩存,所以查庫并寫入緩存 redis value = 9

3)A 進程更新數(shù)據(jù)庫完成 mysql value = 10

4)最終 mysql value = 10;redis value = 9

解決方案:

1、延時雙刪除

場景:A進程update set value = 10 where value = 9 ;B進程查詢value;

1)A 進程先刪除緩存 還沒來得及修改數(shù)據(jù)或者事務未提交

2)B 進程開始查詢,沒有命中緩存,所以查庫并寫入緩存 redis value = 9

3)A 進程更新數(shù)據(jù)庫完成 mysql value = 10

4)A 進程估算延時時間,sleep之后再次刪除緩存

5)最終mysql value = 10;redis value 為空(下次查詢直接查庫)

6)延時的原因時防止B進程在A進程更新完之后B進程還沒來得及寫入緩存

2、請求串行化

1)創(chuàng)建兩個隊列 :更新隊列和查詢隊列

2)當緩存不存在需要查庫的時候將key存入更新隊列

3)如果查詢未完成之前有新的請求進來,并且發(fā)現(xiàn)更新隊列中還存在key則將key放入查詢隊列,則等待;不存在則重復第二步

4)如果查詢的數(shù)據(jù)發(fā)現(xiàn)查詢隊列已經(jīng)存在則不需要再次寫入隊列

5)數(shù)據(jù)更新完成之后rpop更新隊列,同時rpop查詢隊列,釋放查詢請求

6)查詢請求可以使用while + sleep  查詢緩存并且設置最大延遲時間,還沒有完成則返回空

二十二、redis 中的 connect 和 pconnect

1、connect             :腳本結束之后釋放連接

1. close :釋放連接

2、pconnect(長連接) :腳本結束連接不釋放,連接保持在php-fpm進程中,生命周期隨著php-fpm進程的生命周期

  • 1. close不釋放連接

    • 只是當前php-cgi進程中不能再次請求redis

    • 當前php-cgi中的后續(xù)連接仍然可以復用,直到php-fpm結束生命周期

  • 2. 減少建立redis連接的消耗

  • 3. 減少一個php-fpm多次建立連接

  • 4. 消耗更多的內存,并且連接數(shù)持續(xù)增加

  • 5. 同一個php-fpm的woker子進程(php-cgi)的上一個請求可能會影響到下一個請求

3、pconnect 的連接復用問題

  • 變量A select db 1 ;變量B select db 2;會影響到變量A的db

  • 解決:每一個db創(chuàng)建一個連接實例

二十三、redis zset 有序集合使用 skiplist 的原理

1、基本概念

1. skiplist是一個隨機的數(shù)據(jù),以有序的方式在層次化的鏈表中保存元素(只能用于元素有序的情況)

2. skiplist實在有序鏈表和多層鏈表的基礎上演變的

3. 允許重復值,所以對比檢查除了要對比key 還要對比value

4. 每個節(jié)點都帶有一個高度為1的后退指針,用于表頭方向到表尾方向的迭代

5. 時間復雜度O(logn)、空間復雜度O(n)

2、跳躍表和平衡樹的對比

1)范圍查詢效率

  • 跳躍表范圍查詢效率更高,因為找到最小值之后只需要對第一層的鏈表進行遍歷直到小于最大值即可

  • 平衡樹范圍查詢找到最小值之后還要進行中序遍歷找到其他不超過最大值的節(jié)點

2)內存占用

  • skiplist 每個節(jié)點的指針數(shù)量為1/(1-p)

  • 平衡樹的每個節(jié)點指針數(shù)都為2

3)插入和刪除操作

  • skiplist只需要修改相鄰節(jié)點的指針

  • 平衡樹變更會引起子樹的調整

二十四、redis 的過期刪除和淘汰機制

1、常規(guī)過期刪除策略

1)定時刪除

  • 通過定時器在過期的時候立即刪除

  • 內存釋放及時但是消耗更多的CPU,大并發(fā)的時候需要消耗CPU資源影響處理請求的速度

  • 內存友好,CPU不友好

2)惰性刪除

  • 放任鍵過期不管,到下次需要去取出的時候檢查是否過期并刪除

  • 可能存在大量過期鍵,且不會使用,導致內存溢出

  • 內存不友好,CPU友好

3)定期刪除

  • 每隔一段時間檢查,刪除過期的鍵

  • 刪除多少和檢查多少有算法決定

2、redis采用的 惰性刪除 + 定期刪除

  • 周期性隨機測試一些設置了過期時間的鍵進行檢查,到期則刪除

  • 每次清理的時間不超過CPU的25%,達到時間則退出檢查

  • 定期沒有刪除到的鍵,且以后不會使用的鍵還是會存在內存中,所以需要配合淘汰策略

3、淘汰策略(內存不足以寫入新數(shù)據(jù)的時候執(zhí)行)

  • volatile-lru     :設置了過期時間且最近使用越少越優(yōu)先淘汰

  • volatile-ttl     :設置了過期時間且過期時間越早越優(yōu)先淘汰

  • volatile-random    :設置了過期時間中隨機刪除

  • allkeys-lru        :所有鍵中過期時間越早越優(yōu)先淘汰

  • allkeys-random    :所有鍵中過期隨機淘汰

  • no-enviction        :不允許淘汰,內存不足報錯

二十五、redis 常見問題及解決方案

1、緩存雪崩:同一時間大量緩存失效,導致請求直接查詢數(shù)據(jù)庫,數(shù)據(jù)庫內存和CPU壓力增加甚至宕機

解決:

  • 熱點數(shù)據(jù)永不過期或者分布到不同實例,降低單機故障問題

  • 緩存時間添加隨機數(shù),防止大量緩存同時失效

  • 做二級緩存或者雙緩存,A為原始緩存 短時效,B為備份緩存 ,長期有效。更新時候雙寫緩存

2、緩存穿透:緩存和數(shù)據(jù)庫都沒有數(shù)據(jù),大量請求下,所有請求直接擊穿到數(shù)據(jù)庫,導致宕機。

解決:

  • 布隆過濾器:長度為m的位向量或者位列表組成(僅包含0或1位值的列表)

    • 使用多個不用的hash函數(shù),產(chǎn)生多個索引值,填充對應多個位置的值為1

    • 布隆過濾器可以檢查值是 “可能在集合中” 還是 “絕對不在集合中”

    • 可能誤判但是基礎過濾效率高

    • 極端情況,當布隆過濾器沒有空閑位置的時候每次查詢返回true

  • 空緩存(短時效)

  • 業(yè)務層參數(shù)過濾

3、緩存擊穿:數(shù)據(jù)庫中有數(shù)據(jù),但是緩存突然失效之后發(fā)生大量請求導致數(shù)據(jù)庫壓力增加甚至打垮宕機

解決:

  • 熱點數(shù)據(jù)永不過期

  • 互斥鎖:獲取鎖之后不管成功還是失敗都要釋放鎖

二十六、php-fpm 詳解及生命周期

1、基礎知識

1)CGI協(xié)議

  • 動態(tài)語言的代碼文件需要通過對應的解析器才能被服務器識別

  • CGI協(xié)議就是用來使服務器和解釋器相互通信的

  • 服務器解析PHP文件需要PHP解釋器加上對應的CGI協(xié)議

2)CGI程序 = php-cgi

  • php-cgi就是一個遵守CGI協(xié)議的CGI程序

  • 同時也就是PHP解釋器

  • 標準的CGI每個請求都會解析php.ini,初始化執(zhí)行環(huán)境等,降低性能

  • 每次修改配置之后需要重新php-cgi才能讓php.ini生效

  • 不能動態(tài)worker調度,只能一開始指定數(shù)量的worker

3)FastCGI協(xié)議

  • 和CGI一樣也是一個協(xié)議/規(guī)范,不過是再CGI的基礎上優(yōu)化,效率更高

  • 用來提高CGI程序性能的

  • 實現(xiàn)了CGI進程的管理

4)FastCGI程序  = php-fpm

  • php-fpm就是一個遵守FastCGI協(xié)議的FastCGI程序

  • FastCGI程序對CGI程序的管理模式

    • 啟動一個master進程,解析配置文件,初始化環(huán)境

    • 啟動多個worker子進程

    • 接受到請求之后,傳遞給woker進程去執(zhí)行

  • 解決修改php.ini之后平滑重啟問題

    • process_control_timeout:子進程接受主進程復用信號的超時時間(在規(guī)定時間內處理完請求,完成不了就不管了)

    • 設定php-fpm留給fastcgi進程響應重啟信號的時間

    • process_control_timeout = 0,也就是不生效,無法保證平滑重啟

    • process_control_timeout設置過大可能導致系統(tǒng)請求堵塞

    • process_control_timeout =10的情況下,如果代碼邏輯需要11s,重啟舊可能導致代碼執(zhí)行部分退出

    • 建議值:request_terminate_timeout

  • 重啟類型

    • 優(yōu)雅重啟

    • 強制重啟

2、php-fpm生命周期:待更新

二十七、Nginx 和 php 之間的通信

1、通信方式:fastcgi_pass

1)tcp socket

  • 跨服務器,nginx和php不在一個機器時,只能用這個方式

  • 面向連接的協(xié)議,更好的保證通信的正確性和完整性

2)unix socket

  • 不需要網(wǎng)絡協(xié)議棧、打包拆包等

  • 減少tcp 開銷,效率比tcp socket 更高

  • 高并發(fā)時候不穩(wěn)定,連接數(shù)暴增產(chǎn)生大量的長時緩存,大數(shù)據(jù)包可能直接返回異常

到此,關于“PHP面試題基礎知識有哪些”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關知識,請繼續(xù)關注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

網(wǎng)站欄目:PHP面試題基礎知識有哪些
瀏覽路徑:http://bm7419.com/article0/geepoo.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供建站公司、商城網(wǎng)站、網(wǎng)站設計、云服務器電子商務、小程序開發(fā)

廣告

聲明:本網(wǎng)站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

小程序開發(fā)