字節(jié)國際支付十連問
前言
大家好,我是田螺。
之前有位讀者去字節(jié)面試,面的是國際支付部門,他憑記憶,回憶被問到的一些面試真題。于是,我整理了比較全的答案,希望對大家找工作有幫助呀,加油~
1. 聊聊工作中,你是如何設(shè)計數(shù)據(jù)庫表的
- 命名規(guī)范
- 選擇合適的字段類型
- 主鍵設(shè)計合理
- 選擇合適的字段長度
- 優(yōu)先考慮邏輯刪除,而不是物理刪除
- 每個表必備的幾個字段(如create_time和update_time等)
- 一張表的字段不宜過多
- 盡可能使用not null定義字段
- 設(shè)計表時,評估哪些字段需要加索引
- 不需要嚴格遵守3NF,通過業(yè)務(wù)字段冗余來減少表關(guān)聯(lián)
- 避免使用MySQL保留字
- 不搞外鍵關(guān)聯(lián),一般都在代碼維護
- 一般都選擇INNODB存儲引擎
- 選擇合適統(tǒng)一的字符集。
- 如果你的數(shù)據(jù)庫字段是枚舉類型的,需要在comment注釋清楚
- 時間類型選擇恰當
- 不建議使用Stored procedure(包括存儲過程,觸發(fā)器) 。
- 1:N關(guān)系的設(shè)計
- 大字段如何設(shè)計
- 考慮是否需要分庫分表
- 索引的合理設(shè)計
2.什么是三范式?你做過違反三范式的設(shè)計嘛
- 第一范式:對屬性的原子性,要求屬性具有原子性,不可再分解;
- 第二范式:對記錄的唯一性,要求記錄有唯一標識,即實體的唯一性,即不存在部分依賴;
- 第三方式:對字段的冗余性,要求任何字段不能由其他字段派生出來,它要求字段沒有冗余,即不存在傳遞依賴。
我們設(shè)計表及其字段之間的關(guān)系, 應(yīng)盡量滿足第三范式。但是有時候,可以適當冗余,來提高效率
3. TCP的四次揮手?三次揮手行不行
- 第一次揮手(FIN=1,seq=u?),發(fā)送完畢后,客戶端進入FIN_WAIT_1狀態(tài)
- 第二次揮手(ACK=1,ack=u+1,seq =v?),發(fā)送完畢后,服務(wù)器端進入CLOSE_WAIT?狀態(tài),客戶端接收到這個確認包之后,進入FIN_WAIT_2狀態(tài)
- 第三次揮手(FIN=1,ACK=1,seq=w,ack=u+1?),發(fā)送完畢后,服務(wù)器端進入LAST_ACK?狀態(tài),等待來自客戶端的最后一個ACK。
- 第四次揮手(ACK=1,seq=u+1,ack=w+1?),客戶端接收到來自服務(wù)器端的關(guān)閉請求,發(fā)送一個確認包,并進入TIME_WAIT?狀態(tài),等待了某個固定時間(兩個最大段生命周期,2MSL,2 Maximum Segment Lifetime?)之后,沒有收到服務(wù)器端的ACK? ,認為服務(wù)器端已經(jīng)正常關(guān)閉連接,于是自己也關(guān)閉連接,進入CLOSED ?狀態(tài)。服務(wù)器端接收到這個確認包之后,關(guān)閉連接,進入CLOSED狀態(tài)。
TCP為什么需要四次揮手?三次行不行呢?
- 舉個生活的例子吧,假設(shè)小明和小紅打電話聊天,通話差不多要結(jié)束時:
- 小紅說,“我沒啥要說的了”。小明回答,“我知道了”。但是小明可能還有要說的話,小紅不能要求小明跟著自己的節(jié)奏結(jié)束通話,于是小明可能又嘰嘰歪歪說了一通,最后小明說“我說完了”,小紅回答“知道了”,這樣通話才算結(jié)束。
4. 進程線程的區(qū)別,打開迅雷是開了個進程嘛。
- 進程是運行中的應(yīng)用程序,線程是進程的內(nèi)部的一個執(zhí)行序列
- 進程是資源分配的最小單位,線程是CPU調(diào)度的最小單位。
- 一個進程可以有多個線程。線程又叫做輕量級進程,多個線程共享進程的資源
- 進程間切換代價大,線程間切換代價小
- 進程擁有資源多,線程擁有資源少地址
- 進程是存在地址空間的,而線程本身無地址空間,線程的地址空間是包含在進程中的舉個例子:
你打開QQ,開了一個進程;打開了迅雷,也開了一個進程。
在QQ的這個進程里,傳輸文字開一個線程、傳輸語音開了一個線程、彈出對話框又開了一個線程。
所以運行某個軟件,相當于開了一個進程。在這個軟件運行的過程里(在這個進程里),多個工作支撐的完成QQ的運行,那么這“多個工作”分別有一個線程。
所以一個進程管著多個線程。
通俗的講:“進程是爹媽,管著眾多的線程兒子”...
5. 進程是如何通訊的?
進程間的通信方式有這幾種:
- 管道
- 消息隊列
- 共享內(nèi)存
- 信號量
- 信號
每個進程的用戶地址空間都是相互獨立、不能互相訪問的。而內(nèi)核空間則是每個進程都共享的,因此進程之間要通信必須通過內(nèi)核。
- 管道:它的本質(zhì)是內(nèi)核里面的一串緩存。它傳輸數(shù)據(jù)是單向的,這種通信方式效率低,不適合進程間頻繁地交換數(shù)據(jù)。比如我們寫linux?命令時,ps -ef | grep java?這個「|」豎線就是一個匿名管道。
- 消息隊列:它是保存在內(nèi)核中的消息鏈表。消息的發(fā)送方和接收方要約定好消息體的數(shù)據(jù)類型。有了消息隊列,兩個進程之間的通信就像平時發(fā)郵件一樣,你來一封我一封。但是它也有不足,通信不及時,二是附件也有大小限制。
- 共享內(nèi)存:就是拿出一塊虛擬地址空間來,映射到相同的物理內(nèi)存中,節(jié)省了用戶態(tài)與內(nèi)核態(tài)之間切換的開銷。
- 信號量:它其實是一個整型的計數(shù)器,主要用于實現(xiàn)進程間的互斥與同步,而不是用于緩存進程間通信的數(shù)據(jù)。為了防止多進程競爭共享資源,而造成的數(shù)據(jù)錯亂。
- 信號:是進程間通信機制中唯一的異步通信機制,因為可以在任何時候發(fā)送信號給某一進程
- Socket:如果想跨網(wǎng)絡(luò)與不同主機上的進程之間通信,需要socket。
6.什么是零拷貝?零拷貝實現(xiàn)的幾種方式?哪些中間件應(yīng)用了零拷貝技術(shù)?
零拷貝是指計算機執(zhí)行IO操作時,CPU不需要將數(shù)據(jù)從一個存儲區(qū)域復制到另一個存儲區(qū)域,從而可以減少上下文切換以及CPU的拷貝時間。它是一種I/O操作優(yōu)化技術(shù)。
零拷貝實現(xiàn)的方式主要有這三種:
- mmap+write
- sendfile
- 帶有DMA?收集拷貝功能的sendfile
Kafka為什么快等,也跟零拷貝技術(shù)有關(guān)。
我之前寫過一篇零拷貝技術(shù)的文章,收到了很多讀者好評,大家可以看下哈,看一遍就理解:零拷貝詳解
7. 你如何設(shè)計分布式鎖?有哪些坑?
8. Redis跳表
- 跳躍表是有序集合zset的底層實現(xiàn)之一
- 跳躍表支持平均O(logN)?,最壞O(N)復雜度的節(jié)點查找,還可以通過順序性操作批量處理節(jié)點。
- 跳躍表實現(xiàn)由zskiplist和zskiplistNode?兩個結(jié)構(gòu)組成,其中zskiplist?用于保存跳躍表信息(如表頭節(jié)點、表尾節(jié)點、長度),而zskiplistNode則用于表示跳躍表節(jié)點。
- 跳躍表就是在鏈表的基礎(chǔ)上,增加多級索引提升查找效率。
9. 你平時是如何優(yōu)化慢SQL的
數(shù)據(jù)庫慢查詢主要有這些原因
- 如果是SQL沒加索引,那就加恰當?shù)乃饕?/li>
- 如果 SQL 索引不生效,那就關(guān)注索引失效的十種經(jīng)典場景(如不滿足最左匹配原則等)
- 關(guān)注limit深分頁問題(標簽記錄法和延遲關(guān)聯(lián)法)
- 單表數(shù)據(jù)量太大(那就分庫分表)
- join 或者子查詢過多(盡量不要有超過3個以上的表連接,而且關(guān)聯(lián)的字段需要加索引)
- in元素過多 (in元素查詢數(shù)量做限制)
- 數(shù)據(jù)庫在刷臟頁
- order by 走文件排序
- 拿不到鎖
- delete + in子查詢不走索引!
詳細講解,大家可以看下我之前這篇文章哈:盤點MySQL慢查詢的12個原因
10.十億個數(shù)字里里面找最小的10個
這是一道經(jīng)典的TopK問題,可以使用分治法+快速排序原理解決。直接上代碼