溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

PHP面試題基礎(chǔ)知識(shí)有哪些

發(fā)布時(shí)間:2022-03-03 13:37:29 來(lái)源:億速云 閱讀:126 作者:iii 欄目:編程語(yǔ)言

這篇文章主要介紹“PHP面試題基礎(chǔ)知識(shí)有哪些”,在日常操作中,相信很多人在PHP面試題基礎(chǔ)知識(shí)有哪些問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”PHP面試題基礎(chǔ)知識(shí)有哪些”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

PHP面試題基礎(chǔ)知識(shí)有哪些

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

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

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

  • hash表保存當(dāng)前循環(huán)的指針,所以foreach 比f(wàn)or更快

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

2、如何保證有序性

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

  • 2. 用于存儲(chǔ)元素在實(shí)際存儲(chǔ)數(shù)組中的下標(biāo)

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

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

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

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

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

4、基礎(chǔ)知識(shí)

  • 鏈表:隊(duì)列、棧、雙向鏈表、

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

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


二、冒泡排序的時(shí)間復(fù)雜度和空間復(fù)雜度

1、代碼實(shí)現(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、計(jì)算原理

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

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

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

平均時(shí)間復(fù)雜度:O(n^2) ;

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

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

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

3、時(shí)間復(fù)雜度和空間復(fù)雜度

時(shí)間復(fù)雜度:全程為漸進(jìn)時(shí)間復(fù)雜度,估算對(duì)處理器的使用效率(描述算法的效率趨勢(shì),并不是指算法具體使用的時(shí)間,因?yàn)椴煌瑱C(jī)器的性能不一致,只是一種效率計(jì)算的通用方法)

表示方法:大O符號(hào)表示法

復(fù)雜度量級(jí):

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

  • 線性階O(n)

  • 平方階O(n2)

  • 立方階O(n3)

  • K次方階O(n^k)

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

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

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

時(shí)間復(fù)制類型:

  • 最好時(shí)間復(fù)雜度

  • 最壞時(shí)間復(fù)雜度

  • 平均時(shí)間復(fù)雜度

  • 均攤時(shí)間復(fù)雜度

空間復(fù)雜度:全程漸進(jìn)空間復(fù)雜度,估算對(duì)計(jì)算機(jī)內(nèi)存的使用程度(描述算法占用的存儲(chǔ)空間的趨勢(shì),不是實(shí)際占用空間,同上)


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

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

記憶套路:

首字:應(yīng)表會(huì)傳(物鏈網(wǎng))

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

前四個(gè)正向:應(yīng)表 - 會(huì)傳

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

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

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

2、TCP

  • 面向連接,所以只能一對(duì)一

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

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

  • 全雙工通信

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

  • 無(wú)連接,支持一對(duì)一,一對(duì)多,多對(duì)多

  • 面向保溫傳輸

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


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

1、三次握手:

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

    作用:

    客戶端:無(wú)

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

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

    作用:

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

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

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

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

2、四次揮手

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

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

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

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

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

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

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

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

注意:

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

  • 最后需要等待2MSL是因?yàn)榫W(wǎng)絡(luò)是不可靠的,如果服務(wù)端沒(méi)有收到最后一次ACK,服務(wù)端會(huì)重新放FIN包然后等客戶端再次發(fā)送ACK包然后關(guān)閉(所以客戶端最后發(fā)送ACK之后不能立即關(guān)閉連接)


六、HTTP 狀態(tài)碼

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

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

  • - 2xx:成功

  • - 3xx:重定向

  • - 4xx:客戶端錯(cuò)誤

  • - 5xx:服務(wù)端錯(cuò)誤

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

  • 200:請(qǐng)求成功

  • 301:永久重定向

  • 302:臨時(shí)移動(dòng)

  • 400 bad request:客戶端請(qǐng)求語(yǔ)法錯(cuò)誤

  • 401 unauthorized:客戶端沒(méi)有權(quán)限

  • 403 forbidden:服務(wù)器拒絕客戶端請(qǐng)求

  • 404 not found:客戶端請(qǐng)求資源不存在

  • 500 Internal Server Eerro:服務(wù)器內(nèi)部錯(cuò)誤

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

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

  • 504 Gateway timeout:網(wǎng)關(guān)超時(shí)

3、502 的原因及解決方法

原因:nginx將請(qǐng)求提交給網(wǎng)關(guān)(php-fpm)處理異常導(dǎo)致

1)fastcgi 緩沖區(qū)設(shè)置過(guò)小

fastcgi_buffers 8 16k;

fastcgi_buffer_size 32k;

2)php-cgi的進(jìn)程數(shù)設(shè)置過(guò)少

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

調(diào)整參數(shù)最大子進(jìn)程數(shù):max_children

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

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

參數(shù)指明每個(gè)children最多能處理的請(qǐng)求數(shù)量,到達(dá)最大值之后會(huì)重啟children。

設(shè)置過(guò)小可能導(dǎo)致頻繁重啟children:

php將請(qǐng)求輪詢給每個(gè)children,在大流量的場(chǎng)景下,每一個(gè)children 到達(dá)最大值的時(shí)間差不多,如果設(shè)置過(guò)小可能多個(gè)children 在同一時(shí)間關(guān)閉,nginx無(wú)法將請(qǐng)求轉(zhuǎn)發(fā)給php-fpm,cpu降低,負(fù)載變高。

設(shè)置過(guò)大可能導(dǎo)致內(nèi)存泄露

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

fastcgi_connect_timeout

fastcgi_send_timeout

fastcgi_read_timeout

5)fastcgi執(zhí)行時(shí)間

max_execution_time


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

1、端口:http 80; https :443

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

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

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

八、redis 分布式鎖及問(wèn)題

1、實(shí)現(xiàn):

加鎖:setnx

解鎖:del

鎖超時(shí):expire

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

  • 1)setnx 和expire非原子性問(wèn)題(加鎖之后還沒(méi)來(lái)得及設(shè)置超時(shí)就掛了)

    解決方案:

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

  • 2)超時(shí)誤刪其他進(jìn)程鎖。(A進(jìn)程執(zhí)行超時(shí),導(dǎo)致鎖釋放,這時(shí)候B進(jìn)程獲取鎖開(kāi)始處理請(qǐng)求,這時(shí)候A進(jìn)程處理完成,會(huì)誤刪B進(jìn)程的鎖)

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

  • 3)并發(fā)場(chǎng)景,A進(jìn)程執(zhí)行超時(shí)導(dǎo)致鎖釋放,這時(shí)候B進(jìn)程獲取到鎖。

    解決方案:開(kāi)啟守護(hù)進(jìn)程,給當(dāng)前進(jìn)程要過(guò)期的鎖延時(shí)。

  • 4)單點(diǎn)實(shí)例安全問(wèn)題

    單機(jī)宕機(jī)之后導(dǎo)致所有客戶端無(wú)法獲取鎖

    解決:

    主從復(fù)制,因?yàn)槭钱惒酵瓿傻乃詿o(wú)法完全實(shí)現(xiàn)解決


九、redis 的數(shù)據(jù)類型及應(yīng)用場(chǎng)景

1、string :

普通的key/value存儲(chǔ)

2、hash:

hashmap:鍵值隊(duì)集合,存儲(chǔ)對(duì)象信息

3、list:

雙向鏈表:消息隊(duì)列

4、set:

value永遠(yuǎn)為null的hashMap:無(wú)序集合且不重復(fù):計(jì)算交集、并集、差集、去重值

5、zset:

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


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

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

1)fork一個(gè)子進(jìn)程,將快照內(nèi)容寫入臨時(shí)RDB文件中(dump.rdb),當(dāng)子進(jìn)程寫完快照內(nèi)容之后新的文件替換老的文件

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

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

4)持久化之前宕機(jī)可能會(huì)導(dǎo)致數(shù)據(jù)丟失

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

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

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

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

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

  • appendfsync always    :每次變動(dòng)都會(huì)執(zhí)行一次

  • appendfsync no          :不處理

4)AOF文件太大之后會(huì)進(jìn)行重寫:壓縮AOF文件大小

  • fork一個(gè)子進(jìn)程,將redis內(nèi)地?cái)?shù)據(jù)對(duì)象的最新?tīng)顟B(tài)寫入AOF臨時(shí)文件(類似rdb快照)

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

  • 子進(jìn)程完成重寫之后會(huì)將內(nèi)存中的新變動(dòng)同步追加到AOF的臨時(shí)文件中

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


十一、秒殺設(shè)計(jì)流程及難點(diǎn)

1、靜態(tài)緩存

2、nginx 負(fù)載均衡  

三種方式:DNS輪詢、IP負(fù)債均衡、CDN

3、限流機(jī)制

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

4、分布式鎖

方式:

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

  • 釋放鎖超時(shí) (開(kāi)啟守護(hù)進(jìn)程自動(dòng)續(xù)時(shí)間)

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

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

方式:

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

  • 緩存雪崩:緩存設(shè)置隨機(jī)過(guò)期時(shí)間,防止同一時(shí)間過(guò)期

6、庫(kù)存及訂單

  • 扣庫(kù)存

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

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

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

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

  • 創(chuàng)建訂單

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

    • 消費(fèi)驗(yàn)證記錄狀態(tài),防止重復(fù)消費(fèi)

  • 回倉(cāng)

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

十二、防 sql 注入

1、過(guò)濾特殊字符

2、過(guò)濾數(shù)據(jù)庫(kù)關(guān)鍵字

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

4、使用預(yù)編譯模式,綁定變量

十三、事務(wù)隔離級(jí)別

1、標(biāo)準(zhǔn)的sql隔離級(jí)別實(shí)現(xiàn)原理

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

    • 事務(wù)對(duì)當(dāng)前被讀取的數(shù)據(jù)不加鎖

    • 在更新的瞬間加行級(jí)共享鎖到事務(wù)結(jié)束釋放

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

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

    • 在更新的瞬間加行級(jí)排他鎖到事務(wù)結(jié)束釋放

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

    • 事務(wù)對(duì)當(dāng)前讀到的數(shù)據(jù)從事務(wù)一開(kāi)始就加一個(gè)行級(jí)共享鎖

    • 在更新的瞬間加行級(jí)排他鎖到事務(wù)結(jié)束釋放

    • 其他事務(wù)再事務(wù)過(guò)程中可能會(huì)新增數(shù)據(jù)導(dǎo)致幻讀

  • 串行化

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

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

2、innodb的事務(wù)隔離級(jí)別及實(shí)現(xiàn)原理(?。『蜕厦娴牟灰粯?,區(qū)分理解一個(gè)是隔離級(jí)別 一個(gè)是!!事務(wù)??!隔離級(jí)別)

1)基本概念

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

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

    • 寫操作才會(huì)加鎖

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

    • 一個(gè)事務(wù)啟動(dòng)的時(shí)候只能看到所有已經(jīng)提交的事務(wù)結(jié)果

  • 當(dāng)前讀:讀取的是最新版本

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

  • 間隙鎖:間隙鎖會(huì)鎖住一個(gè)范圍內(nèi)的索引

    • update id between 10 and 20

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

    • 只有可重復(fù)讀隔離級(jí)別才有間隙鎖

  • next-key lock:

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

    • 前開(kāi)后閉

    • 阻止幻讀

2)事務(wù)隔離級(jí)別

  • 未提交讀

    • 事務(wù)對(duì)當(dāng)前讀取的數(shù)據(jù)不加鎖,都是當(dāng)前讀

    • 在更新的瞬間加行級(jí)共享鎖到事務(wù)結(jié)束釋放

  • 提交讀

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

    • 在更新的瞬間加行級(jí)排他鎖到事務(wù)結(jié)束釋放

  • 可重復(fù)讀

    • 主從復(fù)制的情況下 ,如果沒(méi)有間隙鎖,master庫(kù)的A、B進(jìn)程

    • A進(jìn)程 delete id < 6 ;然后還沒(méi)有commit

    • B進(jìn)程insert id = 3,commit

    • A進(jìn)程提交commit

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

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

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

    • 間隙鎖解決的是幻讀問(wèn)題

    • MVCC的快照解決的是不可重復(fù)讀問(wèn)題

  • 串行化

    • 事務(wù)讀取數(shù)據(jù)時(shí)加表級(jí),當(dāng)前讀

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


十四、索引原理

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

1、存儲(chǔ)引擎

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

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

2、索引類型

  • hash索引

    • 適合精確查詢且效率高

    • 無(wú)法排序、不適合范圍查詢

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

  • b-tree、b+tree

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

    • b-tree 的內(nèi)部節(jié)點(diǎn)和葉子節(jié)點(diǎn)都存儲(chǔ)key和數(shù)據(jù),查找數(shù)據(jù)不需要找到葉子節(jié)點(diǎn),內(nèi)部節(jié)點(diǎn)可以直接返回?cái)?shù)據(jù)

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

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

  • 聚簇索引和非聚簇索引

    • 聚簇索引  :索引和數(shù)據(jù)存儲(chǔ)在一個(gè)節(jié)點(diǎn)

    • 非聚簇索引:索引和數(shù)據(jù)分開(kāi)存儲(chǔ),通過(guò)索引找到數(shù)據(jù)實(shí)際存儲(chǔ)的地址

    • 概念

    • 詳解:

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

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

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

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

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

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

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


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

1、流程

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

2、水平拆分

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

  • 每個(gè)表的結(jié)構(gòu)相同

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

3、垂直拆分

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

  • 表結(jié)構(gòu)不一樣,分表的同一個(gè)關(guān)聯(lián)行是一條完整的數(shù)據(jù)

  • 擴(kuò)展表,熱點(diǎn)字段和非熱點(diǎn)字段的拆分(列表和詳情的拆分)

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

4、問(wèn)題

  • 跨庫(kù)join問(wèn)題

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

    • 冗余法:常用字段進(jìn)行冗余

    • 組裝法:多次查詢的結(jié)果進(jìn)行組裝

  • 跨節(jié)點(diǎn)的分頁(yè)、排序、函數(shù)問(wèn)題

  • 事務(wù)一致性

  • 全局主鍵id

    • 使用uuid -> 會(huì)降低聚簇索引效率

    • 使用分布式自增id

  • 擴(kuò)容問(wèn)題

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

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

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

    • 從庫(kù)升級(jí)為主庫(kù),數(shù)據(jù)一致,只需要?jiǎng)h除冗余數(shù)據(jù)即可

    • 成倍擴(kuò)容:需要在加一倍從庫(kù)

    • 升級(jí)從庫(kù)

    • 雙寫遷移:


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

1、mysql 構(gòu)成

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

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

2、select 執(zhí)行過(guò)程

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

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

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

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

  • 執(zhí)行器調(diào)用引擎API查詢結(jié)果

  • 返回查詢結(jié)果

3、update執(zhí)行過(guò)程

  • 基礎(chǔ)概念

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

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

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

    • 記錄日志是順序IO

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

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

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

    • redo log是重復(fù)寫,空間固定且會(huì)用完,會(huì)覆蓋老日志

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

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

    • redo log主要是用來(lái)恢復(fù)崩潰,bin log是用來(lái)記錄歸檔的二進(jìn)制日志

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

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

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

    • 臟頁(yè):內(nèi)存中的緩存池更新了,但是沒(méi)有更新磁盤

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

    • redo log 和 binlog

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

    • redo log 刷盤機(jī)制,check point

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

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

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

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

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

    • 引擎層收到請(qǐng)求之后提交commit

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

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

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

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

    • 先redo log 再寫入binlog

      1. redo log 寫完之后,binlog沒(méi)寫完,這時(shí)候宕機(jī)。

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

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

    • 先寫binlog 再寫redo log

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

      2. 重啟之后沒(méi)有redo log ,所以value 還是9

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

  • undo log

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

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


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

作用:

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

2. 主從復(fù)制

格式(二進(jìn)制文件):

1)statement

  • 1. 記錄每次sql語(yǔ)句的原文

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

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

  • 4. RC隔離級(jí)別(讀提交),因?yàn)閎inlog 記錄順序是按照事務(wù)commit 順序記錄的,所以可能導(dǎo)致主從復(fù)制不一致。通過(guò)可重復(fù)讀級(jí)別的間隙鎖的引入,可以解決。

2)row

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

  • 2. 導(dǎo)致binlog日志量很大

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

3)mixed

  • 1. 前兩個(gè)格式的混合版

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

    • 一般的sql語(yǔ)句修改使用statement

    • 修改表結(jié)構(gòu)、函數(shù)、存儲(chǔ)過(guò)程等操作選擇row

    • update 和delete 還是會(huì)記錄全部記錄的變化


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

1、解決的問(wèn)題

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

  • 負(fù)載均衡

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

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

  • 升級(jí)測(cè)試(使用高版本mysql當(dāng)從庫(kù))

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

  • 基于sql語(yǔ)句的復(fù)制

  • 基于行的復(fù)制

  • 混合型復(fù)制

3、原理

1)基礎(chǔ)概念

  • 從庫(kù)生成兩個(gè)線程

    • I/O線程

    • SQL線程

  • 主庫(kù)生成線程

    • log dumo 線程

2)流程(主節(jié)點(diǎn)必須開(kāi)啟bin log功能,)

  • 1. 從節(jié)點(diǎn)開(kāi)啟start slave 命令之后,創(chuàng)建一個(gè)IO進(jìn)程連接到主節(jié)點(diǎn)

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

  • 3. 當(dāng)binlog發(fā)生變化時(shí),主節(jié)點(diǎn)的dump log線程會(huì)讀取bin-log內(nèi)容并發(fā)送給從節(jié)點(diǎn)

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

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

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

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

4、主從復(fù)制的模式

1)異步模式(默認(rèn)方式)

  • 1. 可能導(dǎo)致主從不一致(主從延時(shí))

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

  • 3. 如果主節(jié)點(diǎn)事務(wù)提交之后,log dump還沒(méi)來(lái)得及寫入就宕機(jī)就會(huì)導(dǎo)致主從數(shù)據(jù)不一致

  • 4. 不用關(guān)心主從的同步操作,性能最好

2)全同步模式

  • 1. 可靠更高,但是會(huì)影響主庫(kù)相應(yīng)時(shí)間

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

3)半同步模式

  • 1.  增加一部分可靠性,增加主庫(kù)一部分相應(yīng)時(shí)間

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

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

  • 1. server-id用于標(biāo)識(shí)數(shù)據(jù)庫(kù)實(shí)例,防止在鏈?zhǔn)街鲝?、多主多從拓?fù)渲袑?dǎo)致SQL語(yǔ)句的無(wú)限循環(huán)

  • 2. server-id默認(rèn)值為0,對(duì)于主機(jī)來(lái)說(shuō)依然會(huì)記錄二進(jìn)制日志,但是會(huì)拒絕所有的從機(jī)連接。

  • 2. server-id = 0 對(duì)于從機(jī)來(lái)說(shuō)會(huì)拒絕連接其他實(shí)例

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

  • 4. 主庫(kù)和從庫(kù)的server-id重復(fù)時(shí)

    • 默認(rèn)replicate-same-server-id = 0,從庫(kù)會(huì)跳過(guò)所有主從同步的數(shù)據(jù),導(dǎo)致主從數(shù)據(jù)不一致

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

  • 兩個(gè)從庫(kù)(B、C)server-id重復(fù)會(huì)導(dǎo)致主從連接異常,時(shí)斷時(shí)連

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

    • B、C從庫(kù)的連接會(huì)周而復(fù)始的重連

  • MySQL服務(wù)會(huì)自動(dòng)創(chuàng)建并生成server-uuid配置

    • 當(dāng)主從同步時(shí)如果主從實(shí)例的server-uuid相同會(huì)報(bào)錯(cuò)退出,不過(guò)我們可以通過(guò)設(shè)置replicate-same-server-id=1來(lái)避免報(bào)錯(cuò)(不推薦)

5、讀寫分離

1)基于代碼實(shí)現(xiàn),減少硬件開(kāi)支

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

3)主從延時(shí)

  • 從庫(kù)性能比主庫(kù)差

  • 大量查詢導(dǎo)致從庫(kù)壓力大,消耗大量CPU資源,影響同步速度:一主多從

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

  • 主庫(kù)ddl(alter、drop、create)


十九、死鎖

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

  • 1. 互斥條件

  • 2. 請(qǐng)求與保持條件:一次性分配全部資源,否則一個(gè)都不分配

  • 3. 非剝奪條件:當(dāng)進(jìn)程獲得一部分資源等待其他資源的時(shí)候釋放占有的資源

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

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

2、解除死鎖

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

  • 2. 逐個(gè)種植(殺一個(gè)看一下有沒(méi)有解除)


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

1、原因

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

2、優(yōu)化方案

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

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

  • 記錄上一頁(yè)的結(jié)果位置,避免使用 OFFSET


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

方式:

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

 場(chǎng)景:update set value = 10 where value = 9

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

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

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

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

 場(chǎng)景: A進(jìn)程update set value = 10 where value = 9 ;B進(jìn)程 update set value = 11 where value = 9;

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

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

 3)A 進(jìn)程處理完請(qǐng)求提交事務(wù),寫入緩存:redis value = 10;

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

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

場(chǎng)景:A進(jìn)程update set value = 10 where value = 9 ;B進(jìn)程查詢value;

1)A 進(jìn)程先刪除緩存 還沒(méi)來(lái)得及修改數(shù)據(jù)或者事務(wù)未提交

2)B 進(jìn)程開(kāi)始查詢,沒(méi)有命中緩存,所以查庫(kù)并寫入緩存 redis value = 9

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

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

解決方案:

1、延時(shí)雙刪除

場(chǎng)景:A進(jìn)程update set value = 10 where value = 9 ;B進(jìn)程查詢value;

1)A 進(jìn)程先刪除緩存 還沒(méi)來(lái)得及修改數(shù)據(jù)或者事務(wù)未提交

2)B 進(jìn)程開(kāi)始查詢,沒(méi)有命中緩存,所以查庫(kù)并寫入緩存 redis value = 9

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

4)A 進(jìn)程估算延時(shí)時(shí)間,sleep之后再次刪除緩存

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

6)延時(shí)的原因時(shí)防止B進(jìn)程在A進(jìn)程更新完之后B進(jìn)程還沒(méi)來(lái)得及寫入緩存

2、請(qǐng)求串行化

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

2)當(dāng)緩存不存在需要查庫(kù)的時(shí)候?qū)ey存入更新隊(duì)列

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

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

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

6)查詢請(qǐng)求可以使用while + sleep  查詢緩存并且設(shè)置最大延遲時(shí)間,還沒(méi)有完成則返回空


二十二、redis 中的 connect 和 pconnect

1、connect             :腳本結(jié)束之后釋放連接

1. close :釋放連接

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

  • 1. close不釋放連接

    • 只是當(dāng)前php-cgi進(jìn)程中不能再次請(qǐng)求redis

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

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

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

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

  • 5. 同一個(gè)php-fpm的woker子進(jìn)程(php-cgi)的上一個(gè)請(qǐng)求可能會(huì)影響到下一個(gè)請(qǐng)求

3、pconnect 的連接復(fù)用問(wèn)題

  • 變量A select db 1 ;變量B select db 2;會(huì)影響到變量A的db

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


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

1、基本概念

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

2. skiplist實(shí)在有序鏈表和多層鏈表的基礎(chǔ)上演變的

3. 允許重復(fù)值,所以對(duì)比檢查除了要對(duì)比key 還要對(duì)比value

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

5. 時(shí)間復(fù)雜度O(logn)、空間復(fù)雜度O(n)

2、跳躍表和平衡樹(shù)的對(duì)比

1)范圍查詢效率

  • 跳躍表范圍查詢效率更高,因?yàn)檎业阶钚≈抵笾恍枰獙?duì)第一層的鏈表進(jìn)行遍歷直到小于最大值即可

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

2)內(nèi)存占用

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

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

3)插入和刪除操作

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

  • 平衡樹(shù)變更會(huì)引起子樹(shù)的調(diào)整


二十四、redis 的過(guò)期刪除和淘汰機(jī)制

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

1)定時(shí)刪除

  • 通過(guò)定時(shí)器在過(guò)期的時(shí)候立即刪除

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

  • 內(nèi)存友好,CPU不友好

2)惰性刪除

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

  • 可能存在大量過(guò)期鍵,且不會(huì)使用,導(dǎo)致內(nèi)存溢出

  • 內(nèi)存不友好,CPU友好

3)定期刪除

  • 每隔一段時(shí)間檢查,刪除過(guò)期的鍵

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

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

  • 周期性隨機(jī)測(cè)試一些設(shè)置了過(guò)期時(shí)間的鍵進(jìn)行檢查,到期則刪除

  • 每次清理的時(shí)間不超過(guò)CPU的25%,達(dá)到時(shí)間則退出檢查

  • 定期沒(méi)有刪除到的鍵,且以后不會(huì)使用的鍵還是會(huì)存在內(nèi)存中,所以需要配合淘汰策略

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

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

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

  • volatile-random    :設(shè)置了過(guò)期時(shí)間中隨機(jī)刪除

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

  • allkeys-random    :所有鍵中過(guò)期隨機(jī)淘汰

  • no-enviction        :不允許淘汰,內(nèi)存不足報(bào)錯(cuò)


二十五、redis 常見(jiàn)問(wèn)題及解決方案

1、緩存雪崩:同一時(shí)間大量緩存失效,導(dǎo)致請(qǐng)求直接查詢數(shù)據(jù)庫(kù),數(shù)據(jù)庫(kù)內(nèi)存和CPU壓力增加甚至宕機(jī)

解決:

  • 熱點(diǎn)數(shù)據(jù)永不過(guò)期或者分布到不同實(shí)例,降低單機(jī)故障問(wèn)題

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

  • 做二級(jí)緩存或者雙緩存,A為原始緩存 短時(shí)效,B為備份緩存 ,長(zhǎng)期有效。更新時(shí)候雙寫緩存

2、緩存穿透:緩存和數(shù)據(jù)庫(kù)都沒(méi)有數(shù)據(jù),大量請(qǐng)求下,所有請(qǐng)求直接擊穿到數(shù)據(jù)庫(kù),導(dǎo)致宕機(jī)。

解決:

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

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

    • 布隆過(guò)濾器可以檢查值是 “可能在集合中” 還是 “絕對(duì)不在集合中”

    • 可能誤判但是基礎(chǔ)過(guò)濾效率高

    • 極端情況,當(dāng)布隆過(guò)濾器沒(méi)有空閑位置的時(shí)候每次查詢返回true

  • 空緩存(短時(shí)效)

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

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

解決:

  • 熱點(diǎn)數(shù)據(jù)永不過(guò)期

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


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

1、基礎(chǔ)知識(shí)

1)CGI協(xié)議

  • 動(dòng)態(tài)語(yǔ)言的代碼文件需要通過(guò)對(duì)應(yīng)的解析器才能被服務(wù)器識(shí)別

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

  • 服務(wù)器解析PHP文件需要PHP解釋器加上對(duì)應(yīng)的CGI協(xié)議

2)CGI程序 = php-cgi

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

  • 同時(shí)也就是PHP解釋器

  • 標(biāo)準(zhǔn)的CGI每個(gè)請(qǐng)求都會(huì)解析php.ini,初始化執(zhí)行環(huán)境等,降低性能

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

  • 不能動(dòng)態(tài)worker調(diào)度,只能一開(kāi)始指定數(shù)量的worker

3)FastCGI協(xié)議

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

  • 用來(lái)提高CGI程序性能的

  • 實(shí)現(xiàn)了CGI進(jìn)程的管理

4)FastCGI程序  = php-fpm

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

  • FastCGI程序?qū)GI程序的管理模式

    • 啟動(dòng)一個(gè)master進(jìn)程,解析配置文件,初始化環(huán)境

    • 啟動(dòng)多個(gè)worker子進(jìn)程

    • 接受到請(qǐng)求之后,傳遞給woker進(jìn)程去執(zhí)行

  • 解決修改php.ini之后平滑重啟問(wèn)題

    • process_control_timeout:子進(jìn)程接受主進(jìn)程復(fù)用信號(hào)的超時(shí)時(shí)間(在規(guī)定時(shí)間內(nèi)處理完請(qǐng)求,完成不了就不管了)

    • 設(shè)定php-fpm留給fastcgi進(jìn)程響應(yīng)重啟信號(hào)的時(shí)間

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

    • process_control_timeout設(shè)置過(guò)大可能導(dǎo)致系統(tǒng)請(qǐng)求堵塞

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

    • 建議值:request_terminate_timeout

  • 重啟類型

    • 優(yōu)雅重啟

    • 強(qiáng)制重啟

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


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

1、通信方式:fastcgi_pass

1)tcp socket

  • 跨服務(wù)器,nginx和php不在一個(gè)機(jī)器時(shí),只能用這個(gè)方式

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

2)unix socket

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

  • 減少tcp 開(kāi)銷,效率比tcp socket 更高

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

到此,關(guān)于“PHP面試題基礎(chǔ)知識(shí)有哪些”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

php
AI