天天看點

2019秋招複習筆記--實習項目經驗總結

自己做的幾個小項目

以下需要總結整理細節部分

1. 車道線檢測

2. 視訊解壓縮編碼、傳輸等

3. 一個用python做的路徑尋址application

關于三維模型搜尋引擎項目相關度排序算法是怎麼做的:

以文字搜模型:

基于Lucene文本搜尋引擎,查找最比對的;

以圖檔搜模型:

計算圖檔特征,對圖檔特征計算HashCode, 搜尋的時候比對HashCode;

以模型搜模型:

計算模型的特征得到n維特征矩陣, 對特征矩陣計算HashCode, 搜尋的時候比對HashCode;

去重和檢測url有效性是怎麼做的:

對外網資料去重:

一開始直接使用條件逐個字段比較判斷是否重複;

後來對關鍵字段連接配接建立聯合哈希值儲存,用這個哈希值去重;

後來想到其實外網的url是唯一的,直接對url建立哈希值來去重;後來設想直接用url哈希之後作為主鍵儲存,建立聚集索引;但是資料量上去了之後速度明顯下降;

現在可以使用的解決方法:

對URL 使用布隆過濾器

有效性檢測比較簡單:

使用java.net 下的類來實作,主要用到了 URL和HttpURLConnection :

剛開始使用openStream()方法,這樣使用倒是可以,但是速度慢;

最後使用了getResponseCode()方法,可以得到請求的響應狀态,該方法傳回一個 int 分别是 200 and 404 如無法從響應中識别任何代碼則傳回 -1, 如果對該url發起的5次請求都沒有應答則認為連結失效;

你的項目用了哪些技術?

Lucene, Solr 

MySQL, 

Redis,

Java多線程

遇到過什麼問題?你是怎麼解決的?

去重的過程經曆了多次疊代:

剛開始直接對記錄逐個字段比較判斷是否重複 ——>然後對關鍵字段建立HashCode作為辨別,對比該Hash字段——>再是對外網URL建立HashCode對比;

有什麼可以改進的地方?

可以對URL使用布隆過濾器做去重;(位圖+多個哈希函數)

使用緩存資料庫來提高并發通路;(緩存穿透(查詢一個資料庫一定不存在的資料),緩存擊穿(一個key非常熱點,在不停的扛着大并發,大并發集中對這一個點進行通路,當這個key在失效的瞬間,持續的大并發就穿破緩存),緩存雪崩(緩存集中過期失效))

使用Elesticsearch來替代Solr(Elasticsearch是分布式的, 不需要其他元件,分發是實時的;solr需要結合依賴其他分布式元件來實作分布式);

鍊路負載導出功能

流程圖:

2019秋招複習筆記--實習項目經驗總結

時序圖1

2019秋招複習筆記--實習項目經驗總結

接上面時序圖

2019秋招複習筆記--實習項目經驗總結
2019秋招複習筆記--實習項目經驗總結

遇到的三個問題:

1. zip檔案下載下傳後不能打開,且檔案大小與HFS上的檔案大小不一緻(比實際檔案要大)

1.懷疑檔案傳輸流的代碼有誤,每次往用戶端送出資料的時候送出的時緩沖區長度而不是真實寫入資料的長度,這樣在檔案傳輸的末尾階段會多傳很多個無效檔案位,導緻檔案大小變大且檔案損壞。

走讀傳輸代碼,發現不是這個原因

2. 在和同僚一起排查的時候,發現沒有将下載下傳檔案的連結加入到伺服器的輸入輸入編碼例外中去。常用的輸入輸出編碼方式時base64, 作用是将一些不可見的字元(如回車、制表符等)編碼乘可見字元,提供糾錯功能,減少資料傳輸錯誤。一般伺服器對用戶端的文本響應要通過輸入輸出編碼。但是檔案傳輸的時候是以二進制進行傳輸的,隻有0,1不存在不可見字元,是以無需輸入輸出編碼,一般檔案較大的情況下作編碼的效率也會降低。且隻在服務端對其編碼而不告知用戶端的解碼的話,用戶端收到的檔案會出錯。

解決方式,将下載下傳連結配置到web.xml的輸入輸出編碼例外(一個filter過濾器)解決了問題。

2. 檔案傳輸部分地代碼複用了之前某個下載下傳的子產品地代碼,在背景檢視日志的時候發現response未送出異常。

說明: 複用的代碼邏輯中對ServletResponse的送出狀态做了判斷,代碼的邏輯是運作到代碼的最後, 如果response的isCommitted()狀态如果是false,則将此異常記錄到日志,錯誤的等級是erro。日志顯示每次下載下傳檔案的時候都會觸發此異常。

經過查找資料,知道:

  • 每個response的預設緩沖區大小是8KB,如果緩沖區滿,則servlet會自動送出, 并将isCommited狀态設定為false;

在測試功能的時候,由于鍊路負載資料不多(隻有不到50條資料),是以生成的鍊路負載報表隻有7KB左右。是以在伺服器向用戶端送出資料的時候,報表的大小不足以觸發緩沖區滿而自動送出的條件。是以isCommited狀态時false, 進而每次下載下傳該資料的時候日志裡都會打上response未送出異常。

備份測試資料庫,然後編寫資料庫腳本循環插入一萬條相同的鍊路負載資料,擴大測試資料大小。在此條件下,日志中的response未送出異常消失。說明正是這個原因導緻了日志記錄的異常。

處理;

進一步檢視Servlet 說明文檔, 發現文檔中有如下說明;

ServletResponse在如下三個條件下會送出緩沖區:

1. 伺服器顯示調用commit函數,會将response的isCommited狀态設為true;

2. 緩沖區已滿的時候, 會将response的isCommited狀态設為true并将緩沖區資料刷向用戶端。此後剩餘的資料操作均使用目前的isCommited狀态,也就是說,如果還有剩餘資料,則繼續填入緩沖區,但不會再對isCommited狀态作任何改變。

3. 會話的最後response将要關閉的時候,tomcat會幫我們将緩沖區剩餘的資料全部刷到用戶端。這個刷資料的過程中如果發現緩沖區的資料未送出,會首先送出資料設定isCommited為true然後再将資料刷到用戶端。

綜上所述,其實我們沒有必要人為的通過檢視resposne的isCommited狀态來判斷服務端的資料是否已經向用戶端送出,進而判斷資料是不是全部傳輸到用戶端。因為在response會話關閉之前,TomCat會自動送出緩沖區資料。這種方式并不能正确的檢測出資料是否已經傳到用戶端。

解決方式,删掉此處檢測response isCommited的邏輯,發現下載下傳異常消失并且下載下傳功能正常使用。

3. 使用lombok包簡化java bean對象代碼(lombok包可以隐藏代碼中的getter setter函數),導緻了某個對象在序列化的時候名稱不正确。

經檢查,發現某個類中的一個布爾類型的成員命名位isFinished, 而在序列化之後存到redis中該成員的名字變成了finished。名稱的改變導緻後續的代碼邏輯都找不到反序列化的結果。

原因:

lombok可以隐藏java bean中的getter setter代碼, 但該代碼依然存在。依賴架構生成的getter、 setter代碼函數命名的邏輯是去掉成員變量開頭的is\get\set等單詞,用剩下的部分和get、set組合成為getter、setter函數的名稱。在序列化的時候,架構也會依賴于getter、setter函數名稱(去掉get、set)來生成相應的序列化結果,這樣在這個過程中就會丢失原有變量isFinished的is,變成了finish。

解決方法:

1. 顯示設定getter、setter方法,寫成getIsFinshed和setIsFinised。

2. isFinished作為java bean的成員變量其命名時不規範的,将這個成員變量改為finished.

項目中時怎麼使用redis的

如流程圖所示,主要作為緩存來使用。使用Redis記錄檔案生成的進度、檔案生成的狀态、以及檔案生成的路徑。website層通過查詢redis可以獲得service層檔案生成的進度,service層通過redis向website層傳達自己檔案生成的進度資訊,進而實作website層和service層的解耦,提高子產品的可擴充能力。比如,如果要新增加一個互斥條件(比如正在解析或者采集負載資料的時候不能導出檔案的狀态),website層和service層可以各自針對這個在redis新增的狀态作相應的處理即可。另外,此處應用redis作緩存還考慮到多線程的情況,如果多個用戶端同時請求生成檔案,則伺服器隻需要向redis 寫入檔案導出狀态,各個用戶端各自分别去redis上讀取檔案生成的進度,而不需要service層一一的去相應。

TALK IS CHEAP, SHOW ME THE CODE