日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
分享2022年最新的28道PHP面試題(附答案)

本篇文章給大家整理分享28道php面試題(附答案分享),帶你梳理基礎(chǔ)知識,有一定的參考價(jià)值,有需要的朋友可以參考一下,希望對大家有所幫助。

過完年之后打算尋找新的工作機(jī)會(huì),發(fā)現(xiàn)之前自己對于很多基礎(chǔ)的面試?yán)斫夂蛯W(xué)習(xí)不夠深刻,為了鼓勵(lì)自己持續(xù)前進(jìn)所以最近開始在論壇和搜索引擎上開始學(xué)習(xí)和總結(jié)相關(guān)知識,其中有一些題目時(shí)論壇里面一些前輩分享過的題目或者答案,還有一部分時(shí)自己最近面試遇到的問題,基于自己的理解和前輩們的分享歸檔了一部分,所以分享出來,希望對其他的小伙伴們也有幫助,同時(shí)也希望能收到大佬們對于理解有誤的地方的指導(dǎo),最近一段時(shí)間會(huì)持續(xù)更新

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

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

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

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

4、基礎(chǔ)知識

  • 鏈表:隊(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)篩選出來不用繼續(xù)比較了),哪個(gè)元素更大,就換順序,從而冒泡出第二大的元素

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

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

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

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

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

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

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

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

復(fù)雜度量級:

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

  • 線性階O(n)

  • 平方階O(n2)

  • 立方階O(n3)

  • K次方階O(n^k)

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

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

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

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

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

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

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

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

空間復(fù)雜度:全程漸進(jìn)空間復(fù)雜度,估算對計(jì)算機(jī)內(nèi)存的使用程度(描述算法占用的存儲(chǔ)空間的趨勢,不是實(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

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

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

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

  • 全雙工通信

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

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

  • 面向保溫傳輸

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

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

1、三次握手:

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

    作用:

    客戶端:無

    服務(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ù)端我沒有數(shù)據(jù)發(fā)送了(但是還能接收數(shù)據(jù))

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

    作用:告訴客戶端收到請求了,可能服務(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之后如果沒有收到回復(fù),證明服務(wù)端已經(jīng)關(guān)閉了,這時(shí)候客戶端也關(guān)閉連接。

注意:

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

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

六、HTTP 狀態(tài)碼

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

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

  • - 2xx:成功

  • - 3xx:重定向

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

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

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

  • 200:請求成功

  • 301:永久重定向

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

  • 400 bad request:客戶端請求語法錯(cuò)誤

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

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

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

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

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

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

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

3、502 的原因及解決方法

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

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

fastcgi_buffers 8 16k;

fastcgi_buffer_size 32k;

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

查看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最多能處理的請求數(shù)量,到達(dá)最大值之后會(huì)重啟children。

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

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

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

4)php執(zhí)行時(shí)間超過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無狀態(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 分布式鎖及問題

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

加鎖:setnx

解鎖:del

鎖超時(shí):expire

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

  • 1)setnx 和expire非原子性問題(加鎖之后還沒來得及設(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)程獲取鎖開始處理請求,這時(shí)候A進(jìn)程處理完成,會(huì)誤刪B進(jìn)程的鎖)

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

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

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

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

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

    解決:

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

九、redis 為什么是單線程?為什么快?

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

1、string :

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

2、hash:

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

3、list:

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

4、set:

value永遠(yuǎn)為null的hashMap:無序集合且不重復(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ù)庫只包含一個(gè)備份文件

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

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

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

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

2)持久化的文件會(huì)越來越大,存在大量多余的日志(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ù)對象的最新狀態(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í) (開啟守護(hù)進(jìn)程自動(dòng)續(xù)時(shí)間)

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

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

方式:

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

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

6、庫存及訂單

  • 扣庫存

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

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

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

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

  • 創(chuàng)建訂單

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

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

  • 回倉

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

十三、防 sql 注入

1、過濾特殊字符

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

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

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

十四、事務(wù)隔離級別

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

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

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

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

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

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

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

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

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

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

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

  • 串行化

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

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

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

1)基本概念

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

    • 讓數(shù)據(jù)都讀不會(huì)對數(shù)據(jù)加鎖,提高數(shù)據(jù)庫并發(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

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

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

  • next-key lock:

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

    • 前開后閉

    • 阻止幻讀

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

  • 未提交讀

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

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

  • 提交讀

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

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

  • 可重復(fù)讀

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

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

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

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

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

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

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

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

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

  • 串行化

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

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

十五、索引原理

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

1、存儲(chǔ)引擎

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

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

2、索引類型

  • hash索引

    • 適合精確查詢且效率高

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

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

  • b-tree、b+tree

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

      • 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)的指針,方便返回查詢遍歷

  • 聚簇索引和非聚簇索引

    • 概念

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

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

    • 詳解:

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

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

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

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

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

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

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

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

1、流程

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

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、問題

  • 跨庫join問題

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

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

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

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

  • 事務(wù)一致性

  • 全局主鍵id

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

    • 使用分布式自增id

  • 擴(kuò)容問題

    • 升級從庫

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

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

    • 雙寫遷移:

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

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

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

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

1、mysql 構(gòu)成

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

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

2、select 執(zhí)行過程

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

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

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

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

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

  • 返回查詢結(jié)果

3、update執(zhí)行過程

  • 基礎(chǔ)概念

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

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

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

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

    • redo log 和 binlog

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

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

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

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

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

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

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

      • 記錄日志是順序IO

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

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

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

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

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

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

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

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

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

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

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

    • 引擎層收到請求之后提交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沒寫完,這時(shí)候宕機(jī)。

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

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

    • 先寫binlog 再寫redo log

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

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

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

  • undo log

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

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

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

作用:

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

2. 主從復(fù)制

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

1)statement

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

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

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

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

2)row

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

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

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

3)mixed

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

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

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

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

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

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

1、解決的問題

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

  • 負(fù)載均衡

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

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

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

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

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

  • 基于行的復(fù)制

  • 混合型復(fù)制

3、原理

1)基礎(chǔ)概念

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

    • I/O線程

    • SQL線程

  • 主庫生成線程

    • log dumo 線程

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

  • 1. 從節(jié)點(diǎn)開啟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ì)對主節(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)通過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還沒來得及寫入就宕機(jī)就會(huì)導(dǎo)致主從數(shù)據(jù)不一致

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

2)全同步模式

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

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

3)半同步模式

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

5、讀寫分離

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

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

3)主從延時(shí)

  • 從庫性能比主庫差

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

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

  • 主庫ddl(alter、drop、create)

二十、死鎖

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

  • 1. 互斥條件

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

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

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

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

2、解除死鎖

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

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

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

1、原因

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

2、優(yōu)化方案

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

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

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

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

方式:

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

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

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

 2)數(shù)據(jù)庫更新失敗:mysql value = 9

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

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

 場景: 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ù)庫,還未寫入緩存:mysql value = 10 ;redis value = 9

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

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

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

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

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

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

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

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

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

解決方案:

1、延時(shí)雙刪除

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

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

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

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

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

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

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

2、請求串行化

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

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

3)如果查詢未完成之前有新的請求進(jìn)來,并且發(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ì)列,釋放查詢請求

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

二十三、redis 中的 connect 和 pconnect

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

1. close :釋放連接

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

  • 1. close不釋放連接

    • 只是當(dāng)前php-cgi進(jìn)程中不能再次請求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è)請求可能會(huì)影響到下一個(gè)請求

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

  • 變量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ù)值,所以對比檢查除了要對比key 還要對比value

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

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

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

1)范圍查詢效率

  • 跳躍表范圍查詢效率更高,因?yàn)檎业阶钚≈抵笾恍枰獙Φ谝粚拥逆湵磉M(jìn)行遍歷直到小于最大值即可

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

2)內(nèi)存占用

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

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

3)插入和刪除操作

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

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

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

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

1)定時(shí)刪除

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

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

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

2)惰性刪除

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

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

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

3)定期刪除

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

解決:

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

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

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

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

解決:

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

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

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

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

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

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

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

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

解決:

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

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

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

1、基礎(chǔ)知識

1)CGI協(xié)議

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

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

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

2)CGI程序 = php-cgi

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

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

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

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

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

3)FastCGI協(xié)議

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

  • 用來提高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)程

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

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

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

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

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

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

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

    • 建議值:request_terminate_timeout

  • 重啟類型

    • 優(yōu)雅重啟

    • 強(qiáng)制重啟

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

PHP-FPM 生命周期:https://www.abelzhou.com/php/php-fpm-lifespan/#

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

1、通信方式:fastcgi_pass

1)tcp socket

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

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

2)unix socket

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

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

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

二十九、web 漏洞及問題

1、sql注入

2、XSS攻擊

推薦閱讀(很詳細(xì)的案例來分析XSS攻擊的不同類型及解決方案):[前端安全系列(一):如何防止XSS攻擊?](https://tech.meituan.com/2018/09/27/fe-security.html)

3、CSRF攻擊:

推薦閱讀 :[前端安全系列(二):如何防止CSRF攻擊?](https://tech.meituan.com/2018/10/11/fe-security-csrf.html)

4、文件上傳漏洞

推薦閱讀 :[淺析文件上傳漏洞](https://xz.aliyun.com/t/7365)

5、跨域問題:

1)jsonp

2)cors

3)nginx代理


標(biāo)題名稱:分享2022年最新的28道PHP面試題(附答案)
鏈接地址:http://m.5511xx.com/article/cojspoo.html