1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        美團(tuán)面試經(jīng)歷

        共 3091字,需瀏覽 7分鐘

         ·

        2020-10-28 04:30


        本文公眾號來源:程序員小賤
        作者:L的存在
        本文已收錄至我的GitHub

        叮。。。。。美團(tuán)來電。這次不是外賣而是電話面試。所報崗位為后端/服務(wù)端開發(fā),但是從我的復(fù)盤來看,這和 Java 后端開發(fā)的內(nèi)容差不多,除了部分的語言特性外,還是四大件基礎(chǔ)知識為重,下面我們來看看都問了啥,小心下次面你的時候就有這些問題哦

        如果你問我,看了這些題就完事了?非也,這只是開始,你需要學(xué)習(xí)的還有很多,知道路子是怎么走才是重要的勒。

        開始之前,我們先看提綱,大家默默的想一想,如果是你,你將怎么去回答這個問題,然后再看我的回答也許更佳哈。

        提綱

        1 一面(40分鐘)


        • 自我介紹

        老規(guī)矩,我叫啥,啥專業(yè),技術(shù)棧是啥,能做啥

        • 怎么理解分布式

        其實如果沒有去實習(xí),可能很少接觸分布式的內(nèi)容。對于面試官而言,也沒多期望你們對分布式的理解到多深的地步,只是希望你們能對其有個初步的了解即可。

        不管是高登摩爾提出的摩爾定律還是Gordon Moore堅持的2版本是啥,總之如果你的系統(tǒng)需承載的計算量的增長速度大于摩爾定律的預(yù)測,那么在未來的某一個時間點,集中式系統(tǒng)將無法承載你所需的計算 量。

        在整個計算機系統(tǒng)發(fā)展的過程中,最實際的還是經(jīng)濟(jì)的元素。人們發(fā)現(xiàn)使用更加廉價的機器,組合在一起的分布式系統(tǒng),除了可以獲得超過CPU發(fā)展速度的性能以外,還可以有更好的性價比,所以得出如下結(jié)論:

        無論是要以低價格獲得普通的性能,還是要以較高的價格獲 得極高的性能,分布式系統(tǒng)都能夠滿足。并且受規(guī)模效應(yīng)的影響,系統(tǒng)越大,性價比帶來 的收益越高。

        隨著計算機的飛速發(fā)展,科學(xué)家們發(fā)現(xiàn)分布式系統(tǒng)相比于集中式系統(tǒng)的另一個很明顯的優(yōu)勢就是:具有更高的可用性。假設(shè)使用10個能夠承載10000流量相同的節(jié)點,其中的兩個節(jié)點掛了,只要實際的流量不超過8000,那么系統(tǒng)仍然正常運轉(zhuǎn)。

        說這么多,分布式系統(tǒng)還是建立在「分治」和「冗余」的基礎(chǔ)上,這也就是分布式系統(tǒng)的本質(zhì)

        那么分治是什么?

        這和我們大腦解決問題類似,大問題分解為小問題,然后治理最后歸并。

        分治

        為什么要這樣做?

        • 小問題容易解決,解決了眾多的子問題,大問題也就更容易解決啦

        如果拆分的父子問題有依賴關(guān)系怎么辦?

        大問題拆分的過程中,非常重要的即不同分支的子問題不能相互依賴,需要各自獨立,因為如果存在依賴關(guān)系,父子問題就失去了「歸并」的意義,那么在開發(fā)中,這就是「聚合度」和「內(nèi)聚度」的問題。

        什么是聚合度和內(nèi)聚度?

        所謂聚合度即軟件系統(tǒng)中各個模塊的相互依賴程度。比如在調(diào)用A方法的時候都需要同步調(diào)用方法B,顯然這樣的耦合度就高

        所謂內(nèi)聚度即模塊之間具有共同點的相似程度,所以在拆分的時候要尤其注意這兩點。

        什么是冗余?

        這里的冗余不是代碼的冗余,而是容許系統(tǒng)在一定范圍內(nèi)出現(xiàn)故障,但對系統(tǒng)的影響很小

        冗余

        如上圖將冗余的節(jié)點部署在單獨的服務(wù)器,完全是為了備用而做的冗余,如果不出現(xiàn)故障,那么資源是不是就浪費了,所以大多數(shù)情況會使用諸如雙主多活、讀寫分離之類的概念提高資源利用率

        其實在生活中冗余也很常見,比如大部分的汽車系統(tǒng)中的底層控制系統(tǒng)也是有冗余機制,飛機發(fā)動機為什么是偶數(shù),也是同樣的道理。還有更多的關(guān)于后端的基礎(chǔ)總結(jié)要點則參考另一篇文章42圖揭秘,「后端技術(shù)學(xué)些啥」

        寫個代碼熱熱身----棧實現(xiàn)隊列

        class?MyQueue?{
        public:
        ????stack<int>?stIn;
        ????stack<int>?stOut;
        ????/**?Initialize?your?data?structure?here.?*/
        ????MyQueue()?{

        ????}
        ????/**?Push?element?x?to?the?back?of?queue.?*/
        ????void?push(int?x)?{
        ????????stIn.push(x);
        ????}

        ????/**?Removes?the?element?from?in?front?of?queue?and?returns?that?element.?*/
        ????int?pop()?{
        ????????//?只有當(dāng)stOut為空的時候,再從stIn里導(dǎo)入數(shù)據(jù)(導(dǎo)入stIn全部數(shù)據(jù))
        ????????if?(stOut.empty())?{
        ????????????//?從stIn導(dǎo)入數(shù)據(jù)直到stIn為空
        ????????????while(!stIn.empty())?{
        ????????????????stOut.push(stIn.top());
        ????????????????stIn.pop();
        ????????????}
        ????????}
        ????????int?result?=?stOut.top();
        ????????stOut.pop();
        ????????return?result;
        ????}

        ????/**?Get?the?front?element.?*/
        ????int?peek()?{
        ????????int?res?=?this->pop();?//?直接使用已有的pop函數(shù)
        ????????stOut.push(res);?//?因為pop函數(shù)彈出了元素res,所以再添加回去
        ????????return?res;
        ????}

        ????/**?Returns?whether?the?queue?is?empty.?*/
        ????bool?empty()?{
        ????????return?stIn.empty()?&&?stOut.empty();
        ????}
        };

        介紹下第一個項目

        注意:校招的的面試在我看來寫兩個項目差不多了,印象更深刻且自己的理解程度更好的放在上面。面試之前一定要搞懂這三個問題,且在練習(xí)的時候想想怎么能引面試官上鉤

        • 項目的描述

        • 自己在項目中擔(dān)任的角色,做了什么

        • 在項目中遇到什么難點,怎么處理,有沒有測試過

        說說快排思想?

        如果我們的每一次分區(qū)操作都能正好將數(shù)組分成大小接近相等的兩個小區(qū)間,那么快排的時間復(fù)雜度和歸并是差不多的,所以其時間復(fù)雜度為O(nlogn)

        這里特別注意所謂的每次分區(qū)操作有個前提條件,即選擇的pivot很合適,能掙好的將大區(qū)間對等的一分為二,如果原來的數(shù)據(jù)是一件排好序的,我們選擇最后一個元素為pivot,這樣每次分區(qū)得到的兩個區(qū)間是不均等,我們需要進(jìn)行大約n次分區(qū)操作,每次分區(qū)平均掃描n/2個元素,此時的復(fù)雜度將退化為0(n ^ 2)

        :一定要能手撕快排啊,這真是無數(shù)次會被考?。?!

        public?class?QuickSort?{
        ????public?static?void?main(String[]?args)?{
        ????????int[]?arr?=?{?49,?38,?65,?97,?23,?22,?76,?1,?5,?8,?2,?0,?-1,?22?};
        ????????quickSort(arr,?0,?arr.length?-?1);
        ????????System.out.println("排序后:");
        ????????for?(int?i?:?arr)?{
        ????????????System.out.println(i);
        ????????}
        ????}
        ????private?static?void?quickSort(int[]?arr,?int?low,?int?high)?{

        ????????if?(low?????????????//?找尋基準(zhǔn)數(shù)據(jù)的正確索引
        ????????????int?index?=?getIndex(arr,?low,?high);

        ????????????//?進(jìn)行迭代對index之前和之后的數(shù)組進(jìn)行相同的操作使整個數(shù)組變成有序
        ????????????//quickSort(arr,?0,?index?-?1);?之前的版本,這種姿勢有很大的性能問題,謝謝大家的建議
        ????????????quickSort(arr,?low,?index?-?1);
        ????????????quickSort(arr,?index?+?1,?high);
        ????????}

        ????}

        ????private?static?int?getIndex(int[]?arr,?int?low,?int?high)?{
        ????????//?基準(zhǔn)數(shù)據(jù)
        ????????int?tmp?=?arr[low];
        ????????while?(low?????????????//?當(dāng)隊尾的元素大于等于基準(zhǔn)數(shù)據(jù)時,向前挪動high指針
        ????????????while?(low?=?tmp)?{
        ????????????????high--;
        ????????????}
        ????????????//?如果隊尾元素小于tmp了,需要將其賦值給low
        ????????????arr[low]?=?arr[high];
        ????????????//?當(dāng)隊首元素小于等于tmp時,向前挪動low指針
        ????????????while?(low?????????????????low++;
        ????????????}
        ????????????//?當(dāng)隊首元素大于tmp時,需要將其賦值給high
        ????????????arr[high]?=?arr[low];

        ????????}
        ????????//?跳出循環(huán)時low和high相等,此時的low或high就是tmp的正確索引位置
        ????????//?由原理部分可以很清楚的知道low位置的值并不是tmp,所以需要將tmp賦值給arr[low]
        ????????arr[low]?=?tmp;
        ????????return?low;?//?返回tmp的正確位置
        ????}
        }

        半連接了解吧,如果SYN半連接隊列滿了怎么處理,只能丟棄連接?

        如果你看過我之前寫的文章,這個問題應(yīng)該就非常容易解決了。SYN半連接隊列已滿,通過開啟cookies功能就可以在不使用SYN隊列的情況下成功建立連接

        syncookies是怎么操作的?

        服務(wù)端返回 ACK 的時候會計算一個值放在發(fā)出的SYN+ACK報文中,當(dāng)客戶端返回ACK的時候取出該值進(jìn)行驗證,如果合法即連接成功

        半連接隊列

        Linux如何開啟syncookies呢?

        通過將參數(shù)tcp_cookies設(shè)置1即可。如果參數(shù)值為2,表示無條件開啟這個功能。如果為1表示僅當(dāng)SYN半連接隊列放不下的時候,再開啟。

        開啟syncookies

        那可不可以繞過三次握手?

        還有這種操作?

        三次握手中,一個較大的問題是HTTP請求必須在一次的RTT后才能發(fā)送。從而谷歌提出了TFO。想要繞過三次握手過程,如果是客戶端發(fā)起連接,想要在SYN的請求報文中放入數(shù)據(jù),需要得到服務(wù)端的認(rèn)可,所以事先需要有個約定。

        • 首次建立連接走正常的三次握手,客戶端會在SYN報文中明確告訴服務(wù)器要使用TFO功能,服務(wù)端答應(yīng)后就會將客戶端的IP地址用自己的密鑰加密(cookie)攜帶在返回的SYN+ACK中,客戶端收到后將cookie緩存到本地

        • 下次客戶端再建立連接,就可以在SYN中攜帶請求的數(shù)據(jù)+緩存的cookie

        繞過三次握手

        剛才你說的密鑰是不會變的?

        當(dāng)然變化,不然就很容易產(chǎn)生SYN泛洪攻擊了。

        Linux中如何打開TFO?

        這里要注意了,需要客戶端和服務(wù)端都支持,TFO才會生效,當(dāng)tcp_fastopen設(shè)置為3的時候才生效

        net.ipv4.tcp_fastopen=3

        舉幾個使用緩存的例子

        這里涉及面就非常廣了,什么數(shù)據(jù)庫緩存,如何選擇緩存的讀寫策略,如何做到緩存高可用,緩存穿透的怎么處理以及CDN相關(guān),我們先舉幾個緩存的例子

        • 我們知道虛擬地址到物理地址轉(zhuǎn)換的時候需要通過一個叫做MMU的硬件,每次這樣的轉(zhuǎn)換無疑會造成性能的轉(zhuǎn)換,所以接住了TLB來緩存最近轉(zhuǎn)換過的,下一次轉(zhuǎn)換的時候,如果緩存存在就直接轉(zhuǎn)換即可

        • 在路由尋址的時候,會有個映射表讓我們知道該訪問哪個目的地址,同樣存在于緩存中

        • HTTP緩存機制。通過緩存協(xié)商方式減少網(wǎng)絡(luò)傳輸?shù)臄?shù)據(jù)大小從而提升頁面展示的性能

        緩存怎么個分類?

        緩存分類分為三種,分別為靜態(tài)緩存、分布式緩存與本地緩存。

        靜態(tài)緩存

        通常使用靜態(tài)HTML實現(xiàn)靜態(tài)緩存。通過在Nginx上部署靜態(tài)緩存減少對于后臺應(yīng)用服務(wù)器的壓力。當(dāng)然你也可以存放數(shù)據(jù)庫,然后前端穿透查詢,但是對于后端的服務(wù)器壓力是非常大的。比如內(nèi)容系統(tǒng),通常在錄入文章的時候先渲染成靜態(tài)頁面,然后放在前端Ngix服務(wù)器上,這樣用戶會直接訪問前端靜態(tài)頁面,但是如果是動態(tài)請求,這樣就需要分布式緩存了

        分布式緩存

        面試中高頻的Redis和Memchache,就是通過集群的方式突破單機瓶頸

        熱點本地緩存

        熱點嘛,微博每天都有熱點,尤其是什么XX明星出軌,這樣的查詢通常會命中某一個緩存節(jié)點,短時間內(nèi)極高的緩存熱點查詢。這個時候就會在代碼中使用一些本地本地緩存方案。如hashmap

        緩存的不足

        從上面基本上知道,緩存的主要作用是提升訪問的速度,提升并發(fā)的能力。

        • 緩存最好適用于讀多寫少且?guī)в幸欢ǖ臒狳c屬性

        因為既然是緩存受限于存儲介質(zhì),不可能緩存所有數(shù)據(jù),只有當(dāng)數(shù)據(jù)有一定的熱點屬性才能有更高的緩存命中率

        • 緩存讓系統(tǒng)更加復(fù)雜,容易出現(xiàn)數(shù)據(jù)不一致的現(xiàn)象

        比如更新數(shù)據(jù)庫成功了,但是更新緩存失敗了。這個時候可以考慮固定時間清理或者手動清理。

        • 給運維帶來一定的成本

        運維小哥需要了解一些緩存組件的使用

        一面小結(jié)

        一面面試涉及到了項目,計算機網(wǎng)絡(luò),數(shù)據(jù)結(jié)構(gòu)和后端的基本知識,也基本覆蓋了校招的各科且有一定的是實踐性考察,不同公司面試當(dāng)然不一樣,看多了你會發(fā)現(xiàn)重點就是這些了,繼續(xù)復(fù)盤二面

        2 二面


        慢慢的到了10月,面試的越多不知道的越多,感覺需要學(xué)習(xí)的越多,當(dāng)然越戰(zhàn)越勇,面完一面是一面,積累一面是一面。團(tuán)團(tuán)既然給臉,那就面唄

        寫個代碼-----數(shù)組中數(shù)字出現(xiàn)的次數(shù)

        我擦,上來就是寫代碼,不過大家習(xí)慣就好,每個面試官套路不同,資本社會接受即可,寫唄,準(zhǔn)備這么久的你還怕啥。管他三七二十一,能上位運算就上位運算,盤它完事,小伙伴說能不能寫個python版本,那就py唄。如果這個題目還要猶豫,趕緊再去練練《劍指offer》和leetcode100題呀

        class?Solution(object):
        ????def?singleNumbers(self,?nums):
        ????????"""
        ????????:type?nums:?List[int]
        ????????:rtype:?List[int]
        ????????"""

        ????????temp?=?0
        ????????for?i?in?nums:#得到用于區(qū)分的數(shù)字
        ????????????temp?^=?i
        ????????num?=?1
        ????????while?not?(num?&?temp):#找到用于區(qū)分的數(shù)字中從右到左的第一位為1的值
        ????????????num?=?num?<1
        ????????result1?=?0
        ????????result2?=?0
        ????????for?i?in?nums:
        ????????????if?num?&?i:#?劃分兩個數(shù)組
        ????????????????result1?^=?i#兩個數(shù)組分別取異或
        ????????????else:
        ????????????????result2?^=?i
        ????????return[result1,result2]?

        說說TCP的收發(fā)包可通過哪些配置?

        這個題就有點大了,我可以扯很久,而且只要問到TCP發(fā)送或者接受的類似問題,真是可以大干好幾百個回合。在這里就稍微詳細(xì)的說說,在以后的面試過程中,遇到此題講不在多說哈,還答不上來就打自己幾耳巴可好,別別,還是不能這么對自己,好了,不多BB了,上干貨

        收包是數(shù)據(jù)到達(dá)網(wǎng)卡后交給應(yīng)用程序處理的過程,發(fā)包則調(diào)用相應(yīng)的發(fā)包函數(shù)將數(shù)據(jù)包從網(wǎng)卡發(fā)出的場景。

        我們再看看類似的幾個問題

        • 我明明是用了write和send進(jìn)行發(fā)包,但是總是發(fā)不出去

        • 通過抓包發(fā)現(xiàn)數(shù)據(jù)包已經(jīng)到網(wǎng)卡了,但是應(yīng)用程序為什么就是收不到

        • 調(diào)整了緩沖區(qū)大小,不失效的原因

        和前面一樣,都是需要了解相應(yīng)的系統(tǒng)參數(shù)才能較好的回答這些問題且能體現(xiàn)你對網(wǎng)絡(luò)的了解深度

        TCP數(shù)據(jù)包在發(fā)送的過程中會受到哪些影響?

        TCP數(shù)據(jù)包發(fā)送過程

        這個圖畫了一個小時,一定要好好看看,順便記得給我一個贊,么么噠,下面我們詳細(xì)看看這個圖

        當(dāng)我們通過write等發(fā)包函數(shù)進(jìn)行發(fā)包的時候,這些系統(tǒng)調(diào)用都是將數(shù)據(jù)包先從用戶緩沖區(qū)拷貝到TCP發(fā)送緩沖區(qū)中,可是這個TCP緩沖區(qū)是有大小限制的,正是這個限制就會產(chǎn)生各種問題。

        TCP發(fā)送緩沖區(qū)的默認(rèn)受到 net.ipv4.tcp_wmen 控制

        TCP發(fā)送緩沖區(qū)設(shè)置

        這三個參數(shù)分別的叫做是min,default,max。TCP發(fā)送緩沖區(qū)會在min和max中浮動,初始的大小為default。

        為什么需要自動調(diào)整,是不是越大越好?

        首先這個動態(tài)調(diào)整是由內(nèi)核來完成,不需要應(yīng)用程序的干預(yù),而且每次發(fā)包的大小不一樣,數(shù)據(jù)太小,緩沖區(qū)卻很大自然就浪費了內(nèi)存,所以通過動態(tài)調(diào)整的方式滿足發(fā)包的需要。

        TCP緩沖區(qū)設(shè)置太小或者太大有什么標(biāo)志?

        TCP的發(fā)送緩沖區(qū)設(shè)置太小,最明顯的特征即導(dǎo)致業(yè)務(wù)延遲。如何發(fā)現(xiàn)呢,可以通systemtap等工具在內(nèi)核打點完成觀察,如果發(fā)現(xiàn)了有sk_stream_wait_memory就認(rèn)為這發(fā)送緩沖區(qū)太小了,需要調(diào)大tcp_wemem:max

        可不可以開發(fā)的時候指定需要發(fā)送的大?。?/p>

        當(dāng)然可以呀,通過setsockopt中的SO_SNDBUF設(shè)置固定的緩沖區(qū)大小。但是設(shè)置了這個參數(shù),tcp_wmem就會失效,也就沒有了動態(tài)調(diào)整,設(shè)置的值不能超過net.core.wmem_max,如果超過了,內(nèi)核會強制設(shè)置為wmem_max。所以通常情況下,我們不會通過SO_SNDBUF設(shè)置TCP緩沖區(qū)的大小,設(shè)置太大浪費內(nèi)存,設(shè)置太小引起緩沖區(qū)不足的問題。

        上面所說的tcp_wmem和wmem_max都是針對單個tcp連接,其單位是字節(jié)。系統(tǒng)中通常有非常多的tcp連接,連接太多可能導(dǎo)致內(nèi)存耗盡

        我們能不能設(shè)置tcp消耗內(nèi)存的大???所謂上限

        tcp_mem

        當(dāng)所消耗的內(nèi)存達(dá)到max就不會再發(fā)包

        可以通過什么方式觀測到這種情況?

        Linux內(nèi)核給我們早就埋了點,sock_exceed_buf_limit。觀察的時候只需要打開tracepoint即可

        sock_exceed_buf_limit

        然后在日志中查看是否發(fā)生了事件

        trace_pipe

        伴隨tcp層數(shù)據(jù)包的處理完畢來到ip層,在IP層需要考慮端口范圍的問題,太小可能導(dǎo)致無法創(chuàng)建連接。

        net.ipv4.ip_local_port_range = 1024

        為了實現(xiàn)tcp/ip數(shù)據(jù)流進(jìn)行流控,Linux內(nèi)核在ip層實現(xiàn)了qdisc(排隊規(guī)則)。我們平時見的比較多的TC即是基于qdisc的流控工具,實際上我們通過ipconfig看到的txqueuelen即qdisc的隊列長度。它太小就會導(dǎo)致數(shù)據(jù)包被丟失

        我們?nèi)绾斡^察到這個現(xiàn)象?

        觀察現(xiàn)象

        如果發(fā)現(xiàn)dropped不為0,則很可能是txqueuelen太小導(dǎo)致,此時就需要調(diào)大這個值

        調(diào)大txqueuelen

        經(jīng)過ip層后就進(jìn)入網(wǎng)卡了,此時需要發(fā)送的數(shù)據(jù)包走完TCP/IP協(xié)議棧

        那么對于接受放而言,是怎么接受的?

        同樣,先看看圖

        TCP數(shù)據(jù)包接受過程

        從上圖可以發(fā)現(xiàn)其接受流程和發(fā)送流程基本相反。當(dāng)數(shù)據(jù)包到達(dá)接受方的網(wǎng)卡,就會觸發(fā)中斷,高速CPU讀取數(shù)據(jù)包,但是在高速網(wǎng)絡(luò)中,大量的數(shù)據(jù)包,如果每來一個數(shù)據(jù)包就觸發(fā)一次中斷勢必讓CPU的處理效率大大折扣,所以提出了NAPI技術(shù),讓CPU一次性輪詢多個數(shù)據(jù)包,通過批量的方式來提升效率,降低中斷帶來的性能開銷

        在poll的時候,一次輪詢多少個?

        這個poll通過sysctl選項控制

        netdev_budget

        此值默認(rèn)大小為300,通常會增加此值到600使得一次性能處理更多的的數(shù)據(jù)包

        可以無限增大此值?

        當(dāng)然不行,系統(tǒng)存在太多進(jìn)程,CPU需要權(quán)衡自己的時間照顧其他的進(jìn)程,如果CPU在poll的時間太多,其他任務(wù)的調(diào)度就會延遲。

        當(dāng)poll了數(shù)據(jù)包就會到IP層處理,隨后到達(dá)tcp層,從而遇到我們之前所說的TCP接受緩沖區(qū)

        默認(rèn)通過tcp_rmem控制緩沖區(qū)的大小,通過適當(dāng)?shù)恼{(diào)整該值來獲取更好的網(wǎng)絡(luò)性能

        tcp_rmem

        TCP的默認(rèn)緩沖區(qū)大小會在min和max之間動態(tài)的調(diào)整,不過和發(fā)送緩沖區(qū)不同的是,這個動態(tài)調(diào)整時通過選項tcp_moderade_rcvbuf。通常我們都會打開它

        tcp_moderade_rcvbuf

        為什么接受緩沖區(qū)時通過選項來自動調(diào)節(jié),而發(fā)送緩沖區(qū)不是

        因為tcp接受緩沖區(qū)會直接影響tcp擁塞控制,從而影響對端的發(fā)包,所以通過選項控制的方式更加靈活的控制對端的發(fā)包行為

        還有其他方式控制tcp的接受緩沖區(qū)?

        當(dāng)然有,可以通過setsockopt()的配置選項SO_RECVBUF控制,如果設(shè)置了此值,那么tcp緩沖區(qū)的自動調(diào)整將關(guān)閉,總之只有當(dāng)tcp_moderate_rcvbuf 為 1,并且應(yīng)用程序沒有通過 SO_RCVBUF 來配置緩沖區(qū)大小的情況下,TCP 接收緩沖區(qū)才會動態(tài)調(diào)節(jié)

        總結(jié):

        TCP/IP協(xié)議棧復(fù)雜無比,此文介紹了很多配置選析,后續(xù)給大家總結(jié)一個常用的參數(shù)表

        好了,這個題目也許啰嗦,但是你會發(fā)現(xiàn)確實有點東西哈,盤它呀,接著面試

        小伙子對這個問題的理解比較深刻,差不多都答在了點上,你說說一致性哈希是什么?

        說一致性哈希是什么,那我們肯定需要告訴面試官為啥要用一致性哈希,直接使用哈希不香?有什么問題嘛?

        我先用個簡單的例子讓大伙看一波為啥使用一致性哈希

        現(xiàn)在我們有一個分布式緩存,需要存放6w張美女照片,別問我干啥,就是存著

        三節(jié)點存儲image

        方案1:直接采用哈希算法,對每個圖片進(jìn)行分片

        哈希

        余數(shù)正好對應(yīng)每個機器節(jié)點

        這樣子會出現(xiàn)什么問題?

        通過哈希算法,每個key可以尋址對應(yīng)服務(wù)器,假設(shè)發(fā)過來的請求為key01,計算公式為hash(key01)%3

        經(jīng)過計算后尋址編號為1的服務(wù)器節(jié)點,如下圖所示

        節(jié)點1服務(wù)器

        此時加入新的服務(wù)器節(jié)點,就會出現(xiàn)路由失敗的情況。此時從三個節(jié)點變化為4個節(jié)點,之前的hash(kley01)%3=1就變化為 hash(key-01) % 4 = X,因為取模運算發(fā)生了變化,所以這個 X 大概率不是 1,這時你再查詢,就會找不到數(shù)據(jù)了,因為 key-01 對應(yīng)的數(shù)據(jù),存儲在節(jié)點 A 上,而不是節(jié)點 B。同樣的道理,如果我們需要下線 1 個服務(wù)器節(jié)點(也就是縮容),也會存在類似的可能查詢不到數(shù)據(jù)的問題

        對于這個問題怎么解決呢

        我們就需要遷移數(shù)據(jù),基于新的計算公式 hash(key-01) % 4 ,來重新對數(shù)據(jù)和節(jié)點做映射。需要注意的是,數(shù)據(jù)的遷移成本是非常高的。

        如何解決這個問題---一致性哈希

        一致性哈希也是使用了取模運算,但是和傳統(tǒng)的取摸運算不同,一致性哈希算法是對2^32 - 1進(jìn)行取模運算

        即使這些數(shù)據(jù)均勻,但是數(shù)據(jù)的活躍度不同,存放熱點數(shù)據(jù)多的節(jié)點訪問量非常大,就很容易的達(dá)到CPU瓶頸。一致性哈希算法即將整個哈希值空間組織成一個虛擬的圓環(huán)---哈希環(huán)

        通過哈希算法,將節(jié)點映射到哈希環(huán)上,通常是節(jié)點主機名,ip地址等如下圖

        哈希環(huán)

        在尋址的過程就只需要兩步

        • 將key作為參數(shù)執(zhí)行c-hash計算出哈希值,確定key在環(huán)的位置

        • 從這個位置沿著哈希環(huán)順時針走,遇到的第一個節(jié)點即key對應(yīng)的節(jié)點

        如下圖所示

        尋址案例

        從上圖可以發(fā)現(xiàn),key01對應(yīng)節(jié)點A,key03對應(yīng)節(jié)點C,如果此時C宕機了,只需要將key03定位到節(jié)點A即可,key01和key02并不需要改變。所以一致性哈希算法在增加和減少節(jié)點的時候,只需要重新定位一小部分?jǐn)?shù)據(jù)而不需要重新定位所有數(shù)據(jù),這樣就實現(xiàn)了"增加/減少節(jié)點需要大規(guī)模遷移"這個問題

        節(jié)點B失效

        如果節(jié)點比較少,是不是很容易就將請求數(shù)據(jù)打到一個節(jié)點呢?

        這個問題即"數(shù)據(jù)傾斜問題",由于節(jié)點的不均勻是的大量你的請求訪問到節(jié)點A上,造成負(fù)載不均衡。

        數(shù)據(jù)傾斜

        鑒于這個問題引入了虛擬節(jié)點,簡單的來說通過增加節(jié)點的個數(shù)來緩解節(jié)點的不均勻現(xiàn)象

        所謂虛擬節(jié)點即對每個服務(wù)器節(jié)點計算多個哈希值,假設(shè)一個真實的節(jié)點有2個虛擬節(jié)點,此時我的三個節(jié)點就共有6個虛擬節(jié)點,如下圖所示

        引入虛擬節(jié)點

        此時如果在環(huán)上順時針尋找虛擬節(jié)點,假設(shè)key01選擇虛擬節(jié)點nodeB02,那么此時將請求映射到真是節(jié)點B即可

        所以通過虛擬節(jié)點擴(kuò)充節(jié)點數(shù)量的方式解決節(jié)點較少情況下數(shù)據(jù)傾斜的問題,代價非常小,只需要增加一個字典map維護(hù)真實節(jié)點和虛擬節(jié)點的映射關(guān)系即可

        • 說說HTTP1.0 1.1 2 3的演進(jìn)

        之前有一篇文章單獨說了這個問題,現(xiàn)在粗略總結(jié)下,希望讀者們再去查查相關(guān)資料

        http/1.1 相對于http/1.0性能上的改進(jìn):

        • http/1.0 采用的是短連接,會有較大的三次握手和四次揮手的開銷

        • 支持管道傳輸,http/1.0 只有第一個響應(yīng)回來才能發(fā)這個請求,但是http/1.1 可以連續(xù)發(fā)送,并不需要等待其回來,減少了整體響應(yīng)時間

        http/1.1 性能瓶頸:

        • 請求/響應(yīng)的頭部沒有經(jīng)改壓縮就發(fā)送,只能壓縮body部分

        • 發(fā)送冗長的首部,每次互相發(fā)送相同的首部造成的浪費較多

        • 服務(wù)器是按順序響應(yīng)的,會出現(xiàn)隊頭擁塞的情況

        • 沒有請求優(yōu)先級控制

        • 請求只能從客戶端開始,服務(wù)器只能被動響應(yīng)

        http/2

        • 采用了HPACK算法避免傳送相同的頭部,并且對頭部數(shù)據(jù)進(jìn)行了壓縮

        • 對傳輸?shù)臄?shù)據(jù)采用二進(jìn)制的方式傳輸,分為頭部幀和數(shù)據(jù)幀

        • 對連接進(jìn)行了復(fù)用,只要訪問同一個域名下的資源,不必進(jìn)行TCP連接的重新建立

        • 支持服務(wù)端push

        • 對于服務(wù)端的響應(yīng)也不會不會出現(xiàn)隊頭擁塞的情況,可以根據(jù)優(yōu)先級進(jìn)行響應(yīng)

        http/3 QUIC

        • 采用了基于UDP的傳輸層協(xié)議,希望取代TCP

        • 仍然也有隊頭阻塞的情況,例如當(dāng)TCP出現(xiàn)丟包重傳時

        • 支持應(yīng)用層級別的重傳,而且在只丟失一個數(shù)據(jù)包的情況下不需要重傳,使用糾錯機制恢復(fù)丟失的包

        • 說說數(shù)據(jù)庫事務(wù)的四大特性

        事務(wù)時一個可執(zhí)行的邏輯單元,該邏輯單元的操作要么都執(zhí)行,要么都不執(zhí)行,事務(wù)具有ACID四個性質(zhì)

        • 原子性:指事務(wù)包含的所有操作,要么都被執(zhí)行成功,如果中間有一條語句失敗,則進(jìn)行回滾。

        • 一致性:指事務(wù)執(zhí)行前和執(zhí)行后都必須處于一致性狀態(tài)

        • 隔離性:事務(wù)之間是相互獨立的,中間狀態(tài)對外是不可見的

        • 持久性:數(shù)據(jù)的修改是永久的

        • 多加索引一定很好嗎

        索引主要用于加速查詢速度,但并發(fā)越多越好,因為索引需要占用物理空間的,且索引的維護(hù)需要時間的,所以如果建索引,一般來說,應(yīng)該查詢的次數(shù)大于插入的次數(shù),同時我們一般只對例如where或者h(yuǎn)aving子句中涉及的字段進(jìn)行設(shè)置索引,因為其它的地方就算建立了索引,一般也用不到,只是浪費。

        • 請問TCP哪些保證了數(shù)據(jù)傳輸?shù)目煽啃?/span>

        序列號、確認(rèn)重傳、超時重傳、擁塞控制(ps 看過我之前文章的小伙伴,問這個問題如果不能扯上一小時,自罰三杯)

        • 三個線程順序打印A-Z

        #include?
        #include?
        #include?
        using?namespace?std;

        char?ch?=?'A'?-?1;

        pthread_cond_t??cond??=?PTHREAD_COND_INITIALIZER;
        pthread_mutex_t?mutex?=?PTHREAD_MUTEX_INITIALIZER;

        void*?print_fun(void?*?args){
        ????int?i?=?*((int*)args);
        ????char?next_ch?=?'A'?+?i;?
        ????while(next_ch?<=?'Z'){
        ????????pthread_mutex_lock(&mutex);
        ????????while(ch?+?1?!=?next_ch)pthread_cond_wait(&cond,?&mutex);
        ????????ch++;
        ????????cout<":"<endl;
        ????????next_ch?=?ch?+?3;
        ????????pthread_mutex_unlock(&mutex);
        ????????pthread_cond_broadcast(&cond);
        ????}
        ????return?nullptr;
        }

        int?main(){

        ????pthread_t?tids[3];
        ????int?pos?=?0;
        ????for(int?i?=?0;?i?3;?++i){
        ????????pthread_create(tids?+?i,?nullptr,?print_fun,?&pos);
        ????????sleep(1);
        ????????pos++;
        ????}
        ????for(int?i?=?0;?i?3;?++i){
        ????????pthread_join(tids[i],?nullptr);
        ????}
        ????return?0;
        }

        5 總結(jié)

        請記下以下幾點:

        • 公司招你去是干活了,不會因為你怎么怎么的而降低對你的要求標(biāo)準(zhǔn)。

        • 工具上面寫代碼和手撕代碼完全不一樣。

        • 珍惜每一次面試機會并學(xué)會復(fù)盤。

        • 對于應(yīng)屆生主要考察的還是計算機基礎(chǔ)知識的掌握,項目要求沒有那么高,是自己做的就使勁摳細(xì)節(jié),做測試,只有這樣,才知道會遇到什么問題,遇到什么難點,如何解決的。從而可以侃侃而談了。

        • 非科班也不要怕,怕了你就輸了!一定要多嘗試。



        原創(chuàng)電子書

        原創(chuàng)思維導(dǎo)圖

        掃碼或微信搜 Java3y?回復(fù)「888」領(lǐng)取1000+原創(chuàng)電子書和思維導(dǎo)圖。

        瀏覽 59
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            久久久裸体视频 | 91黄片 | 小柔被肉干高h潮文不断 | 日本三级全黄三级三级三级口周 | 又粗又长又大又爽的视频 | 欧美伊人综合 | 成人免费看片 视频 | 欧美在线观看爆操 | 我用双乳夹住他的巨大 | 国产偷窥熟女精品大全 |