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>

        2020校招面試

        共 6612字,需瀏覽 14分鐘

         ·

        2020-09-10 20:02

        個人情況

        • 崗位:后臺 golang 開發(fā)

        • 公司:字節(jié) shopee 拼多多百度阿里快手都有

        • 途徑:提前批內(nèi)推

        • 學(xué)歷:某 985 大三

        • 實習(xí)情況:一段小廠實習(xí)

        • 項目和準(zhǔn)備:實習(xí)時候做的是一個分布式存儲系統(tǒng)以及一個 kv 數(shù)據(jù)庫,這也是面試的重點

        計算機(jī)網(wǎng)絡(luò)

        1,tcp 中 timewait 狀態(tài)的作用,為什么要等待兩個 msl

        2,tcp 中三次揮手開啟連接,四次握手關(guān)閉連接的流程

        3,聊聊 tcp 的滑動窗口

        4,ssl 建立過程

        5,輸入一個 url 的過程

        6,大文件傳輸

        1,答:為了確認(rèn)被動關(guān)閉端接受到最后一個ack,避免主動關(guān)閉端重新在相同端口啟動連接后發(fā)送syn后被動關(guān)閉端認(rèn)為上一個連接沒有完全關(guān)閉,進(jìn)而返回rst終止連接

        2,答:就是那個著名的連接建立圖

        3,答:滑動窗口由接受窗口和擁塞窗口中的最小值,然后就是reno的慢啟動,擁塞控制,快速重傳三個步驟。然后我還談了談cubic算法。

        4,答:很詳細(xì)的描述。從客戶端發(fā)送clienthello包括ssl版本,對稱算法,第一個不重數(shù),mac算法,公鑰算法。重點是一共生成了三個不重復(fù)數(shù),從主密鑰解出了四個密鑰,兩個用于會話加密,兩個用于mac加密。為什么是兩個呢,因為一個用于客戶端到服務(wù)器的會話加密,另一個用于服務(wù)器到客戶端的會話加密。這里要提醒證書機(jī)制并不是完全安全的,因此有EXPECT_CT這個瀏覽器的頭,防止證書頒發(fā)機(jī)構(gòu)被劫持。

        5,答:從dns從瀏覽器,操作系統(tǒng)host文件解析。到http的hsts連接建立過程(302,307等狀態(tài)碼),到瀏覽器緩存etag,以及dom樹和css樹解析,繪圖和渲染,js事件循環(huán)https://juejin.im/post/6844903922084085773。

        6,答:文件分塊。服務(wù)端返回206表示部分?jǐn)?shù)據(jù),416表示范圍出錯。添加一個Range header表示發(fā)送的數(shù)據(jù)的范圍。

        linux io

        首先需要對 linux 五種 io 模型和 epoll 有一定的了解,這里推薦一篇文章https://juejin.im/post/5c725dbe51882575e37ef9ed。

        在傳輸文件的時候,有 sendfile 語意,用于高效的傳輸文件。

        減少了內(nèi)核上下文切換以及 cpu 復(fù)制的損耗。

        這里引用一篇文章https://juejin.im/post/6844903949359644680#heading-17。

        在 go 語言里頭,當(dāng)我們使用 io.copy 的時候,會判斷目標(biāo)是否實現(xiàn) readerFrom 接口。

        如果實現(xiàn)了就會調(diào)用 readerFrom,那么 readerFrom 和普通磁盤 io 的區(qū)別在哪呢?

        // copyBuffer is the actual implementation of Copy and CopyBuffer.
        // if buf is nil, one is allocated.
        func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) {
        // If the reader has a WriteTo method, use it to do the copy.
        // Avoids an allocation and a copy.
        if wt, ok := src.(WriterTo); ok {
        return wt.WriteTo(dst)
        }
        // Similarly, if the writer has a ReadFrom method, use it to do the copy.
        if rt, ok := dst.(ReaderFrom); ok {
        return rt.ReadFrom(src)
        }

        在 go 語言里頭,tcpconn 實現(xiàn)了這個接口。我們會發(fā)現(xiàn)它會用 splice 和 sendfile 兩個系統(tǒng)調(diào)用去獲取數(shù)據(jù)。如果 sendfile 系統(tǒng)也不支持,那么就會做一個優(yōu)雅降級的處理,轉(zhuǎn)換為普通的 io.Copy(隱藏 readerFrom 接口)。

        func (c *TCPConn) readFrom(r io.Reader) (int64, error) {
        if n, err, handled := splice(c.fd, r); handled {
        return n, err
        }
        if n, err, handled := sendFile(c.fd, r); handled {
        return n, err
        }
        return genericReadFrom(c, r)
        }
        普通的磁盤 io 傳輸。

        一,發(fā)起 read 系統(tǒng)調(diào)用,從用戶態(tài)切換到內(nèi)核態(tài)。

        二,cpu 通過控制 dma,將數(shù)據(jù)從硬件緩沖區(qū) copy 到內(nèi)核緩沖區(qū)。再將內(nèi)核緩沖區(qū)的數(shù)據(jù) copy 到用戶緩沖區(qū)。

        三,系統(tǒng)調(diào)用結(jié)束,從內(nèi)核態(tài)切換為用戶態(tài)。

        四,發(fā)起 write 系統(tǒng)調(diào)用,同上。

        整個操作兩次 cpu copy,兩次 dma copy,四次上下文切換,兩次系統(tǒng)調(diào)用。



        sendfile

        一,sendfile 系統(tǒng)調(diào)用,從用戶態(tài)切換到內(nèi)核態(tài)

        二,數(shù)據(jù)從硬件緩沖區(qū)通過 dma copy 復(fù)制到內(nèi)核緩沖區(qū);網(wǎng)卡的硬件緩沖區(qū)直接從磁盤對應(yīng)數(shù)據(jù)的內(nèi)核緩沖區(qū)讀取數(shù)據(jù)

        三,sendfile 調(diào)用結(jié)束,從內(nèi)核態(tài)切換為用戶態(tài)

        整個過程兩次 dma copy,兩次上下文切換,0 次 cpu copy,一個系統(tǒng)調(diào)用。



        socket

        而關(guān)于 tcp 這塊,socket 編程也需要了解,下面我們就來看看 go 中 socket 編程的流程。

        net.dialTcp 是如何包裝 linux 系統(tǒng)調(diào)用的 socket 的。

        客戶端

        • 使用 socket 建立連接

        linux 操作系統(tǒng)把各種 tcp,udp 連接抽象化成 socket,而 go 通過調(diào)用 linux 系統(tǒng)調(diào)用來建立連接。linux 中一切節(jié)文件,SYS_SOCKET 返回的一個數(shù)字就代表著文件的進(jìn)程打開文件描述符的句柄。type 表示 socket 類型,我們建立一個 tcp 連接,就使用的是 SOCK_STREAM,表示一個流式連接;proto 表示協(xié)議,IPPROTO_TCP 表示連接傳輸協(xié)議。domain 表示協(xié)議域,AF_INET、AF_INET6 表示 ip4,ip6 的協(xié)議。

        func socket(domain int, typ int, proto int) (fd int, err error) {
        r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
        fd = int(r0)
        if e1 != 0 {
        err = errnoErr(e1)
        }
        return
        }
        • 將 socket 注冊為 nonblock 和 closeonexec 形式。當(dāng)我們向 socket 讀取數(shù)據(jù)的時候,是從設(shè)備緩沖區(qū)到內(nèi)核緩沖區(qū)再到用戶緩沖區(qū),而 nonblock 會當(dāng)設(shè)備緩沖區(qū)中數(shù)據(jù)沒有準(zhǔn)備好時返回一個 EAGAIN 錯誤。closeonexec 可以參考這篇文章https://blog.csdn.net/ljxfblog/article/details/41680115

        syscall.CloseOnExec(s)
        syscall.SetNonblock(s, true)
        • 在 epoll 注冊 socket。當(dāng)向 socket 寫入數(shù)據(jù)的時候,首先使用系統(tǒng)調(diào)用 write,如果返回 eagain 錯誤,則休眠當(dāng)前 goroutine,等待 epoll 喚醒。

        • 注冊為 nodelay(禁止 nigle 算法)

        • dodialtcp 用于建立一條 tcp 連接,包括本端地址和外目標(biāo)地址。internetsocket 就是完成我們之前所說的事。之后的錯誤處理主要是因為,當(dāng)建立連接時如果沒有源端口,那么就會隨機(jī)選擇一個端口,由于 tcp 能夠同時建立連接;那么很可能出現(xiàn)一條連接,目的端口和接受端口一致而且目的地址和接受地址一樣的情況。我們這里就是為了避免出現(xiàn)這種情況


        func (sd *sysDialer) doDialTCP(ctx context.Context, laddr, raddr *TCPAddr) (*TCPConn, error) {
        fd, err := internetSocket(ctx, sd.network, laddr, raddr, syscall.SOCK_STREAM, 0, "dial", sd.Dialer.Control)

        // TCP has a rarely used mechanism called a 'simultaneous connection' in
        // which Dial("tcp", addr1, addr2) run on the machine at addr1 can
        // connect to a simultaneous Dial("tcp", addr2, addr1) run on the machine
        // at addr2, without either machine executing Listen. If laddr == nil,
        // it means we want the kernel to pick an appropriate originating local
        // address. Some Linux kernels cycle blindly through a fixed range of
        // local ports, regardless of destination port. If a kernel happens to
        // pick local port 50001 as the source for a Dial("tcp", "", "localhost:50001"),
        // then the Dial will succeed, having simultaneously connected to itself.
        // This can only happen when we are letting the kernel pick a port (laddr == nil)
        // and when there is no listener for the destination address.
        // It's hard to argue this is anything other than a kernel bug. If we
        // see this happen, rather than expose the buggy effect to users, we
        // close the fd and try again. If it happens twice more, we relent and
        // use the result. See also:
        // https://golang.org/issue/2690
        // https://stackoverflow.com/questions/4949858/
        //
        // The opposite can also happen: if we ask the kernel to pick an appropriate
        // originating local address, sometimes it picks one that is already in use.
        // So if the error is EADDRNOTAVAIL, we have to try again too, just for
        // a different reason.
        //
        // The kernel socket code is no doubt enjoying watching us squirm.
        for i := 0; i < 2 && (laddr == nil || laddr.Port == 0) && (selfConnect(fd, err) || spuriousENOTAVAIL(err)); i++ {
        if err == nil {
        fd.Close()
        }
        fd, err = internetSocket(ctx, sd.network, laddr, raddr, syscall.SOCK_STREAM, 0, "dial", sd.Dialer.Control)
        }

        if err != nil {
        return nil, err
        }
        return newTCPConn(fd), nil
        }

        服務(wù)器

        • 使用 socket 建立一條連接,使用 listen 將 socket 注冊為 listen 狀態(tài),bind 系統(tǒng)調(diào)用綁定端口

        • 通過 accept 從 socket 接受連接。accept 首先通過系統(tǒng)調(diào)用 accept 等待連接,如果返回 eagain 錯誤則 epoll 等待。如果是 connectaborted 錯誤,則重試。connectionaborted 表示 tcp“三次握手” 后,又發(fā)送了一個 rst 中斷連接。

        • 對于通過 accept 接受到的連接,也僅僅是一個 int 類型的 fd,我們要通過 epoll 包裝連接。

        • 然后設(shè)置 keepalive 為默認(rèn)的 15s 間隔。keepalive 設(shè)置原則可以參考這里https://github.com/golang/go/issues/23459keepcnt 的不同,因此我們將 keepalive 設(shè)置為 15s,在 keepcnt 最大為 9 的 linux 系統(tǒng)上,超時事件為 150s。主要為了適應(yīng)不同操作系統(tǒng)上 < 3min。

        func (ln *TCPListener) accept() (*TCPConn, error) {
        fd, err := ln.fd.accept()
        if err != nil {
        return nil, err
        }
        tc := newTCPConn(fd)
        if ln.lc.KeepAlive >= 0 {
        setKeepAlive(fd, true)
        ka := ln.lc.KeepAlive
        if ln.lc.KeepAlive == 0 {
        ka = defaultTCPKeepAlive
        }
        setKeepAlivePeriod(fd, ka)
        }
        return tc, nil
        }


        學(xué)習(xí)經(jīng)驗

        書籍推薦《計算機(jī)網(wǎng)絡(luò)-自頂向下》。

        一些業(yè)界比較新的算法也要會:cubic,bbr,quic。quic 推薦這篇文章https://zhuanlan.zhihu.com/p/32553477bbr 推薦這篇文章 https://www.jianshu.com/p/08eab499415a。,

        tcp 的一些 option 字段要了解:sack,timestamp。

        關(guān)于學(xué)習(xí) http 中繁瑣的 header,這里推薦使用 chrome 瀏覽器觀察 GitHub 的 http 連接建立的過程,觀察使用了哪些 header,如何使用 cookie 的(ps:可以學(xué)到很多的瀏覽器安全比如 xss 等知識)

        而很多知識比如說 socket 的連接建立其實光看博客很抽象化,最好去看看 go 語言內(nèi)部的源碼。而往往在看 go 源碼的時候又會順藤摸瓜學(xué)習(xí)到很多知識。

        面試經(jīng)驗

        一,一些重要的數(shù)據(jù)結(jié)構(gòu)題還是要背一背的,不然面試官說讓你寫一個堆排序,事實上是讓你寫一個 for 循環(huán)的,考慮到 int 類型溢出的排序,這里沒有提前的準(zhǔn)備,很難當(dāng)場寫好。

        二,有些問題可能你覺得自己專門準(zhǔn)備過,準(zhǔn)備好滔滔不絕顯示能力。但很多時候面試官不喜歡你說的太多,因為說的太多很像背面經(jīng)。。。因此首先要簡略的回答出重點,再看看面試官的反應(yīng)如何,考慮是否需要詳細(xì)的說。

        三,針對項目,要準(zhǔn)備的非常深,詳細(xì)到重要參數(shù)的大小,為什么這樣設(shè)置?當(dāng)然,實際上很多參數(shù)其實也沒有個明確標(biāo)準(zhǔn)。。。比如我做存儲項目的時候,要在一個目錄下存儲很多大文件,然后文件分片成 256kb。。。面試官就問為什么分片成 256kb,為什么不能分片成 4kb 或者 16kb??當(dāng)時就懵了,后面網(wǎng)上查了查,發(fā)現(xiàn)創(chuàng)作者也是照著其他開源軟件的標(biāo)準(zhǔn)設(shè)置的。。。

        四,總有一些問題你從來就沒見過的。遇見不要慌,說回自己熟悉的領(lǐng)域。比如說面試官曾經(jīng)問我 c++ 里頭怎么做 io 隔離?當(dāng)時想了半天也沒弄明白到底什么是 io 隔離,所以我感覺 go 中沒有這個問題。于是我就只好說抱歉我不懂 c++,但我可以談?wù)?go 語言是如何封裝 linux 系統(tǒng)文件系統(tǒng)調(diào)用,我們項目是如何處理文件的讀寫。。。然后在我們這種情況下,應(yīng)該是不存在 io 隔離的問題等等。最后也順利過了面試。

        最后,希望每個 gopher 都能在求職季收獲自己滿意的 offer。


        目前Gopher China大會已開啟。關(guān)于大會商務(wù)合作,請聯(lián)系聯(lián)系司徒小姐姐:18516100522 ??


        關(guān)于大會報名,請點擊“閱讀原文”進(jìn)入活動頁面。但由于目前信息不夠齊備, 也請保持對我們的關(guān)注,后續(xù)會揭開更多驚喜。


        最后,希望每位開發(fā)者永遠(yuǎn)保持不斷提升自己的動力,因為無論外界如何,技術(shù)實力就是我們的底氣。

        瀏覽 130
        點贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

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

        手機(jī)掃一掃分享

        分享
        舉報
        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>
            国产做a爱一级毛片久久黑料网站 | 亚洲高清在线播放 | 学生妹一级 片内射视频 | 在线国产福利视频 | 欧美一色| 老司机伊人网 | www.久操 | 无码人妻精品一区二区三区9厂 | 青青草av在线播放 | 国产成人 免费视频在线观看 |