感謝數(shù)字馬力收留,再也不想面試了??!

你好,我是Guide。最近,圈子里一個(gè)詞的討論度很高——大廠“內(nèi)包”。

像螞蟻的“數(shù)字馬力”、騰訊的“騰訊云智”,這些由大廠100%控股的子公司,就是典型的例子。它們是大型企業(yè)為了解決傳統(tǒng)外包帶來的數(shù)據(jù)安全、協(xié)同管理和成本問題,而催生出的新用工形態(tài)。

雖說名為“內(nèi)包”,但它們的整體待遇通常優(yōu)于大部分中小廠,且面試難度往往不低。

下面是一位球友分享的數(shù)字馬力面經(jīng),這是他面試了很多家公司拿到的唯一 offer。他直言,身心俱疲,再也不想經(jīng)歷面試了。

為了方便大家學(xué)習(xí)參考,我為其中的面試題補(bǔ)充了詳盡的參考答案。

概覽:

image.png

自我介紹

面試時(shí)的自我介紹,其實(shí)是你給面試官的“第一印象濃縮版”。它不需要面面俱到,但要精準(zhǔn)、自信地展現(xiàn)你的核心價(jià)值和與崗位的匹配度。通??刂圃?1-2 分鐘內(nèi)比較合適。一個(gè)好的自我介紹應(yīng)該包含這幾點(diǎn)要素:

  1. 用簡單的話說清楚自己主要的技術(shù)棧于擅長的領(lǐng)域,例如 Java 后端開發(fā)、分布式系統(tǒng)開發(fā);
  2. 把重點(diǎn)放在自己的優(yōu)勢上,重點(diǎn)突出自己的能力,最好能用一個(gè)簡短的例子支撐,例如:我比較擅長定位和解決復(fù)雜問題。在[某項(xiàng)目/實(shí)習(xí)]中,我曾通過[簡述方法,如日志分析、源碼追蹤、壓力測試]成功解決了[某個(gè)具體問題,如一個(gè)棘手的性能瓶頸/一個(gè)偶現(xiàn)的 Bug],將[某個(gè)指標(biāo)]提升了[百分比/具體數(shù)值]。
  3. 簡要提及 1-2 個(gè)最能體現(xiàn)你能力和與崗位要求匹配的項(xiàng)目經(jīng)歷、實(shí)習(xí)經(jīng)歷或競賽成績。不需要展開細(xì)節(jié),目的是引出面試官后續(xù)的提問。
  4. 如果時(shí)間允許,可以非常簡短地表達(dá)對所申請崗位的興趣和對公司的向往,表明你是有備而來。

介紹項(xiàng)目的亮點(diǎn)

當(dāng)你需要向別人(尤其是面試官)介紹項(xiàng)目中的亮點(diǎn)時(shí),我強(qiáng)烈推薦你使用 B-T-A-R 模型來組織思路和語言。

這個(gè)模型能幫你把一個(gè)技術(shù)故事講得既清晰又有條理,還能突出你的能力和貢獻(xiàn)。它包含四個(gè)關(guān)鍵部分:

  • B - Background (項(xiàng)目背景):
    • 做什么: 用一兩句話概括這個(gè)項(xiàng)目是干什么的,它解決了什么業(yè)務(wù)問題,或者滿足了什么用戶需求。
    • 為什么重要: 簡單說明當(dāng)時(shí)的業(yè)務(wù)場景或技術(shù)上下文,讓聽眾明白你接下來要講的亮點(diǎn)是在什么樣的大環(huán)境下產(chǎn)生的。
  • T - Task/Challenge (任務(wù)/挑戰(zhàn)):
    • 遇到什么坎: 具體描述在這個(gè)項(xiàng)目中,你或團(tuán)隊(duì)面臨的最棘手的技術(shù)難題或業(yè)務(wù)挑戰(zhàn)是什么。
    • 鉤子在這里: 這個(gè)問題越具體、越有挑戰(zhàn)性,就越能吸引聽眾的注意力,為后續(xù)你的解決方案做鋪墊。避免泛泛而談,比如“性能優(yōu)化”,要具體到“某個(gè)核心接口在高并發(fā)下響應(yīng)時(shí)間超過 2 秒,無法滿足 SLA 要求”。
  • A - Action (行動(dòng)/方案):
    • 問題分析: 你是如何定位問題根源的?用了什么工具或方法?
    • 方案思考與選擇: 你考慮過哪些備選方案?為什么最終選擇了當(dāng)前這個(gè)方案?(這里可以體現(xiàn)你的技術(shù)視野和權(quán)衡能力)
    • 具體實(shí)施: 你的方案是如何設(shè)計(jì)的?涉及哪些關(guān)鍵技術(shù)點(diǎn)或架構(gòu)調(diào)整?
    • 克服困難: 在實(shí)施過程中遇到了哪些新的問題?你是如何克服的?
    • 你是怎么干的: 這是展示你技術(shù)深度和解決問題能力的核心部分。詳細(xì)說明:
  • R - Result (結(jié)果/成果):
    • 帶來了什么價(jià)值: 用具體、可量化的數(shù)據(jù)來展示你的解決方案所帶來的積極成果。
    • 用數(shù)據(jù)說話: 這是最有說服力的部分。比如:“接口響應(yīng)時(shí)間從平均 2 秒降低到 200 毫秒”、“系統(tǒng)吞吐量提升了 3 倍”、“錯(cuò)誤率降低了 80%”、“為公司節(jié)省了 XX%的服務(wù)器成本”等。
    • 其他影響: 也可以提及一些非量化的積極影響,如“提升了用戶體驗(yàn)”、“增強(qiáng)了系統(tǒng)穩(wěn)定性”、“為后續(xù)業(yè)務(wù)擴(kuò)展打下了基礎(chǔ)”等。

抽象類和接口有什么區(qū)別

  • 設(shè)計(jì)目的:接口主要用于對類的行為進(jìn)行約束,你實(shí)現(xiàn)了某個(gè)接口就具有了對應(yīng)的行為。抽象類主要用于代碼復(fù)用,強(qiáng)調(diào)的是所屬關(guān)系。
  • 繼承和實(shí)現(xiàn):一個(gè)類只能繼承一個(gè)類(包括抽象類),因?yàn)?Java 不支持多繼承。但一個(gè)類可以實(shí)現(xiàn)多個(gè)接口,一個(gè)接口也可以繼承多個(gè)其他接口。
  • 成員變量:接口中的成員變量只能是 public static final 類型的,不能被修改且必須有初始值。抽象類的成員變量可以有任何修飾符(private, protected, public),可以在子類中被重新定義或賦值。
  • 方法
    • Java 8 之前,接口中的方法默認(rèn)是 public abstract ,也就是只能有方法聲明。自 Java 8 起,可以在接口中定義 default(默認(rèn)) 方法和 static (靜態(tài))方法。 自 Java 9 起,接口可以包含 private 方法。
    • 抽象類可以包含抽象方法和非抽象方法。抽象方法沒有方法體,必須在子類中實(shí)現(xiàn)。非抽象方法有具體實(shí)現(xiàn),可以直接在抽象類中使用或在子類中重寫。

在 Java 8 及以上版本中,接口引入了新的方法類型:default 方法、static 方法和 private 方法。這些方法讓接口的使用更加靈活。

Java 8 引入的default 方法用于提供接口方法的默認(rèn)實(shí)現(xiàn),可以在實(shí)現(xiàn)類中被覆蓋。這樣就可以在不修改實(shí)現(xiàn)類的情況下向現(xiàn)有接口添加新功能,從而增強(qiáng)接口的擴(kuò)展性和向后兼容性。

1.png

Java 8 引入的static 方法無法在實(shí)現(xiàn)類中被覆蓋,只能通過接口名直接調(diào)用( MyInterface.staticMethod()),類似于類中的靜態(tài)方法。static 方法通常用于定義一些通用的、與接口相關(guān)的工具方法,一般很少用。

2.png

Java 9 允許在接口中使用 private 方法。private方法可以用于在接口內(nèi)部共享代碼,不對外暴露。

3.png

Java 可變長參數(shù)有什么用?

從 Java5 開始,Java 支持定義可變長參數(shù),所謂可變長參數(shù)就是允許在調(diào)用方法時(shí)傳入不定長度的參數(shù)。就比如下面這個(gè)方法就可以接受 0 個(gè)或者多個(gè)參數(shù)。


4.png

另外,可變參數(shù)只能作為函數(shù)的最后一個(gè)參數(shù),但其前面可以有也可以沒有任何其他參數(shù)。

5.png

可變長參數(shù)的核心價(jià)值在于用一種優(yōu)雅的方式替代了繁瑣的方法重載和不便的數(shù)組傳參,讓代碼更加靈活、簡潔和易讀。它的本質(zhì)是編譯器的語法糖,可變長參數(shù)在編譯后,會(huì)被編譯器自動(dòng)轉(zhuǎn)換成一個(gè)數(shù)組。

Java 基礎(chǔ)面試題匯總可參考筆者寫的這幾篇文章:

索引的優(yōu)缺點(diǎn)

索引的優(yōu)點(diǎn):

  1. 查詢速度起飛 (主要目的):通過索引,數(shù)據(jù)庫可以大幅減少需要掃描的數(shù)據(jù)量,直接定位到符合條件的記錄,從而顯著加快數(shù)據(jù)檢索速度,減少磁盤 I/O 次數(shù)。
  2. 保證數(shù)據(jù)唯一性:通過創(chuàng)建唯一索引 (Unique Index),可以確保表中的某一列(或幾列組合)的值是獨(dú)一無二的,比如用戶 ID、郵箱等。主鍵本身就是一種唯一索引。
  3. 加速排序和分組:如果查詢中的 ORDER BY 或 GROUP BY 子句涉及的列建有索引,數(shù)據(jù)庫往往可以直接利用索引已經(jīng)排好序的特性,避免額外的排序操作,從而提升性能。

索引的缺點(diǎn):

  1. 創(chuàng)建和維護(hù)耗時(shí):創(chuàng)建索引本身需要時(shí)間,特別是對大表操作時(shí)。更重要的是,當(dāng)對表中的數(shù)據(jù)進(jìn)行增、刪、改 (DML 操作) 時(shí),不僅要操作數(shù)據(jù)本身,相關(guān)的索引也必須動(dòng)態(tài)更新和維護(hù),這會(huì)降低這些 DML 操作的執(zhí)行效率。
  2. 占用存儲(chǔ)空間:索引本質(zhì)上也是一種數(shù)據(jù)結(jié)構(gòu),需要以物理文件(或內(nèi)存結(jié)構(gòu))的形式存儲(chǔ),因此會(huì)額外占用一定的磁盤空間。索引越多、越大,占用的空間也就越多。
  3. 可能被誤用或失效:如果索引設(shè)計(jì)不當(dāng),或者查詢語句寫得不好,數(shù)據(jù)庫優(yōu)化器可能不會(huì)選擇使用索引(或者選錯(cuò)索引),反而導(dǎo)致性能下降。

那么,用了索引就一定能提高查詢性能嗎?

不一定。 大多數(shù)情況下,合理使用索引確實(shí)比全表掃描快得多。但也有例外:

  • 數(shù)據(jù)量太小:如果表里的數(shù)據(jù)非常少(比如就幾百條),全表掃描可能比通過索引查找更快,因?yàn)樽咚饕旧硪灿虚_銷。
  • 查詢結(jié)果集占比過大:如果要查詢的數(shù)據(jù)占了整張表的大部分(比如超過 20%-30%),優(yōu)化器可能會(huì)認(rèn)為全表掃描更劃算,因?yàn)橥ㄟ^索引多次回表(隨機(jī) I/O)的成本可能高于一次順序的全表掃描。
  • 索引維護(hù)不當(dāng)或統(tǒng)計(jì)信息過時(shí):導(dǎo)致優(yōu)化器做出錯(cuò)誤判斷。

數(shù)據(jù)庫中哪些字段適合索引優(yōu)化?

  • 被頻繁查詢的字段(WHERE 子句) :我們創(chuàng)建索引的字段應(yīng)該是查詢操作非常頻繁的字段。高選擇性的列效果更好:也就是說,列中不重復(fù)的值越多(比如用戶 ID、訂單號(hào)),通過索引篩選出的數(shù)據(jù)就越少,索引效率越高。像性別這種選擇性很低的列,單獨(dú)建索引效果通常不佳,但可以作為組合索引的一部分。
  • 頻繁需要排序的字段 (ORDER BY 子句) :索引已經(jīng)排序,這樣查詢可以利用索引的排序,加快排序查詢時(shí)間。
  • 被經(jīng)常頻繁用于連接的字段(JOIN ON 子句) :經(jīng)常用于連接的字段可能是一些外鍵列,對于外鍵列并不一定要建立外鍵,只是說該列涉及到表與表的關(guān)系。對于頻繁被連接查詢的字段,可以考慮建立索引,提高多表連接查詢的效率。
  • 盡量選擇非 NULL 且短小的字段
    • 關(guān)于 NULL 值:雖然現(xiàn)代數(shù)據(jù)庫對 NULL 值的索引處理有所改進(jìn),但索引列中包含大量 NULL 值有時(shí)會(huì)影響優(yōu)化器的效率和索引占用的空間(不同數(shù)據(jù)庫處理方式有差異)。如果業(yè)務(wù)允許,并且字段經(jīng)常被查詢,可以考慮用一個(gè)有明確業(yè)務(wù)含義的默認(rèn)值(如 0, 'N/A')代替 NULL。但這不是絕對的,具體情況需具體分析。
    • 短小字段:索引列的值越短,索引本身占用的空間就越小,一次 I/O 能加載的索引項(xiàng)就越多,查詢效率相對更高。例如,用 INT 類型存儲(chǔ)年齡比用 VARCHAR(100) 好。

Redis 如何同時(shí)執(zhí)行多條命令?

當(dāng)我們需要向 Redis 發(fā)送多條命令時(shí),如果一條一條地發(fā)送,每次命令都會(huì)產(chǎn)生一次網(wǎng)絡(luò)往返 (RTT),這在命令數(shù)量很多時(shí)會(huì)非常低效。為了解決這個(gè)問題,Redis 提供了幾種批量執(zhí)行命令的方式,主要是 Pipeline (流水線)Lua 腳本。

Pipeline 允許客戶端將一批 Redis 命令打包起來,一次性發(fā)送給 Redis 服務(wù)器。服務(wù)器收到這些命令后,會(huì)按順序執(zhí)行它們,然后將所有命令的執(zhí)行結(jié)果一次性返回給客戶端。本來 N 條命令需要 N 次網(wǎng)絡(luò)往返,用了 Pipeline 后,理想情況下只需要 1 次(發(fā)送批命令)+ 1 次(接收批結(jié)果)。不過,Pipeline 中的命令是按順序執(zhí)行,但它們不是原子操作。如果在執(zhí)行過程中,有其他客戶端的命令插入進(jìn)來,是可能發(fā)生的(雖然 Redis 單線程模型保證了單個(gè)命令的原子性,但 Pipeline 整體不是)。

6.png

Lua 腳本同樣支持批量操作多條命令。一段 Lua 腳本可以視作一條命令執(zhí)行,可以看作是 原子操作。也就是說,一段 Lua 腳本執(zhí)行過程中不會(huì)有其他腳本或 Redis 命令同時(shí)執(zhí)行,保證了操作不會(huì)被其他指令插入或打擾,這是 pipeline 所不具備的。并且,Lua 腳本中支持一些簡單的邏輯處理比如使用命令讀取值并在 Lua 腳本中進(jìn)行處理,這同樣是 pipeline 所不具備的。

總結(jié)對比:

特性 Pipeline (流水線) Lua 腳本
原子性 非原子 原子
網(wǎng)絡(luò)開銷 顯著減少 RTT 顯著減少 RTT
服務(wù)端邏輯 不支持 支持簡單的條件、循環(huán)等
命令依賴 命令間結(jié)果不能直接用于后續(xù)命令 (客戶端處理) 腳本內(nèi)命令可以依賴前序命令結(jié)果
主要用途 提升批量操作吞吐量 保證多操作原子性,服務(wù)端簡單邏輯處理

緩存擊穿問題注意過嗎?

緩存擊穿中,請求的 key 對應(yīng)的是 熱點(diǎn)數(shù)據(jù),該數(shù)據(jù) 存在于數(shù)據(jù)庫中,但不存在于緩存中(通常是因?yàn)榫彺嬷械哪欠輸?shù)據(jù)已經(jīng)過期)。這就可能會(huì)導(dǎo)致瞬時(shí)大量的請求直接打到了數(shù)據(jù)庫上,對數(shù)據(jù)庫造成了巨大的壓力,可能直接就被這么多請求弄宕機(jī)了。

8.png

緩存擊穿

舉個(gè)例子:秒殺進(jìn)行過程中,緩存中的某個(gè)秒殺商品的數(shù)據(jù)突然過期,這就導(dǎo)致瞬時(shí)大量對該商品的請求直接落到數(shù)據(jù)庫上,對數(shù)據(jù)庫造成了巨大的壓力。

有哪些解決辦法?

  1. 永不過期(不推薦):設(shè)置熱點(diǎn)數(shù)據(jù)永不過期或者過期時(shí)間比較長。
  2. 提前預(yù)熱(推薦):針對熱點(diǎn)數(shù)據(jù)提前預(yù)熱,將其存入緩存中并設(shè)置合理的過期時(shí)間比如秒殺場景下的數(shù)據(jù)在秒殺結(jié)束之前不過期。
  3. 加鎖(看情況):在緩存失效后,通過設(shè)置互斥鎖確保只有一個(gè)請求去查詢數(shù)據(jù)庫并更新緩存。

數(shù)據(jù)庫和緩存面試題匯總可參考筆者寫的這幾篇文章:

分布式下 Session 一致性如何保證

將 Session 數(shù)據(jù)集中存儲(chǔ)在像 RedisMemcached 這樣的分布式緩存系統(tǒng)中。所有服務(wù)器都通過訪問這個(gè)共享緩存來獲取和更新 Session。

這是目前最廣泛使用的方案。

  • 優(yōu)點(diǎn)
    • 高性能:緩存系統(tǒng)基于內(nèi)存操作,讀寫速度非???,能輕松應(yīng)對高并發(fā)的 Session 訪問。
    • 易于水平擴(kuò)展:緩存集群(如 Redis Cluster)可以方便地?cái)U(kuò)展以支持更大的數(shù)據(jù)量和并發(fā)。
    • 相對簡單:很多框架(如 Spring Session)都對這種方式提供了很好的支持,集成方便。
  • 缺點(diǎn)
    • 數(shù)據(jù)可能丟失:如果緩存服務(wù)(如 Redis)宕機(jī)且沒有配置好持久化或高可用方案(如哨兵、集群),可能會(huì)丟失部分 Session 數(shù)據(jù),導(dǎo)致用戶需要重新登錄。不過,通過合理的持久化和集群配置可以大大降低風(fēng)險(xiǎn)。
    • 引入額外依賴:需要維護(hù)一套獨(dú)立的緩存系統(tǒng)。

大量 Excel 導(dǎo)出時(shí)出現(xiàn) OOM 問題,如何解決?

Excel 導(dǎo)出時(shí)發(fā)生 OOM (Out Of Memory) 是個(gè)常見問題,尤其當(dāng)數(shù)據(jù)量非常大的時(shí)候。根本原因在于,很多傳統(tǒng)的 Excel 操作庫會(huì)嘗試 一次性把所有數(shù)據(jù)加載到內(nèi)存中 來構(gòu)建 Excel 文件,數(shù)據(jù)一大,內(nèi)存自然就爆了。

解決這個(gè)問題的核心思路是避免全量數(shù)據(jù)駐留內(nèi)存,采用流式處理或者分批處理的方式。

EasyExcel 是阿里巴巴開源的一個(gè)優(yōu)秀 Java Excel 處理框架,它的核心設(shè)計(jì)理念就是為了解決 OOM 問題。它采用 “邊讀邊寫”的流式處理機(jī)制 ,逐行讀取數(shù)據(jù)并寫入到輸出流,內(nèi)存占用極低,非常適合大數(shù)據(jù)量的導(dǎo)出。FastExcel 可以看作是 EasyExcel 的升級(jí)版或增強(qiáng)版,由原作者在 EasyExcel 停止積極維護(hù)后推出,繼承了其優(yōu)點(diǎn)并在性能和功能上有所提升。

如果你因?yàn)闅v史項(xiàng)目原因或者其他特定需求必須使用 Apache POI,那么一定要用它提供的 SXSSFWorkbook (Streaming Usermodel API) 。SXSSFWorkbook 允許你定義一個(gè)“內(nèi)存窗口大小”(比如,只在內(nèi)存中保留最近的 100 行數(shù)據(jù))。當(dāng)寫入的行數(shù)超過這個(gè)窗口時(shí),最早的行數(shù)據(jù)會(huì)被自動(dòng)刷新(flush)到磁盤上的一個(gè)臨時(shí)文件中,從而釋放內(nèi)存。最后,這些臨時(shí)文件會(huì)被整合成最終的 Excel 文件。

其他建議:

  • 分頁查詢導(dǎo)出:不要一次性從數(shù)據(jù)庫查詢所有數(shù)據(jù)。可以分頁查詢,每次處理一小批數(shù)據(jù),然后通過流式庫寫入 Excel。這可以顯著降低數(shù)據(jù)庫壓力和應(yīng)用服務(wù)器的瞬時(shí)內(nèi)存占用。
  • 按需導(dǎo)出字段:只導(dǎo)出用戶真正需要的列,避免導(dǎo)出不必要的寬表數(shù)據(jù),減少數(shù)據(jù)量。
  • 異步導(dǎo)出與任務(wù)隊(duì)列:對于非常大的數(shù)據(jù)導(dǎo)出,可以將其設(shè)計(jì)成一個(gè)異步任務(wù)。用戶提交導(dǎo)出請求后,后端將任務(wù)放入消息隊(duì)列(如 Kafka, RabbitMQ),由專門的 worker 服務(wù)異步處理導(dǎo)出,完成后再通知用戶下載。這樣可以避免長時(shí)間占用 HTTP 連接,提升用戶體驗(yàn),并且更利于資源控制。

作者:JavaGuide
來源:稀土掘金

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容