主頁 > 後端開發 > 小林求職記(三)一上來就圍繞電商系統層層提問,我太難了….

小林求職記(三)一上來就圍繞電商系統層層提問,我太難了….

2020-09-25 12:02:57 後端開發

前傳

  面試官:什么是大事務?小林哥:就是 很大...的...事務??

  小林求職記(二):說好的問基礎,為啥我感覺一點也不基礎呢?

 


二面的面試官來到來我的跟前,開始對我的簡歷進行了一番打量然后就開始了技術提問,

面試官: 看了下你在簡歷上邊有寫到過關于電商系統的設計,那我想深入問下你在電商系統設計的幾個問題哈,

小林: 好的,

面試官: 你們電商系統的每天的榷訓量大概在多少呢?

小林: 嗯,榷訓用戶數目在5萬左右,搞促銷活動的時候還會涉及到一些大流量的訪問,

面試官: 嗯嗯,那么接下來我問你幾個系統內部設計的場景吧,

小林: 嗯嗯,(表面風平浪靜,內心還是會有些慌張)

面試官:你剛才提到了促銷活動,那么在搞促銷活動之前,你們應該會有一些特殊的準備吧,能和我講幾個場景的實際案例嗎?

小林: 嗯嗯,我們的商品資訊其實是存盤在mysql里面的,當進行促銷活動的時候需要進行一次預熱作業,將一些熱點資料加載到快取層當中,減少對于實際mysql訪問的壓力,在快取方面我之前一貫都是使用了redis來存盤資料,但是高峰時期對于redis的查詢依然是需要網路消耗,有些特殊的業務場景需要在回圈里面對redis做查詢(老舊代碼的原因,不推薦在作業中這么使用),因此這部分的模塊我加入了本地快取作為優化手段,

面試官: 嗯嗯(就這??)

小林停頓了一會,看面試官似憾訓覺得說得不夠,然后繼續回答接下來的內容點,

小林: 對于一些熱點資料而言,我們的本地快取使用的是Guava Cache 技術,它提供了一個LoadingCache介面供開發者進行快取資料的本地管理,當查詢資料不存在的時候會發生快取命中失效,這時候可以通過定義內部的一些callable介面來實作對應的策略,

ps: 此時小林想起來自己以前剛學習guava cache技術時接觸的代碼:

//這種型別到好處在于 查詢資料的時候,如果資料不存在,那么就需要寫如何從記憶體里加載,每次查詢都需要做一個callable的處理
Cache<Object, Object> cache = CacheBuilder.newBuilder().build();
cache.put("k1","v1");
//如果物件資料不存在,則回傳一個null值
Object v1=cache.getIfPresent("k1");
Object v2 = cache.get("k2",new Callable<Object>(){
    @Override
    public Object call() throws Exception {
        System.out.println("該數值不存在,需要到redis去查詢");
        return "k2";
    }
});
System.out.println(v1);
System.out.println(v2);

 

面試官:如果每次查詢不了資料都需要在get的時候去重寫策略,豈不是很麻煩嗎?(其實面試官也用過這款技術,就是故意深入問問求職者是否有更多的了解內部構造)

小林:嗯嗯,其實可以在定義LoadingCache做一個全域性的callable回呼操作處理,我腦海中還對這段代碼有印象,主要是通過cacheloader來做實作,

ps:此時一段熟悉的代碼模型從小林腦海中閃過,

LoadingCache<String, String> loadingCache = CacheBuilder.newBuilder()
        .build(new CacheLoader<String, String>() {
            @Override
            public String load(String key) throws Exception {
                // 當快取沒有命中的時候,可以通過這里面的策略去加載資料資訊
                System.out.println("快取命中失敗,需要查詢redis");
                return "value"+key;
            }
        });

 

面試官: 嗯嗯,那你對于這些快取演算法有過相關研究嗎?可以講講自己的理解嗎?

小林: 嗯呢,常見的快取佇列可以采用lru演算法,所謂的lru其實本質的核心就在于:最近最久未使用的資料,可能在將來也不會再次使用,因此當快取空間滿了之后就可以將其淘汰掉,簡單的實作思路可以用一條佇列來實作,當陣列中的某個元素存在且再次被訪問的時候就會將其挪到鏈表的首位,如果查詢某些新元素發現在lru佇列里面沒有命中,則需要從db中查詢然后插入到佇列的首部,這樣能夠保持佇列里面的元素大多數場景下都是熱點元素,當佇列的體積占滿了之后,訪問最低頻率的元素就會從隊尾被擠出,

面試官: 嗯嗯,可以再深入講解下lru演算法所存在的弊端嗎?(內心仿佛在說,就這?)

小林求職記(三)一上來就圍繞電商系統層層提問,我太難了....

小林: 嗯嗯,lru演算法其實存在這快取污染的問題,例如說某次批量查詢操作,將一些平時用不到的資料也塞入到了佇列中,將一些真正的熱點資料給擠出了佇列,造成快取污染現象,因此后邊就衍生出來了lru-k演算法,其核心思想是給每個訪問的元素都標識一個訪問次數k值,這類演算法需要多維護一條佇列(暫且稱之為訪問佇列),當資料的訪問次數超過了k次之后,才會從原先的訪問佇列中轉移到真正的lru佇列里面,這樣就能避免之前所說的快取污染問題了,但是采用lru-k演算法其實需要涉及到的演算法復雜度,空間大小遠高于前邊提到的lru演算法,這也是它的一個小”缺陷“吧,

小林求職記(三)一上來就圍繞電商系統層層提問,我太難了....

面試官: 嗯嗯,好的,那關于快取的回收策略你有了解過嗎?

小林: 嗯嗯,我在之前的工程中使用的guava-cache技術就是采用惰性回收策略的,當快取的資料到達過期時間的時候不會去主動回收記憶體空間,而是在當程式有需要主動查詢資料的時候才會去做記憶體回收的檢測等相關操作,之所以不做主動回收的作業,我推測是因為自動回收程式的步驟對于cache自身需要維護的難度較高,所以改成了惰性回收策略,這一點和redis里的惰性回收策略有點類似,這種策略容易造成某些長期不使用的資料一直沒法回收,占用了大量的記憶體空間,

面試官: 嗯嗯,好的,那么這個面試點先到此告一段落吧,我再問下你其他的業務場景,

小林內心漸漸恢復平靜,一開始的那種焦慮和緊張感漸漸地消失了,又恢復了從前的那種淡定和從容,

小林: 好的,

面試官: 你們的訂單業務系統一般是怎么做分表操作的啊?可以介紹一下嗎?

小林

嗯嗯,可以的,我們的訂單表每日的增加數目為5萬條資料左右,一個月左右訂單的資料量就會增加到100萬條左右的資料,因此我們通常每個月都會按照月為單位來做分表操作,在用戶的電商app界面上邊有個訂單查詢模塊,關于那塊的業務我也做過相關的開發,

通常我的訂單查詢的資料都是按照時間順序,先查詢最近的資料,再查詢之前的資料資訊,結合前端做了分頁涉及的功能,會根據前端傳入的月份時間,來識別應該定位在哪張表進行查詢,通常來說近三個月時間內的訂單資料都是一些熱點資料,所以我們將前三個月的資料存在同一張表里面專門做優化,

關于后續幾個月的資料大多數情況下用戶自身并不會涉及到查詢功能,因此我們會定時將資料同步到es資料庫里面,如果后續需要涉及這塊的資料查詢,則走es資料庫,

關于訂單資料如何定時同步到到es這塊,相關的查詢邏輯圖如下所示:

小林求職記(三)一上來就圍繞電商系統層層提問,我太難了....

這里面會有一個job去維護MySQL和ES之間的資料一致性,

面試官: 嗯嗯,那么你們的es和mysql之間是怎么做資料一致性的維護呢?

小林: 我們借助的是阿里的一款開源中間件做資料同步,結合了canal+mysql+rocketmq來進行實作的,

canal會模擬成一臺mysql的slave去接收mysql的master節點回傳的binlog資訊,然后將這些binlog資料決議成一個json字串,再投遞到mq當中,在rocketmq的接收端會做訊息的監聽,一旦有接收到訊息就會寫入到es中,

面試官: 嗯嗯,那么你能簡單講解下在這程序中遇到的困難嗎?

小林: 額,其實這一套環境在我入職的時候就已經搭建好來,我也只是大概知道有這么一個東西,具體的很多細節也并不是很熟悉....

(此時小林的內心再一次流下了沒有技術的眼淚.......)

小林求職記(三)一上來就圍繞電商系統層層提問,我太難了....

面試官似乎有點失望,看了下專案,于是便切換了另一個問題進行詢問,

ps:

當我們使用canal進行binlog監聽的初始化時候,難免需要遇到一些全量同步和增量同步的問題,那么在這個先全量同步再轉換為增量同步的過渡期間該如何做到程式的自動化銜接呢?

關于這塊的設計方案可以參考下mysql內部是如何重建索引樹的思想,

在mysql進行索引樹重建的時候,會將原先表的所有資料都拷貝存入另外一張表,在拷貝的期間如果有新資料寫入表的話,會建立一份redo log檔案將新寫入的資料存放進去,保證整個程序都是online的,因此這也被稱為Online DDL,redo log在這整個程序中就起到了一個類似緩沖池的角色,

同理在使用canal做日志訂閱的時候也可以借助這么一個“緩沖池”角色的幫助,這個緩沖池可以是一些分布式快取,用于臨時接收資料,當全量同步完成之后,進入一個加鎖的狀態,此時將快取中的資料也一同刷入到db中,最后釋放鎖,由于將redis中的資料刷入到磁盤中是個非常迅速的瞬間,因此整個程序可以看作為幾乎平滑無感知,

那么你可能也會有所疑惑,mysql表本身已經有初始化資料了,該如何全量將binlog都發送給到canal呢?其實方法有很多種,binlog的產生主要是依靠資料發生變動導致的,假設我們需要同步的表里面包含了update_time欄位的話,這里只需要更新下全表的update_time欄位為原先值+1 就可以產生出全表的binlog資訊了,

整體的設計思路圖如下:

小林求職記(三)一上來就圍繞電商系統層層提問,我太難了....

(可惜小林平時在作業中沒有對這塊做過多的梳理)

面試官:好吧,你在平時的作業中有遇到過一些jvm調優相關的內容嗎?

小林:嗯嗯,有的,

面試官:哦,太好了,可以講講你是怎么去做jvm調優的嗎?

小林:我們一般都搞不定,遇到jvm堆疊溢位的時候重啟并且增加機器就完事了,

面試官:...... 這確實是一種方案,能不能講些有價值點的思路呢?

小林:嗯嗯,我之前有學習了解到過,Java虛擬機將堆記憶體劃分為新生代、老年代和永久代,

小林求職記(三)一上來就圍繞電商系統層層提問,我太難了....圖片

l通常來講,我們代年輕代物件會被存放在eden區域里面,這塊區域當記憶體占比會相對于survivor區要大一些,大部分當物件在經歷一次Minor GC之后都被銷毀了,剩余當物件會被分入到survivor區里面,然后在survivor區進入新的垃圾回收,當回收當次數超過了閾值之后(默認是15次),物件就會從年輕代中晉升到老年代,當然如果說survivor區中相同年齡的物件體積大小之和大于了survivor區中一半的空間,那么此時物件也會直接晉升到老年代中,哦對了,jdk8

之后還多出來了一個叫做元空間的概念,

小林非常流暢地將自己對于jvm的理解講了出來,感覺自己的這番回答似乎很滿意,可是別小瞧對方面試官,人家畢竟是有過十多年經驗的大佬啊,

小林求職記(三)一上來就圍繞電商系統層層提問,我太難了....

面試官:嗯嗯,能深入介紹下嗎你對于垃圾收集器使用方面的一些經驗總結嗎?

小林:額....這塊就不是很熟系了

ps:

對于 JVM 調優來說,主要是 JVM 垃圾收集的優化,一般來說是因為有問題才需要優化,所以對于 JVM GC 來說,如果當我們發現線上的gc回收頻率變得頻繁之后,就是需要進行jvm調優的時候了,而對于jvm的垃圾回收而言,應該是針對不同的垃圾收集器來做優化調整,

例如說cms垃圾收集器,這塊收集器主要是將jvm分為了年輕代,老年代,在年輕代采用了復制整理演算法,在老年代使用的是標記清除演算法,再其進行標記物件的時候會發生stw的情況,而在jdk9之后,可以看出一定的趨勢,G1回收演算法開始在漸漸占領位置,由于以前的磁區將jvm的各個模塊eden,survivor區都劃分地過大了,因此G1將jvm的區域劃分為了多個零散的region,將原先連續固定的eden區和survivor區給拆解開來分割成多個小模塊,這樣一來垃圾回收的停頓時長就會大大降低,減少stw機制造成的影響,

對于 CMS 收集器來說,最重要的是合理地設定年輕代和年老代的大小,年輕代太小的話,會導致頻繁的 Minor GC,并且很有可能存活期短的物件也不能被回收,GC 的效率就不高,

對于 G1 收集器來說,不是太推薦直接設定年輕代的大小,這一點跟 CMS 收集器不一樣,這是因為 G1 收集器會根據演算法動態決定年輕代和年老代的大小,因此對于 G1 收集器,我們更加需要關心的是 Java 堆的總大小(-Xmx),

面試官: 好吧,那今天的面試就先這樣告一段落吧,

小林: 嗯嗯,我還有機會嗎...

面試官: 我覺得你后邊可以進步和提升的空間還有很大(意思是你太菜了),可以再學習學習哈,

聽完此話后,小林留下了沒有技術的淚水....,唉,看來這個作業還是得繼續找啊....

后來,小林問了下以前大學同學,打探到了新的內推崗位....

小林求職記(三)一上來就圍繞電商系統層層提問,我太難了....

 

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/125393.html

標籤:Java

上一篇:Spring Data R2DBC回應式操作MySQL

下一篇:牛市來了,我勸讀者不要炒股他卻說我不地道...

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more