大家好,我是小林。
這次跟大家分享一位同學(xué)面騰訊后端開(kāi)發(fā)的面經(jīng),一步一步深挖計(jì)算機(jī)基礎(chǔ)的內(nèi)容,問(wèn)的問(wèn)題很多,光面試時(shí)常長(zhǎng)達(dá) 1 個(gè)小時(shí)多,再加上寫(xiě)算法 20 分鐘,面試的強(qiáng)度還是挺大的。
雖然面試強(qiáng)度是比較大了一點(diǎn),但是整體面下來(lái),同學(xué)反饋還是很有收獲的,也算是對(duì)自己沒(méi)掌握的內(nèi)容進(jìn)行查漏補(bǔ)缺的過(guò)程。
計(jì)算機(jī)網(wǎng)絡(luò)
網(wǎng)絡(luò)七層模型分別是什么?
為了使得多種設(shè)備能通過(guò)網(wǎng)絡(luò)相互通信,和為了解決各種不同設(shè)備在網(wǎng)絡(luò)互聯(lián)中的兼容性問(wèn)題,國(guó)際標(biāo)準(zhǔn)化組織制定了開(kāi)放式系統(tǒng)互聯(lián)通信參考模型(Open System Interconnection Reference Model),也就是 OSI 網(wǎng)絡(luò)模型,該模型主要有 7 層,分別是應(yīng)用層、表示層、會(huì)話層、傳輸層、網(wǎng)絡(luò)層、數(shù)據(jù)鏈路層以及物理層。
img-
應(yīng)用層:應(yīng)用層最接近終端用戶(hù)。大多數(shù)應(yīng)用程序都位于這一層。我們從后端服務(wù)器請(qǐng)求數(shù)據(jù),無(wú)需了解數(shù)據(jù)傳輸?shù)木唧w細(xì)節(jié)。這一層的協(xié)議包括 HTTP、SMTP、FTP、DNS 等。
-
表示層:這一層處理數(shù)據(jù)編碼、加密和壓縮,為應(yīng)用層準(zhǔn)備數(shù)據(jù)。例如,HTTPS 利用 TLS(Transport Layer Security)實(shí)現(xiàn)客戶(hù)端與服務(wù)器之間的安全通信。
-
會(huì)話層:該層用于打開(kāi)和關(guān)閉兩個(gè)設(shè)備之間的通信。如果數(shù)據(jù)量較大,會(huì)話層就會(huì)設(shè)置檢查點(diǎn),避免從頭開(kāi)始重新發(fā)送。
-
傳輸層:該層處理兩個(gè)設(shè)備之間的端到端的通信。它在發(fā)送方將數(shù)據(jù)分解成段,然后在接收方重新組裝。這一層有流量控制,以防止擁塞。這一層的主要協(xié)議是 TCP 和 UDP。
-
網(wǎng)絡(luò)層:這一層實(shí)現(xiàn)不同網(wǎng)絡(luò)之間的數(shù)據(jù)傳輸。它進(jìn)一步將網(wǎng)段或數(shù)據(jù)報(bào)分解成更小的數(shù)據(jù)包,并使用 IP 地址找到通往最終目的地的最佳路由。
-
數(shù)據(jù)鏈路層:這一層允許在同一網(wǎng)絡(luò)的設(shè)備之間傳輸數(shù)據(jù)。數(shù)據(jù)包被分解成幀,這些幀被限制在局域網(wǎng)內(nèi)。
-
物理層:這一層通過(guò)電纜和交換機(jī)發(fā)送比特流,因此與設(shè)備之間的物理連接密切相關(guān)。與 OSI 模型相比,TCP/IP 模型只有 4 層。在討論網(wǎng)絡(luò)協(xié)議的層次時(shí),必須明確上下文。
TCP和UDP的應(yīng)用場(chǎng)景是哪些?
TCP適用:網(wǎng)頁(yè)、電子郵件、遠(yuǎn)程登錄連接、文件傳輸
UDP適用:語(yǔ)音通話,多播通信,DNS解析
TCP如何實(shí)現(xiàn)可靠傳輸?
面向連接、同步序列號(hào)、校驗(yàn)和、流量控制和擁塞控制。
- 序列號(hào)與確認(rèn)機(jī)制:TCP將每個(gè)數(shù)據(jù)包分配一個(gè)唯一的序列號(hào),并且接收方會(huì)發(fā)送確認(rèn)消息來(lái)確認(rèn)已經(jīng)接收到的數(shù)據(jù)。發(fā)送方會(huì)根據(jù)接收到的確認(rèn)消息判斷是否需要重新發(fā)送丟失的數(shù)據(jù)包。
- 數(shù)據(jù)校驗(yàn)和:TCP使用校驗(yàn)和來(lái)驗(yàn)證數(shù)據(jù)在傳輸過(guò)程中是否發(fā)生了損壞。接收方會(huì)計(jì)算校驗(yàn)和并與發(fā)送方發(fā)送的校驗(yàn)和進(jìn)行比較,如果不一致,則說(shuō)明數(shù)據(jù)包發(fā)生了損壞,需要重新發(fā)送。
- 滑動(dòng)窗口機(jī)制:TCP使用滑動(dòng)窗口來(lái)控制發(fā)送方發(fā)送數(shù)據(jù)的速度和接收方接收數(shù)據(jù)的速度,以避免因發(fā)送速度過(guò)快或接收速度過(guò)慢而導(dǎo)致的數(shù)據(jù)丟失或堵塞。
- 重傳機(jī)制:如果發(fā)送方?jīng)]有收到接收方的確認(rèn)消息,或者接收方收到的數(shù)據(jù)包校驗(yàn)和不一致,發(fā)送方會(huì)重新發(fā)送數(shù)據(jù)包,確保數(shù)據(jù)的可靠傳輸。
- 擁塞控制:TCP具有擁塞控制機(jī)制,可以根據(jù)網(wǎng)絡(luò)的擁塞情況來(lái)調(diào)整發(fā)送數(shù)據(jù)的速率,避免網(wǎng)絡(luò)擁塞導(dǎo)致的數(shù)據(jù)丟失和延遲。
第一次握手,客戶(hù)端發(fā)送SYN報(bào)后,服務(wù)端回復(fù)ACK報(bào),那這個(gè)過(guò)程中服務(wù)端內(nèi)部做了哪些工作?
服務(wù)端收到客戶(hù)端發(fā)起的 SYN 請(qǐng)求后,內(nèi)核會(huì)把該連接存儲(chǔ)到半連接隊(duì)列,并向客戶(hù)端響應(yīng) SYN+ACK,接著客戶(hù)端會(huì)返回 ACK,服務(wù)端收到第三次握手的 ACK 后,內(nèi)核會(huì)把連接從半連接隊(duì)列移除,然后創(chuàng)建新的完全的連接,并將其添加到 accept 隊(duì)列,等待進(jìn)程調(diào)用 accept 函數(shù)時(shí)把連接取出來(lái)。
半連接隊(duì)列與全連接隊(duì)列不管是半連接隊(duì)列還是全連接隊(duì)列,都有最大長(zhǎng)度限制,超過(guò)限制時(shí),內(nèi)核會(huì)直接丟棄,或返回 RST 包。
大量SYN包發(fā)送給服務(wù)端服務(wù)端會(huì)發(fā)生什么事情?
有可能會(huì)導(dǎo)致TCP 半連接隊(duì)列打滿(mǎn),這樣當(dāng) TCP 半連接隊(duì)列滿(mǎn)了,后續(xù)再在收到 SYN 報(bào)文就會(huì)丟棄,導(dǎo)致客戶(hù)端無(wú)法和服務(wù)端建立連接。
避免 SYN 攻擊方式,可以有以下四種方法:
- 調(diào)大 netdev_max_backlog;
- 增大 TCP 半連接隊(duì)列;
- 開(kāi)啟 tcp_syncookies;
- 減少 SYN+ACK 重傳次數(shù)
方式一:調(diào)大 netdev_max_backlog
當(dāng)網(wǎng)卡接收數(shù)據(jù)包的速度大于內(nèi)核處理的速度時(shí),會(huì)有一個(gè)隊(duì)列保存這些數(shù)據(jù)包。控制該隊(duì)列的最大值如下參數(shù),默認(rèn)值是 1000,我們要適當(dāng)調(diào)大該參數(shù)的值,比如設(shè)置為 10000:
net.core.netdev_max_backlog=10000
方式二:增大 TCP 半連接隊(duì)列
增大 TCP 半連接隊(duì)列,要同時(shí)增大下面這三個(gè)參數(shù):
- 增大 net.ipv4.tcp_max_syn_backlog
- 增大 listen() 函數(shù)中的 backlog
- 增大 net.core.somaxconn
方式三:開(kāi)啟 net.ipv4.tcp_syncookies
開(kāi)啟 syncookies 功能就可以在不使用 SYN 半連接隊(duì)列的情況下成功建立連接,相當(dāng)于繞過(guò)了 SYN 半連接來(lái)建立連接。
tcp_syncookies 應(yīng)對(duì) SYN 攻擊具體過(guò)程:
-
當(dāng) 「 SYN 隊(duì)列」?jié)M之后,后續(xù)服務(wù)端收到 SYN 包,不會(huì)丟棄,而是根據(jù)算法,計(jì)算出一個(gè)
cookie
值; - 將 cookie 值放到第二次握手報(bào)文的「序列號(hào)」里,然后服務(wù)端回第二次握手給客戶(hù)端;
- 服務(wù)端接收到客戶(hù)端的應(yīng)答報(bào)文時(shí),服務(wù)端會(huì)檢查這個(gè) ACK 包的合法性。如果合法,將該連接對(duì)象放入到「 Accept 隊(duì)列」。
-
最后應(yīng)用程序通過(guò)調(diào)用
accpet()
接口,從「 Accept 隊(duì)列」取出的連接。
可以看到,當(dāng)開(kāi)啟了 tcp_syncookies 了,即使受到 SYN 攻擊而導(dǎo)致 SYN 隊(duì)列滿(mǎn)時(shí),也能保證正常的連接成功建立。
net.ipv4.tcp_syncookies 參數(shù)主要有以下三個(gè)值:
- 0 值,表示關(guān)閉該功能;
- 1 值,表示僅當(dāng) SYN 半連接隊(duì)列放不下時(shí),再啟用它;
- 2 值,表示無(wú)條件開(kāi)啟功能;
那么在應(yīng)對(duì) SYN 攻擊時(shí),只需要設(shè)置為 1 即可。
$echo1>/proc/sys/net/ipv4/tcp_syncookies
方式四:減少 SYN+ACK 重傳次數(shù)
當(dāng)服務(wù)端受到 SYN 攻擊時(shí),就會(huì)有大量處于 SYN_REVC 狀態(tài)的 TCP 連接,處于這個(gè)狀態(tài)的 TCP 會(huì)重傳 SYN+ACK ,當(dāng)重傳超過(guò)次數(shù)達(dá)到上限后,就會(huì)斷開(kāi)連接。
那么針對(duì) SYN 攻擊的場(chǎng)景,我們可以減少 SYN-ACK 的重傳次數(shù),以加快處于 SYN_REVC 狀態(tài)的 TCP 連接斷開(kāi)。
SYN-ACK 報(bào)文的最大重傳次數(shù)由 tcp_synack_retries
內(nèi)核參數(shù)決定(默認(rèn)值是 5 次),比如將 tcp_synack_retries 減少到 2 次:
$echo2>/proc/sys/net/ipv4/tcp_synack_retries
服務(wù)端默認(rèn)能接受多少個(gè)連接?
TCP 四元組可以唯一的確定一個(gè)連接,四元組包括如下:
- 源地址
- 源端口
- 目的地址
- 目的端口
源地址和目的地址的字段(32 位)是在 IP 頭部中,作用是通過(guò) IP 協(xié)議發(fā)送報(bào)文給對(duì)方主機(jī)。
源端口和目的端口的字段(16 位)是在 TCP 頭部中,作用是告訴 TCP 協(xié)議應(yīng)該把報(bào)文發(fā)給哪個(gè)進(jìn)程。
有一個(gè) IP 的服務(wù)端監(jiān)聽(tīng)了一個(gè)端口,它的 TCP 的最大連接數(shù)是多少?
服務(wù)端通常固定在某個(gè)本地端口上監(jiān)聽(tīng),等待客戶(hù)端的連接請(qǐng)求。
因此,客戶(hù)端 IP 和端口是可變的,其理論值計(jì)算公式如下:
img
對(duì) IPv4,客戶(hù)端的 IP 數(shù)最多為 2
的 32
次方,客戶(hù)端的端口數(shù)最多為 2
的 16
次方,也就是服務(wù)端單機(jī)最大 TCP 連接數(shù),約為 2
的 48
次方。
當(dāng)然,服務(wù)端最大并發(fā) TCP 連接數(shù)遠(yuǎn)不能達(dá)到理論上限,會(huì)受以下因素影響:
-
文件描述符限制
,每個(gè) TCP 連接都是一個(gè)文件,如果文件描述符被占滿(mǎn)了,會(huì)發(fā)生 Too many open files。Linux 對(duì)可打開(kāi)的文件描述符的數(shù)量分別作了三個(gè)方面的限制:
-
系統(tǒng)級(jí):當(dāng)前系統(tǒng)可打開(kāi)的最大數(shù)量,通過(guò)
cat /proc/sys/fs/file-max
查看; -
用戶(hù)級(jí):指定用戶(hù)可打開(kāi)的最大數(shù)量,通過(guò)
cat /etc/security/limits.conf
查看; -
進(jìn)程級(jí):?jiǎn)蝹€(gè)進(jìn)程可打開(kāi)的最大數(shù)量,通過(guò)
cat /proc/sys/fs/nr_open
查看;
-
系統(tǒng)級(jí):當(dāng)前系統(tǒng)可打開(kāi)的最大數(shù)量,通過(guò)
-
內(nèi)存限制,每個(gè) TCP 連接都要占用一定內(nèi)存,操作系統(tǒng)的內(nèi)存是有限的,如果內(nèi)存資源被占滿(mǎn)后,會(huì)發(fā)生 OOM。
從輸入url到頁(yè)面顯示發(fā)生了哪些事情?
圖片- 解析URL:分析 URL 所需要使用的傳輸協(xié)議和請(qǐng)求的資源路徑。如果輸入的 URL 中的協(xié)議或者主機(jī)名不合法,將會(huì)把地址欄中輸入的內(nèi)容傳遞給搜索引擎。如果沒(méi)有問(wèn)題,瀏覽器會(huì)檢查 URL 中是否出現(xiàn)了非法字符,則對(duì)非法字符進(jìn)行轉(zhuǎn)義后在進(jìn)行下一過(guò)程。
- 緩存判斷:瀏覽器會(huì)判斷所請(qǐng)求的資源是否在緩存里,如果請(qǐng)求的資源在緩存里且沒(méi)有失效,那么就直接使用,否則向服務(wù)器發(fā)起新的請(qǐng)求。
- DNS解析:如果資源不在本地緩存,首先需要進(jìn)行DNS解析。瀏覽器會(huì)向本地DNS服務(wù)器發(fā)送域名解析請(qǐng)求,本地DNS服務(wù)器會(huì)逐級(jí)查詢(xún),最終找到對(duì)應(yīng)的IP地址。
- 獲取MAC地址:當(dāng)瀏覽器得到 IP 地址后,數(shù)據(jù)傳輸還需要知道目的主機(jī) MAC 地址,因?yàn)閼?yīng)用層下發(fā)數(shù)據(jù)給傳輸層,TCP 協(xié)議會(huì)指定源端口號(hào)和目的端口號(hào),然后下發(fā)給網(wǎng)絡(luò)層。網(wǎng)絡(luò)層會(huì)將本機(jī)地址作為源地址,獲取的 IP 地址作為目的地址。然后將下發(fā)給數(shù)據(jù)鏈路層,數(shù)據(jù)鏈路層的發(fā)送需要加入通信雙方的 MAC 地址,本機(jī)的 MAC 地址作為源 MAC 地址,目的 MAC 地址需要分情況處理。通過(guò)將 IP 地址與本機(jī)的子網(wǎng)掩碼相結(jié)合,可以判斷是否與請(qǐng)求主機(jī)在同一個(gè)子網(wǎng)里,如果在同一個(gè)子網(wǎng)里,可以使用 APR 協(xié)議獲取到目的主機(jī)的 MAC 地址,如果不在一個(gè)子網(wǎng)里,那么請(qǐng)求應(yīng)該轉(zhuǎn)發(fā)給網(wǎng)關(guān),由它代為轉(zhuǎn)發(fā),此時(shí)同樣可以通過(guò) ARP 協(xié)議來(lái)獲取網(wǎng)關(guān)的 MAC 地址,此時(shí)目的主機(jī)的 MAC 地址應(yīng)該為網(wǎng)關(guān)的地址。
- 建立TCP連接:主機(jī)將使用目標(biāo) IP地址和目標(biāo)MAC地址發(fā)送一個(gè)TCP SYN包,請(qǐng)求建立一個(gè)TCP連接,然后交給路由器轉(zhuǎn)發(fā),等路由器轉(zhuǎn)到目標(biāo)服務(wù)器后,服務(wù)器回復(fù)一個(gè)SYN-ACK包,確認(rèn)連接請(qǐng)求。然后,主機(jī)發(fā)送一個(gè)ACK包,確認(rèn)已收到服務(wù)器的確認(rèn),然后 TCP 連接建立完成。
- HTTPS 的 TLS 四次握手:如果使用的是 HTTPS 協(xié)議,在通信前還存在 TLS 的四次握手。
- 發(fā)送HTTP請(qǐng)求:連接建立后,瀏覽器會(huì)向服務(wù)器發(fā)送HTTP請(qǐng)求。請(qǐng)求中包含了用戶(hù)需要獲取的資源的信息,例如網(wǎng)頁(yè)的URL、請(qǐng)求方法(GET、POST等)等。
- 服務(wù)器處理請(qǐng)求并返回響應(yīng):服務(wù)器收到請(qǐng)求后,會(huì)根據(jù)請(qǐng)求的內(nèi)容進(jìn)行相應(yīng)的處理。例如,如果是請(qǐng)求網(wǎng)頁(yè),服務(wù)器會(huì)讀取相應(yīng)的網(wǎng)頁(yè)文件,并生成HTTP響應(yīng)。
拿到IP地址還要去獲取MAC地址,TCP連接需要用到MAC地址嗎?
也需要的,客戶(hù)端發(fā)送第一個(gè) syn 報(bào)文的時(shí)候,也需要在數(shù)據(jù)鏈路層組裝 mac 地址的。
DNS解析流程?
域名解析的工作流程- 客戶(hù)端首先會(huì)發(fā)出一個(gè) DNS 請(qǐng)求,問(wèn) www.server.com 的 IP 是啥,并發(fā)給本地 DNS 服務(wù)器(也就是客戶(hù)端的 TCP/IP 設(shè)置中填寫(xiě)的 DNS 服務(wù)器地址)。
- 本地域名服務(wù)器收到客戶(hù)端的請(qǐng)求后,如果緩存里的表格能找到 www.server.com,則它直接返回 IP 地址。如果沒(méi)有,本地 DNS 會(huì)去問(wèn)它的根域名服務(wù)器:“老大, 能告訴我 www.server.com 的 IP 地址嗎?” 根域名服務(wù)器是最高層次的,它不直接用于域名解析,但能指明一條道路。
- 根 DNS 收到來(lái)自本地 DNS 的請(qǐng)求后,發(fā)現(xiàn)后置是 .com,說(shuō):“www.server.com 這個(gè)域名歸 .com 區(qū)域管理”,我給你 .com 頂級(jí)域名服務(wù)器地址給你,你去問(wèn)問(wèn)它吧。”
- 本地 DNS 收到頂級(jí)域名服務(wù)器的地址后,發(fā)起請(qǐng)求問(wèn)“老二, 你能告訴我 www.server.com 的 IP 地址嗎?”
- 頂級(jí)域名服務(wù)器說(shuō):“我給你負(fù)責(zé) www.server.com 區(qū)域的權(quán)威 DNS 服務(wù)器的地址,你去問(wèn)它應(yīng)該能問(wèn)到”。
- 本地 DNS 于是轉(zhuǎn)向問(wèn)權(quán)威 DNS 服務(wù)器:“老三,www.server.com對(duì)應(yīng)的IP是啥呀?” server.com 的權(quán)威 DNS 服務(wù)器,它是域名解析結(jié)果的原出處。為啥叫權(quán)威呢?就是我的域名我做主。
- 權(quán)威 DNS 服務(wù)器查詢(xún)后將對(duì)應(yīng)的 IP 地址 X.X.X.X 告訴本地 DNS。
- 本地 DNS 再將 IP 地址返回客戶(hù)端,客戶(hù)端和目標(biāo)建立連接。
至此,我們完成了 DNS 的解析過(guò)程。現(xiàn)在總結(jié)一下,整個(gè)過(guò)程我畫(huà)成了一個(gè)圖。
網(wǎng)頁(yè)非常慢轉(zhuǎn)圈圈的時(shí)候,要定位問(wèn)題需要從哪些角度?
最直接的辦法就是抓包,排查的思路大概有:
-
先確定是服務(wù)端的問(wèn)題,還是客戶(hù)端的問(wèn)題。先確認(rèn)瀏覽器是否可以訪問(wèn)其他網(wǎng)站,如果不可以,說(shuō)明客戶(hù)端網(wǎng)絡(luò)自身的問(wèn)題,然后檢查客戶(hù)端網(wǎng)絡(luò)配置(連接wifi正不正常,有沒(méi)有插網(wǎng)線);如果可以正常其他網(wǎng)頁(yè),說(shuō)明客戶(hù)端網(wǎng)絡(luò)是可以正常上網(wǎng)的。
-
如果客戶(hù)端網(wǎng)絡(luò)沒(méi)問(wèn)題,就抓包確認(rèn) DNS 是否解析出了 IP 地址,如果沒(méi)有解析出來(lái),說(shuō)明域名寫(xiě)錯(cuò)了,如果解析出了 IP 地址,抓包確認(rèn)有沒(méi)有和服務(wù)端建立三次握手,如果能成功建立三次握手,并且發(fā)出了 HTTP 請(qǐng)求,但是就是沒(méi)有顯示頁(yè)面,可以查看服務(wù)端返回的響應(yīng)碼:
- 如果是404錯(cuò)誤碼,檢查輸入的url是否正確;
- 如果是500,說(shuō)明服務(wù)器此時(shí)有問(wèn)題;
- 如果是200,F(xiàn)12看看前端代碼有問(wèn)題導(dǎo)致瀏覽器沒(méi)有渲染出頁(yè)面。
-
如果客戶(hù)端網(wǎng)絡(luò)是正常的,但是訪問(wèn)速度很慢,導(dǎo)致很久才顯示出來(lái)。這時(shí)候要看客戶(hù)端的網(wǎng)口流量是否太大的了,導(dǎo)致tcp發(fā)生丟包之類(lèi)的問(wèn)題。
總之就是一層一層有沒(méi)有插網(wǎng)線,網(wǎng)絡(luò)配置是否正確、DNS有沒(méi)有解析出 IP地址、TCP有沒(méi)有三次握手、HTTP返回的響應(yīng)碼是什么。
推薦閱讀:網(wǎng)站顯示不出來(lái),怎么排查?
HTTP默認(rèn)的端口是什么?
http 是 80,https 默認(rèn)是 443。
端口通不通用什么命令?
第一種方式:telnet:telnet命令用于建立與遠(yuǎn)程主機(jī)的Telnet連接,并可以使用telnet命令測(cè)試特定端口的可訪問(wèn)性。
-
示例:
telnet IP地址 端口號(hào)
用于測(cè)試指定IP地址上的指定端口是否可訪問(wèn)。如果能夠建立連接,則表示端口通暢;如果連接失敗或超時(shí),則表示端口不可訪問(wèn)。
第二種方式:nc:nc命令(也稱(chēng)為netcat)是一個(gè)網(wǎng)絡(luò)工具,可以用于創(chuàng)建各種類(lèi)型的網(wǎng)絡(luò)連接,包括測(cè)試端口的可訪問(wèn)性。
-
示例:
nc -zv IP地址 端口號(hào)
用于測(cè)試指定IP地址上的指定端口是否可訪問(wèn)。如果能夠成功連接,則表示端口通暢;如果連接失敗或拒絕,則表示端口不可訪問(wèn)。
linux端口狀態(tài)查詢(xún)有哪些命令?
-
netstat -tunlp
用于顯示所有TCP和UDP端口的監(jiān)聽(tīng)狀態(tài)。 -
lsof -i :端口號(hào)
用于顯示指定端口的相關(guān)信息。
ping命令走的是什么協(xié)議?
ICMP 協(xié)議。
ICMP 回送消息錯(cuò)誤返回碼認(rèn)識(shí)哪些?
五大類(lèi) HTTP 狀態(tài)碼-
1xx
類(lèi)狀態(tài)碼屬于提示信息,是協(xié)議處理中的一種中間狀態(tài),實(shí)際用到的比較少。 -
2xx
類(lèi)狀態(tài)碼表示服務(wù)器成功處理了客戶(hù)端的請(qǐng)求,也是我們最愿意看到的狀態(tài)。 -
3xx
類(lèi)狀態(tài)碼表示客戶(hù)端請(qǐng)求的資源發(fā)生了變動(dòng),需要客戶(hù)端用新的 URL 重新發(fā)送請(qǐng)求獲取資源,也就是重定向。 -
4xx
類(lèi)狀態(tài)碼表示客戶(hù)端發(fā)送的報(bào)文有誤,服務(wù)器無(wú)法處理,也就是錯(cuò)誤碼的含義。 -
5xx
類(lèi)狀態(tài)碼表示客戶(hù)端請(qǐng)求報(bào)文正確,但是服務(wù)器處理時(shí)內(nèi)部發(fā)生了錯(cuò)誤,屬于服務(wù)器端的錯(cuò)誤碼。
403代表什么含義?
「403 Forbidden」表示服務(wù)器禁止訪問(wèn)資源,并不是客戶(hù)端的請(qǐng)求出錯(cuò)。
常見(jiàn)的情況包括:
- 客戶(hù)端嘗試訪問(wèn)需要身份驗(yàn)證的資源,但未提供有效的憑據(jù)。
- 客戶(hù)端嘗試訪問(wèn)受限制的目錄或文件。
- 客戶(hù)端的IP地址被服務(wù)器所禁止訪問(wèn)。
重定向的作用?
重定向狀態(tài)碼如下,301 和 302 都會(huì)在響應(yīng)頭里使用字段 Location
,指明后續(xù)要跳轉(zhuǎn)的 URL,瀏覽器會(huì)自動(dòng)重定向新的 URL。
- 「301 Moved Permanently」表示永久重定向,說(shuō)明請(qǐng)求的資源已經(jīng)不存在了,需改用新的 URL 再次訪問(wèn)。
- 「302 Found」表示臨時(shí)重定向,說(shuō)明請(qǐng)求的資源還在,但暫時(shí)需要用另一個(gè) URL 來(lái)訪問(wèn)。
重定向是指將一個(gè)URL請(qǐng)求轉(zhuǎn)發(fā)到另一個(gè)URL的過(guò)程。重定向的作用包括:
-
更改URL:通過(guò)重定向,可以更改URL,使其更易于記憶、更友好或更有意義。例如,將長(zhǎng)而復(fù)雜的URL重定向到簡(jiǎn)潔的、易于理解的URL。
-
網(wǎng)站遷移:當(dāng)網(wǎng)站進(jìn)行重構(gòu)、更換域名或更改URL結(jié)構(gòu)時(shí),通過(guò)重定向舊的URL到新的URL,可以讓用戶(hù)和搜索引擎正確地訪問(wèn)和索引新的內(nèi)容。
反向代理,那正向代理是什么?
圖片來(lái)源:ByteByteGo- 正向代理是位于用戶(hù)設(shè)備和互聯(lián)網(wǎng)之間的服務(wù)器。它代理的是客戶(hù)端,是站在用戶(hù)一方的。其真實(shí)客戶(hù)端對(duì)于服務(wù)器不可見(jiàn)。
- 反向代理是一種服務(wù)器,它接受客戶(hù)端的請(qǐng)求,將請(qǐng)求轉(zhuǎn)發(fā)給網(wǎng)絡(luò)服務(wù)器,然后將結(jié)果返回給客戶(hù)端,就像代理服務(wù)器處理了請(qǐng)求一樣。
推薦閱讀:面試官:你背一下負(fù)載均衡算法?
TCP的擁塞控制介紹一下?
擁塞控制是用于在網(wǎng)絡(luò)擁塞時(shí)減少網(wǎng)絡(luò)流量和避免網(wǎng)絡(luò)崩潰。
TCP的擁塞控制機(jī)制主要包括以下幾個(gè)方面:
-
慢啟動(dòng):當(dāng)建立連接或恢復(fù)丟失的數(shù)據(jù)包時(shí),TCP會(huì)以指數(shù)增加的方式逐漸增加發(fā)送窗口的大小,從而逐漸增加發(fā)送的數(shù)據(jù)量。
-
擁塞避免:在慢啟動(dòng)階段,當(dāng)檢測(cè)到網(wǎng)絡(luò)擁塞時(shí),TCP會(huì)切換到擁塞避免模式。擁塞避免使用線性增加的方式逐漸增加發(fā)送窗口的大小,以降低網(wǎng)絡(luò)擁塞的風(fēng)險(xiǎn)。
-
快速重傳:當(dāng)發(fā)送方連續(xù)接收到同一個(gè)確認(rèn)號(hào)的重復(fù)確認(rèn)時(shí),它會(huì)認(rèn)為該數(shù)據(jù)包已經(jīng)丟失,并立即重新發(fā)送丟失的數(shù)據(jù)包,而不等待超時(shí)重傳。
-
快速恢復(fù):在快速重傳后,發(fā)送方會(huì)將擁塞窗口減半,并使用擁塞避免模式逐漸增加發(fā)送窗口的大小,以便恢復(fù)正常的發(fā)送速率。
通過(guò)這些機(jī)制,TCP能夠根據(jù)網(wǎng)絡(luò)的擁塞情況動(dòng)態(tài)調(diào)整發(fā)送窗口的大小和發(fā)送速率,以避免網(wǎng)絡(luò)擁塞并保證數(shù)據(jù)的可靠傳輸。擁塞控制是TCP協(xié)議的重要特性,它在保持網(wǎng)絡(luò)穩(wěn)定和高效運(yùn)行方面起著重要作用。
HTTP層請(qǐng)求的類(lèi)型有哪些?
-
GET:用于請(qǐng)求獲取指定資源,通常用于獲取數(shù)據(jù)。
-
POST:用于向服務(wù)器提交數(shù)據(jù),通常用于提交表單數(shù)據(jù)或進(jìn)行資源的創(chuàng)建。
-
PUT:用于向服務(wù)器更新指定資源,通常用于更新已存在的資源。
-
DELETE:用于請(qǐng)求服務(wù)器刪除指定資源。
-
HEAD:類(lèi)似于GET請(qǐng)求,但只返回資源的頭部信息,用于獲取資源的元數(shù)據(jù)而不獲取實(shí)際內(nèi)容。
GET和POST的使用場(chǎng)景,有哪些區(qū)別?
根據(jù) RFC 規(guī)范,GET 的語(yǔ)義是從服務(wù)器獲取指定的資源,這個(gè)資源可以是靜態(tài)的文本、頁(yè)面、圖片視頻等。GET 請(qǐng)求的參數(shù)位置一般是寫(xiě)在 URL 中,URL 規(guī)定只能支持 ASCII,所以 GET 請(qǐng)求的參數(shù)只允許 ASCII 字符 ,而且瀏覽器會(huì)對(duì) URL 的長(zhǎng)度有限制(HTTP協(xié)議本身對(duì) URL長(zhǎng)度并沒(méi)有做任何規(guī)定)。
比如,你打開(kāi)我的文章,瀏覽器就會(huì)發(fā)送 GET 請(qǐng)求給服務(wù)器,服務(wù)器就會(huì)返回文章的所有文字及資源。
GET 請(qǐng)求根據(jù) RFC 規(guī)范,POST 的語(yǔ)義是根據(jù)請(qǐng)求負(fù)荷(報(bào)文body)對(duì)指定的資源做出處理,具體的處理方式視資源類(lèi)型而不同。POST 請(qǐng)求攜帶數(shù)據(jù)的位置一般是寫(xiě)在報(bào)文 body 中,body 中的數(shù)據(jù)可以是任意格式的數(shù)據(jù),只要客戶(hù)端與服務(wù)端協(xié)商好即可,而且瀏覽器不會(huì)對(duì) body 大小做限制。
比如,你在我文章底部,敲入了留言后點(diǎn)擊「提交」(暗示你們留言),瀏覽器就會(huì)執(zhí)行一次 POST 請(qǐng)求,把你的留言文字放進(jìn)了報(bào)文 body 里,然后拼接好 POST 請(qǐng)求頭,通過(guò) TCP 協(xié)議發(fā)送給服務(wù)器。
POST 請(qǐng)求如果從 RFC 規(guī)范定義的語(yǔ)義來(lái)看:
- GET 方法就是安全且冪等的,因?yàn)樗恰钢蛔x」操作,無(wú)論操作多少次,服務(wù)器上的數(shù)據(jù)都是安全的,且每次的結(jié)果都是相同的。所以,可以對(duì) GET 請(qǐng)求的數(shù)據(jù)做緩存,這個(gè)緩存可以做到瀏覽器本身上(徹底避免瀏覽器發(fā)請(qǐng)求),也可以做到代理上(如nginx),而且在瀏覽器中 GET 請(qǐng)求可以保存為書(shū)簽。
- POST 因?yàn)槭恰感略龌蛱峤粩?shù)據(jù)」的操作,會(huì)修改服務(wù)器上的資源,所以是不安全的,且多次提交數(shù)據(jù)就會(huì)創(chuàng)建多個(gè)資源,所以不是冪等的。所以,瀏覽器一般不會(huì)緩存 POST 請(qǐng)求,也不能把 POST 請(qǐng)求保存為書(shū)簽。
但是實(shí)際過(guò)程中,開(kāi)發(fā)者不一定會(huì)按照 RFC 規(guī)范定義的語(yǔ)義來(lái)實(shí)現(xiàn) GET 和 POST 方法。比如:
- 可以用 GET 方法實(shí)現(xiàn)新增或刪除數(shù)據(jù)的請(qǐng)求,這樣實(shí)現(xiàn)的 GET 方法自然就不是安全和冪等。
- 可以用 POST 方法實(shí)現(xiàn)查詢(xún)數(shù)據(jù)的請(qǐng)求,這樣實(shí)現(xiàn)的 POST 方法自然就是安全和冪等。
HTTP的長(zhǎng)連接是什么?
HTTP 協(xié)議采用的是「請(qǐng)求-應(yīng)答」的模式,也就是客戶(hù)端發(fā)起了請(qǐng)求,服務(wù)端才會(huì)返回響應(yīng),一來(lái)一回這樣子。
請(qǐng)求-應(yīng)答由于 HTTP 是基于 TCP 傳輸協(xié)議實(shí)現(xiàn)的,客戶(hù)端與服務(wù)端要進(jìn)行 HTTP 通信前,需要先建立 TCP 連接,然后客戶(hù)端發(fā)送 HTTP 請(qǐng)求,服務(wù)端收到后就返回響應(yīng),至此「請(qǐng)求-應(yīng)答」的模式就完成了,隨后就會(huì)釋放 TCP 連接。
一個(gè) HTTP 請(qǐng)求如果每次請(qǐng)求都要經(jīng)歷這樣的過(guò)程:建立 TCP -> 請(qǐng)求資源 -> 響應(yīng)資源 -> 釋放連接,那么此方式就是 HTTP 短連接,如下圖:
HTTP 短連接這樣實(shí)在太累人了,一次連接只能請(qǐng)求一次資源。
能不能在第一個(gè) HTTP 請(qǐng)求完后,先不斷開(kāi) TCP 連接,讓后續(xù)的 HTTP 請(qǐng)求繼續(xù)使用此連接?
當(dāng)然可以,HTTP 的 Keep-Alive 就是實(shí)現(xiàn)了這個(gè)功能,可以使用同一個(gè) TCP 連接來(lái)發(fā)送和接收多個(gè) HTTP 請(qǐng)求/應(yīng)答,避免了連接建立和釋放的開(kāi)銷(xiāo),這個(gè)方法稱(chēng)為 HTTP 長(zhǎng)連接。
HTTP 長(zhǎng)連接HTTP 長(zhǎng)連接的特點(diǎn)是,只要任意一端沒(méi)有明確提出斷開(kāi)連接,則保持 TCP 連接狀態(tài)。
HTTP長(zhǎng)連接與WebSocket有什么區(qū)別?
- 全雙工和半雙工:TCP 協(xié)議本身是全雙工的,但我們最常用的 HTTP/1.1,雖然是基于 TCP 的協(xié)議,但它是半雙工的,對(duì)于大部分需要服務(wù)器主動(dòng)推送數(shù)據(jù)到客戶(hù)端的場(chǎng)景,都不太友好,因此我們需要使用支持全雙工的 WebSocket 協(xié)議。
- 應(yīng)用場(chǎng)景區(qū)別:在 HTTP/1.1 里,只要客戶(hù)端不問(wèn),服務(wù)端就不答。基于這樣的特點(diǎn),對(duì)于登錄頁(yè)面這樣的簡(jiǎn)單場(chǎng)景,可以使用定時(shí)輪詢(xún)或者長(zhǎng)輪詢(xún)的方式實(shí)現(xiàn)服務(wù)器推送(comet)的效果。對(duì)于客戶(hù)端和服務(wù)端之間需要頻繁交互的復(fù)雜場(chǎng)景,比如網(wǎng)頁(yè)游戲,都可以考慮使用 WebSocket 協(xié)議。
操作系統(tǒng)
進(jìn)程跟線程的區(qū)別?
- 本質(zhì)區(qū)別:進(jìn)程是操作系統(tǒng)資源分配的基本單位,而線程是任務(wù)調(diào)度和執(zhí)行的基本單位
- 在開(kāi)銷(xiāo)方面:每個(gè)進(jìn)程都有獨(dú)立的代碼和數(shù)據(jù)空間(程序上下文),程序之間的切換會(huì)有較大的開(kāi)銷(xiāo);線程可以看做輕量級(jí)的進(jìn)程,同一類(lèi)線程共享代碼和數(shù)據(jù)空間,每個(gè)線程都有自己獨(dú)立的運(yùn)行棧和程序計(jì)數(shù)器(PC),線程之間切換的開(kāi)銷(xiāo)小
- 所處環(huán)境:在操作系統(tǒng)中能同時(shí)運(yùn)行多個(gè)進(jìn)程(程序);而在同一個(gè)進(jìn)程(程序)中有多個(gè)線程同時(shí)執(zhí)行(通過(guò)CPU調(diào)度,在每個(gè)時(shí)間片中只有一個(gè)線程執(zhí)行)
- 內(nèi)存分配方面:系統(tǒng)在運(yùn)行的時(shí)候會(huì)為每個(gè)進(jìn)程分配不同的內(nèi)存空間;而對(duì)線程而言,除了CPU外,系統(tǒng)不會(huì)為線程分配內(nèi)存(線程所使用的資源來(lái)自其所屬進(jìn)程的資源),線程組之間只能共享資源
- 包含關(guān)系:沒(méi)有線程的進(jìn)程可以看做是單線程的,如果一個(gè)進(jìn)程內(nèi)有多個(gè)線程,則執(zhí)行過(guò)程不是一條線的,而是多條線(線程)共同完成的;線程是進(jìn)程的一部分,所以線程也被稱(chēng)為輕權(quán)進(jìn)程或者輕量級(jí)進(jìn)程
舉個(gè)例子:進(jìn)程=火車(chē),線程=車(chē)廂
- 線程在進(jìn)程下行進(jìn)(單純的車(chē)廂無(wú)法運(yùn)行)
- 一個(gè)進(jìn)程可以包含多個(gè)線程(一輛火車(chē)可以有多個(gè)車(chē)廂)
- 不同進(jìn)程間數(shù)據(jù)很難共享(一輛火車(chē)上的乘客很難換到另外一輛火車(chē),比如站點(diǎn)換乘)
- 同一進(jìn)程下不同線程間數(shù)據(jù)很易共享(A車(chē)廂換到B車(chē)廂很容易)
- 進(jìn)程要比線程消耗更多的計(jì)算機(jī)資源(采用多列火車(chē)相比多個(gè)車(chē)廂更耗資源)
- 進(jìn)程間不會(huì)相互影響,一個(gè)線程掛掉將導(dǎo)致整個(gè)進(jìn)程掛掉(一列火車(chē)不會(huì)影響到另外一列火車(chē),但是如果一列火車(chē)上中間的一節(jié)車(chē)廂著火了,將影響到所有車(chē)廂)
多線程是不是越多越好,太多會(huì)有什么問(wèn)題?
多線程不一定越多越好,過(guò)多的線程可能會(huì)導(dǎo)致一些問(wèn)題。
- 切換開(kāi)銷(xiāo):線程的創(chuàng)建和切換會(huì)消耗系統(tǒng)資源,包括內(nèi)存和CPU。如果創(chuàng)建太多線程,會(huì)占用大量的系統(tǒng)資源,導(dǎo)致系統(tǒng)負(fù)載過(guò)高,某個(gè)線程崩潰后,可能會(huì)導(dǎo)致進(jìn)程崩潰。
- 死鎖的問(wèn)題:過(guò)多的線程可能會(huì)導(dǎo)致競(jìng)爭(zhēng)條件和死鎖。競(jìng)爭(zhēng)條件指的是多個(gè)線程同時(shí)訪問(wèn)和修改共享資源,如果沒(méi)有合適的同步機(jī)制,可能會(huì)導(dǎo)致數(shù)據(jù)不一致或錯(cuò)誤的結(jié)果。而死鎖則是指多個(gè)線程相互等待對(duì)方釋放資源,導(dǎo)致程序無(wú)法繼續(xù)執(zhí)行。
進(jìn)程調(diào)度算法有哪些?
01 先來(lái)先服務(wù)調(diào)度算法
最簡(jiǎn)單的一個(gè)調(diào)度算法,就是非搶占式的先來(lái)先服務(wù)(*First Come First Serve, FCFS*)算法了。
FCFS 調(diào)度算法
顧名思義,先來(lái)后到,每次從就緒隊(duì)列選擇最先進(jìn)入隊(duì)列的進(jìn)程,然后一直運(yùn)行,直到進(jìn)程退出或被阻塞,才會(huì)繼續(xù)從隊(duì)列中選擇第一個(gè)進(jìn)程接著運(yùn)行。
這似乎很公平,但是當(dāng)一個(gè)長(zhǎng)作業(yè)先運(yùn)行了,那么后面的短作業(yè)等待的時(shí)間就會(huì)很長(zhǎng),不利于短作業(yè)。
FCFS 對(duì)長(zhǎng)作業(yè)有利,適用于 CPU 繁忙型作業(yè)的系統(tǒng),而不適用于 I/O 繁忙型作業(yè)的系統(tǒng)。
02 最短作業(yè)優(yōu)先調(diào)度算法
最短作業(yè)優(yōu)先(*Shortest Job First, SJF*)調(diào)度算法同樣也是顧名思義,它會(huì)優(yōu)先選擇運(yùn)行時(shí)間最短的進(jìn)程來(lái)運(yùn)行,這有助于提高系統(tǒng)的吞吐量。
SJF 調(diào)度算法
這顯然對(duì)長(zhǎng)作業(yè)不利,很容易造成一種極端現(xiàn)象。
比如,一個(gè)長(zhǎng)作業(yè)在就緒隊(duì)列等待運(yùn)行,而這個(gè)就緒隊(duì)列有非常多的短作業(yè),那么就會(huì)使得長(zhǎng)作業(yè)不斷的往后推,周轉(zhuǎn)時(shí)間變長(zhǎng),致使長(zhǎng)作業(yè)長(zhǎng)期不會(huì)被運(yùn)行。
03 高響應(yīng)比優(yōu)先調(diào)度算法
前面的「先來(lái)先服務(wù)調(diào)度算法」和「最短作業(yè)優(yōu)先調(diào)度算法」都沒(méi)有很好的權(quán)衡短作業(yè)和長(zhǎng)作業(yè)。
那么,高響應(yīng)比優(yōu)先 (*Highest Response Ratio Next, HRRN*)調(diào)度算法主要是權(quán)衡了短作業(yè)和長(zhǎng)作業(yè)。
每次進(jìn)行進(jìn)程調(diào)度時(shí),先計(jì)算「響應(yīng)比優(yōu)先級(jí)」,然后把「響應(yīng)比優(yōu)先級(jí)」最高的進(jìn)程投入運(yùn)行,「響應(yīng)比優(yōu)先級(jí)」的計(jì)算公式:
從上面的公式,可以發(fā)現(xiàn):
- 如果兩個(gè)進(jìn)程的「等待時(shí)間」相同時(shí),「要求的服務(wù)時(shí)間」越短,「響應(yīng)比」就越高,這樣短作業(yè)的進(jìn)程容易被選中運(yùn)行;
- 如果兩個(gè)進(jìn)程「要求的服務(wù)時(shí)間」相同時(shí),「等待時(shí)間」越長(zhǎng),「響應(yīng)比」就越高,這就兼顧到了長(zhǎng)作業(yè)進(jìn)程,因?yàn)檫M(jìn)程的響應(yīng)比可以隨時(shí)間等待的增加而提高,當(dāng)其等待時(shí)間足夠長(zhǎng)時(shí),其響應(yīng)比便可以升到很高,從而獲得運(yùn)行的機(jī)會(huì);
04 時(shí)間片輪轉(zhuǎn)調(diào)度算法
最古老、最簡(jiǎn)單、最公平且使用最廣的算法就是時(shí)間片輪轉(zhuǎn)(*Round Robin, RR*)調(diào)度算法。
RR 調(diào)度算法
每個(gè)進(jìn)程被分配一個(gè)時(shí)間段,稱(chēng)為時(shí)間片(*Quantum*),即允許該進(jìn)程在該時(shí)間段中運(yùn)行。
- 如果時(shí)間片用完,進(jìn)程還在運(yùn)行,那么將會(huì)把此進(jìn)程從 CPU 釋放出來(lái),并把 CPU 分配給另外一個(gè)進(jìn)程;
- 如果該進(jìn)程在時(shí)間片結(jié)束前阻塞或結(jié)束,則 CPU 立即進(jìn)行切換;
另外,時(shí)間片的長(zhǎng)度就是一個(gè)很關(guān)鍵的點(diǎn):
- 如果時(shí)間片設(shè)得太短會(huì)導(dǎo)致過(guò)多的進(jìn)程上下文切換,降低了 CPU 效率;
- 如果設(shè)得太長(zhǎng)又可能引起對(duì)短作業(yè)進(jìn)程的響應(yīng)時(shí)間變長(zhǎng)。將
一般來(lái)說(shuō),時(shí)間片設(shè)為 20ms~50ms
通常是一個(gè)比較合理的折中值。
05 最高優(yōu)先級(jí)調(diào)度算法
前面的「時(shí)間片輪轉(zhuǎn)算法」做了個(gè)假設(shè),即讓所有的進(jìn)程同等重要,也不偏袒誰(shuí),大家的運(yùn)行時(shí)間都一樣。
但是,對(duì)于多用戶(hù)計(jì)算機(jī)系統(tǒng)就有不同的看法了,它們希望調(diào)度是有優(yōu)先級(jí)的,即希望調(diào)度程序能從就緒隊(duì)列中選擇最高優(yōu)先級(jí)的進(jìn)程進(jìn)行運(yùn)行,這稱(chēng)為最高優(yōu)先級(jí)(*Highest Priority First,HPF*)調(diào)度算法。
進(jìn)程的優(yōu)先級(jí)可以分為,靜態(tài)優(yōu)先級(jí)和動(dòng)態(tài)優(yōu)先級(jí):
- 靜態(tài)優(yōu)先級(jí):創(chuàng)建進(jìn)程時(shí)候,就已經(jīng)確定了優(yōu)先級(jí)了,然后整個(gè)運(yùn)行時(shí)間優(yōu)先級(jí)都不會(huì)變化;
- 動(dòng)態(tài)優(yōu)先級(jí):根據(jù)進(jìn)程的動(dòng)態(tài)變化調(diào)整優(yōu)先級(jí),比如如果進(jìn)程運(yùn)行時(shí)間增加,則降低其優(yōu)先級(jí),如果進(jìn)程等待時(shí)間(就緒隊(duì)列的等待時(shí)間)增加,則升高其優(yōu)先級(jí),也就是隨著時(shí)間的推移增加等待進(jìn)程的優(yōu)先級(jí)。
該算法也有兩種處理優(yōu)先級(jí)高的方法,非搶占式和搶占式:
- 非搶占式:當(dāng)就緒隊(duì)列中出現(xiàn)優(yōu)先級(jí)高的進(jìn)程,運(yùn)行完當(dāng)前進(jìn)程,再選擇優(yōu)先級(jí)高的進(jìn)程。
- 搶占式:當(dāng)就緒隊(duì)列中出現(xiàn)優(yōu)先級(jí)高的進(jìn)程,當(dāng)前進(jìn)程掛起,調(diào)度優(yōu)先級(jí)高的進(jìn)程運(yùn)行。
但是依然有缺點(diǎn),可能會(huì)導(dǎo)致低優(yōu)先級(jí)的進(jìn)程永遠(yuǎn)不會(huì)運(yùn)行。
06 多級(jí)反饋隊(duì)列調(diào)度算法
多級(jí)反饋隊(duì)列(*Multilevel Feedback Queue*)調(diào)度算法是「時(shí)間片輪轉(zhuǎn)算法」和「最高優(yōu)先級(jí)算法」的綜合和發(fā)展。
顧名思義:
- 「多級(jí)」表示有多個(gè)隊(duì)列,每個(gè)隊(duì)列優(yōu)先級(jí)從高到低,同時(shí)優(yōu)先級(jí)越高時(shí)間片越短。
- 「反饋」表示如果有新的進(jìn)程加入優(yōu)先級(jí)高的隊(duì)列時(shí),立刻停止當(dāng)前正在運(yùn)行的進(jìn)程,轉(zhuǎn)而去運(yùn)行優(yōu)先級(jí)高的隊(duì)列;
多級(jí)反饋隊(duì)列
來(lái)看看,它是如何工作的:
- 設(shè)置了多個(gè)隊(duì)列,賦予每個(gè)隊(duì)列不同的優(yōu)先級(jí),每個(gè)隊(duì)列優(yōu)先級(jí)從高到低,同時(shí)優(yōu)先級(jí)越高時(shí)間片越短;
- 新的進(jìn)程會(huì)被放入到第一級(jí)隊(duì)列的末尾,按先來(lái)先服務(wù)的原則排隊(duì)等待被調(diào)度,如果在第一級(jí)隊(duì)列規(guī)定的時(shí)間片沒(méi)運(yùn)行完成,則將其轉(zhuǎn)入到第二級(jí)隊(duì)列的末尾,以此類(lèi)推,直至完成;
- 當(dāng)較高優(yōu)先級(jí)的隊(duì)列為空,才調(diào)度較低優(yōu)先級(jí)的隊(duì)列中的進(jìn)程運(yùn)行。如果進(jìn)程運(yùn)行時(shí),有新進(jìn)程進(jìn)入較高優(yōu)先級(jí)的隊(duì)列,則停止當(dāng)前運(yùn)行的進(jìn)程并將其移入到原隊(duì)列末尾,接著讓較高優(yōu)先級(jí)的進(jìn)程運(yùn)行;
可以發(fā)現(xiàn),對(duì)于短作業(yè)可能可以在第一級(jí)隊(duì)列很快被處理完。對(duì)于長(zhǎng)作業(yè),如果在第一級(jí)隊(duì)列處理不完,可以移入下次隊(duì)列等待被執(zhí)行,雖然等待的時(shí)間變長(zhǎng)了,但是運(yùn)行時(shí)間也變更長(zhǎng)了,所以該算法很好的兼顧了長(zhǎng)短作業(yè),同時(shí)有較好的響應(yīng)時(shí)間。
數(shù)據(jù)庫(kù)
MySQL和Redis的區(qū)別,應(yīng)用場(chǎng)景?
MySQL 是關(guān)系型數(shù)據(jù)庫(kù),適用于需要保持?jǐn)?shù)據(jù)一致性、進(jìn)行復(fù)雜的數(shù)據(jù)分析和關(guān)聯(lián)查詢(xún)的場(chǎng)景。
Redis是一種基于內(nèi)存的數(shù)據(jù)存儲(chǔ)系統(tǒng),它主要用于緩存和高速數(shù)據(jù)訪問(wèn)。Redis適合處理高速讀寫(xiě)和緩存需求,適用于需要快速響應(yīng)和高并發(fā)的場(chǎng)景,例如實(shí)時(shí)計(jì)數(shù)器、會(huì)話緩存、消息隊(duì)列、發(fā)布/訂閱系統(tǒng)等。
一般會(huì)用Redis 作為MySQL的緩存,主要是因?yàn)?Redis 具備「高性能」和「高并發(fā)」兩種特性。
1、Redis 具備高性能
假如用戶(hù)第一次訪問(wèn) MySQL 中的某些數(shù)據(jù)。這個(gè)過(guò)程會(huì)比較慢,因?yàn)槭菑挠脖P(pán)上讀取的。將該用戶(hù)訪問(wèn)的數(shù)據(jù)緩存在 Redis 中,這樣下一次再訪問(wèn)這些數(shù)據(jù)的時(shí)候就可以直接從緩存中獲取了,操作 Redis 緩存就是直接操作內(nèi)存,所以速度相當(dāng)快。
img如果 MySQL 中的對(duì)應(yīng)數(shù)據(jù)改變的之后,同步改變 Redis 緩存中相應(yīng)的數(shù)據(jù)即可,不過(guò)這里會(huì)有 Redis 和 MySQL 雙寫(xiě)一致性的問(wèn)題,后面我們會(huì)提到。
2、Redis 具備高并發(fā)
單臺(tái)設(shè)備的 Redis 的 QPS(Query Per Second,每秒鐘處理完請(qǐng)求的次數(shù)) 是 MySQL 的 10 倍,Redis 單機(jī)的 QPS 能輕松破 10w,而 MySQL 單機(jī)的 QPS 很難破 1w。
所以,直接訪問(wèn) Redis 能夠承受的請(qǐng)求是遠(yuǎn)遠(yuǎn)大于直接訪問(wèn) MySQL 的,所以我們可以考慮把數(shù)據(jù)庫(kù)中的部分?jǐn)?shù)據(jù)轉(zhuǎn)移到緩存中去,這樣用戶(hù)的一部分請(qǐng)求會(huì)直接到緩存這里而不用經(jīng)過(guò)數(shù)據(jù)庫(kù)。
MySQL有哪些存儲(chǔ)引擎?有什么區(qū)別?
-
InnoDB:支持事務(wù)處理,支持外鍵,支持崩潰修復(fù)能力和并發(fā)控制。如果需要對(duì)事務(wù)的完整性要求比較高(比如銀行),要求實(shí)現(xiàn)并發(fā)控制(比如售票),那選擇InnoDB有很大的優(yōu)勢(shì)。如果需要頻繁的更新、刪除操作的數(shù)據(jù)庫(kù),也可以選擇InnoDB,因?yàn)橹С质聞?wù)的提交(commit)和回滾(rollback)。
-
MyISAM:插入數(shù)據(jù)快,空間和內(nèi)存使用比較低。如果表主要是用于插入新記錄和讀出記錄,那么選擇MyISAM能實(shí)現(xiàn)處理高效率。如果應(yīng)用的完整性、并發(fā)性要求比 較低,也可以使用。如果數(shù)據(jù)表主要用來(lái)插入和查詢(xún)記錄,則MyISAM引擎能提供較高的處理效率
-
MEMORY:所有的數(shù)據(jù)都在內(nèi)存中,數(shù)據(jù)的處理速度快,但是安全性不高。如果需要很快的讀寫(xiě)速度,對(duì)數(shù)據(jù)的安全性要求較低,可以選擇MEMOEY。它對(duì)表的大小有要求,不能建立太大的表。所以,這類(lèi)數(shù)據(jù)庫(kù)只使用在相對(duì)較小的數(shù)據(jù)庫(kù)表。如果只是臨時(shí)存放數(shù)據(jù),數(shù)據(jù)量不大,并且不需要較高的數(shù)據(jù)安全性,可以選擇將數(shù)據(jù)保存在內(nèi)存中的Memory引擎,MySQL中使用該引擎作為臨時(shí)表,存放查詢(xún)的中間結(jié)果
事務(wù)用來(lái)解決什么問(wèn)題?
事務(wù)用于解決數(shù)據(jù)庫(kù)操作中的一致性和持久性問(wèn)題。
-
一致性問(wèn)題指的是在多個(gè)并發(fā)操作中,如果其中一個(gè)操作失敗或發(fā)生錯(cuò)誤,可能導(dǎo)致數(shù)據(jù)處于不一致的狀態(tài),不符合預(yù)期的要求。
-
持久性問(wèn)題指的是確保已提交的數(shù)據(jù)在數(shù)據(jù)庫(kù)系統(tǒng)
事務(wù)的四大特性主要是:
- 原子性(Atomicity):一個(gè)事務(wù)中的所有操作,要么全部完成,要么全部不完成,不會(huì)結(jié)束在中間某個(gè)環(huán)節(jié),而且事務(wù)在執(zhí)行過(guò)程中發(fā)生錯(cuò)誤,會(huì)被回滾到事務(wù)開(kāi)始前的狀態(tài),就像這個(gè)事務(wù)從來(lái)沒(méi)有執(zhí)行過(guò)一樣,就好比買(mǎi)一件商品,購(gòu)買(mǎi)成功時(shí),則給商家付了錢(qián),商品到手;購(gòu)買(mǎi)失敗時(shí),則商品在商家手中,消費(fèi)者的錢(qián)也沒(méi)花出去。
- 一致性(Consistency):是指事務(wù)操作前和操作后,數(shù)據(jù)滿(mǎn)足完整性約束,數(shù)據(jù)庫(kù)保持一致性狀態(tài)。比如,用戶(hù) A 和用戶(hù) B 在銀行分別有 800 元和 600 元,總共 1400 元,用戶(hù) A 給用戶(hù) B 轉(zhuǎn)賬 200 元,分為兩個(gè)步驟,從 A 的賬戶(hù)扣除 200 元和對(duì) B 的賬戶(hù)增加 200 元。一致性就是要求上述步驟操作后,最后的結(jié)果是用戶(hù) A 還有 600 元,用戶(hù) B 有 800 元,總共 1400 元,而不會(huì)出現(xiàn)用戶(hù) A 扣除了 200 元,但用戶(hù) B 未增加的情況(該情況,用戶(hù) A 和 B 均為 600 元,總共 1200 元)。
- 隔離性(Isolation):數(shù)據(jù)庫(kù)允許多個(gè)并發(fā)事務(wù)同時(shí)對(duì)其數(shù)據(jù)進(jìn)行讀寫(xiě)和修改的能力,隔離性可以防止多個(gè)事務(wù)并發(fā)執(zhí)行時(shí)由于交叉執(zhí)行而導(dǎo)致數(shù)據(jù)的不一致,因?yàn)槎鄠€(gè)事務(wù)同時(shí)使用相同的數(shù)據(jù)時(shí),不會(huì)相互干擾,每個(gè)事務(wù)都有一個(gè)完整的數(shù)據(jù)空間,對(duì)其他并發(fā)事務(wù)是隔離的。也就是說(shuō),消費(fèi)者購(gòu)買(mǎi)商品這個(gè)事務(wù),是不影響其他消費(fèi)者購(gòu)買(mǎi)的。
- 持久性(Durability):事務(wù)處理結(jié)束后,對(duì)數(shù)據(jù)的修改就是永久的,即便系統(tǒng)故障也不會(huì)丟失。
MySQL存儲(chǔ)的數(shù)據(jù)結(jié)構(gòu)是怎么樣的?
InnoDB 存儲(chǔ)引擎的索引結(jié)構(gòu)是 b+樹(shù)。
選擇 b+樹(shù)作為數(shù)據(jù)結(jié)構(gòu)的原因是:
- B+Tree vs B Tree:B+Tree 只在葉子節(jié)點(diǎn)存儲(chǔ)數(shù)據(jù),而 B 樹(shù) 的非葉子節(jié)點(diǎn)也要存儲(chǔ)數(shù)據(jù),所以 B+Tree 的單個(gè)節(jié)點(diǎn)的數(shù)據(jù)量更小,在相同的磁盤(pán) I/O 次數(shù)下,就能查詢(xún)更多的節(jié)點(diǎn)。另外,B+Tree 葉子節(jié)點(diǎn)采用的是雙鏈表連接,適合 MySQL 中常見(jiàn)的基于范圍的順序查找,而 B 樹(shù)無(wú)法做到這一點(diǎn)。
-
B+Tree vs 二叉樹(shù):對(duì)于有 N 個(gè)葉子節(jié)點(diǎn)的 B+Tree,其搜索復(fù)雜度為
O(logdN)
,其中 d 表示節(jié)點(diǎn)允許的最大子節(jié)點(diǎn)個(gè)數(shù)為 d 個(gè)。在實(shí)際的應(yīng)用當(dāng)中, d 值是大于100的,這樣就保證了,即使數(shù)據(jù)達(dá)到千萬(wàn)級(jí)別時(shí),B+Tree 的高度依然維持在 3~4 層左右,也就是說(shuō)一次數(shù)據(jù)查詢(xún)操作只需要做 3~4 次的磁盤(pán) I/O 操作就能查詢(xún)到目標(biāo)數(shù)據(jù)。而二叉樹(shù)的每個(gè)父節(jié)點(diǎn)的兒子節(jié)點(diǎn)個(gè)數(shù)只能是 2 個(gè),意味著其搜索復(fù)雜度為O(logN)
,這已經(jīng)比 B+Tree 高出不少,因此二叉樹(shù)檢索到目標(biāo)數(shù)據(jù)所經(jīng)歷的磁盤(pán) I/O 次數(shù)要更多。 - B+Tree vs Hash:Hash 在做等值查詢(xún)的時(shí)候效率賊快,搜索復(fù)雜度為 O(1)。但是 Hash 表不適合做范圍查詢(xún),它更適合做等值的查詢(xún),這也是 B+Tree 索引要比 Hash 表索引有著更廣泛的適用場(chǎng)景的原因。
Text數(shù)據(jù)類(lèi)型可以無(wú)限大嗎?
MySQL 3 種text類(lèi)型的最大長(zhǎng)度如下:
- TEXT:65,535 bytes ~64kb
- MEDIUMTEXT:16,777,215 bytes ~16Mb
- LONGTEXT:4,294,967,295 bytes ~4Gb
MySQL索引的優(yōu)缺點(diǎn)?
索引最大的好處是提高查詢(xún)速度,但是索引也是有缺點(diǎn)的,比如:
- 需要占用物理空間,數(shù)量越大,占用空間越大;
- 創(chuàng)建索引和維護(hù)索引要耗費(fèi)時(shí)間,這種時(shí)間隨著數(shù)據(jù)量的增加而增大;
- 會(huì)降低表的增刪改的效率,因?yàn)槊看卧鰟h改索引,B+ 樹(shù)為了維護(hù)索引有序性,都需要進(jìn)行動(dòng)態(tài)維護(hù)。
所以,索引不是萬(wàn)能鑰匙,它也是根據(jù)場(chǎng)景來(lái)使用的。
什么時(shí)候不適合用索引?
-
WHERE
條件,GROUP BY
,ORDER BY
里用不到的字段,索引的價(jià)值是快速定位,如果起不到定位的字段通常是不需要?jiǎng)?chuàng)建索引的,因?yàn)樗饕菚?huì)占用物理空間的。 - 字段中存在大量重復(fù)數(shù)據(jù),不需要?jiǎng)?chuàng)建索引,比如性別字段,只有男女,如果數(shù)據(jù)庫(kù)表中,男女的記錄分布均勻,那么無(wú)論搜索哪個(gè)值都可能得到一半的數(shù)據(jù)。在這些情況下,還不如不要索引,因?yàn)?MySQL 還有一個(gè)查詢(xún)優(yōu)化器,查詢(xún)優(yōu)化器發(fā)現(xiàn)某個(gè)值出現(xiàn)在表的數(shù)據(jù)行中的百分比很高的時(shí)候,它一般會(huì)忽略索引,進(jìn)行全表掃描。
- 表數(shù)據(jù)太少的時(shí)候,不需要?jiǎng)?chuàng)建索引;
- 經(jīng)常更新的字段不用創(chuàng)建索引,比如不要對(duì)電商項(xiàng)目的用戶(hù)余額建立索引,因?yàn)樗饕侄晤l繁修改,由于要維護(hù) B+Tree的有序性,那么就需要頻繁的重建索引,這個(gè)過(guò)程是會(huì)影響數(shù)據(jù)庫(kù)性能的。
算法
- 實(shí)現(xiàn) LRU算法實(shí)現(xiàn)(鏈表+hashmap)
#include
#include
#include
classLRUCache{
private:
intcapacity;
std::unordered_map<int,std::list<std::pair<int,int>>::iterator>cache;
std::list<std::pair<int,int>>lruList;
public:
LRUCache(intcapacity){
this->capacity=capacity;
}
intget(intkey){
if(cache.find(key)==cache.end()){
return-1;//如果key不存在,返回-1
}
//將訪問(wèn)的節(jié)點(diǎn)移動(dòng)到鏈表頭部
std::pair<int,int>keyValue=*cache[key];
lruList.erase(cache[key]);
lruList.push_front(keyValue);
cache[key]=lruList.begin();
returnkeyValue.second;
}
voidput(intkey,intvalue){
if(cache.find(key)==cache.end()){
//如果容量已滿(mǎn),移除最久未使用的節(jié)點(diǎn)
if(lruList.size()==capacity){
std::pair<int,int>lastPair=lruList.back();
intlastKey=lastPair.first;
cache.erase(lastKey);
lruList.pop_back();
}
//將新節(jié)點(diǎn)添加到鏈表頭部
lruList.push_front(std::make_pair(key,value));
cache[key]=lruList.begin();
}else{
//如果key已存在,更新節(jié)點(diǎn)的值,并將節(jié)點(diǎn)移動(dòng)到鏈表頭部
lruList.erase(cache[key]);
lruList.push_front(std::make_pair(key,value));
cache[key]=lruList.begin();
}
}
};
intmain(){
LRUCachecache(2);
cache.put(1,1);
cache.put(2,2);
std::cout<1)<std::endl;//輸出1
cache.put(3,3);
std::cout<2)<std::endl;//輸出-1
cache.put(4,4);
std::cout<1)<std::endl;//輸出-1
std::cout<3)<std::endl;//輸出3
std::cout<4)<std::endl;//輸出4
return0;
}
-
數(shù)據(jù)傳輸
+關(guān)注
關(guān)注
9文章
1915瀏覽量
64649 -
傳輸層
+關(guān)注
關(guān)注
0文章
29瀏覽量
10912 -
網(wǎng)絡(luò)模型
+關(guān)注
關(guān)注
0文章
44瀏覽量
8439
原文標(biāo)題:騰訊有點(diǎn)頂,連環(huán)追問(wèn)我基礎(chǔ)細(xì)節(jié)!
文章出處:【微信號(hào):小林coding,微信公眾號(hào):小林coding】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論