JAVA面試常問針對性問題精華帖

1.是什麼狀況造成了要從springmvc框架改爲微服務springcloud框架?

可擴展性差,性能提升困難

web應用性能瓶頸基本都在數據庫上。這個系統使用mysql作爲數據庫。三個應用對應三個數據庫。沒有讀寫分離。讀寫都在一個庫上操作。數據量最大的表當時在5000萬條數據。高峯期數據庫操作的QPS在1000左右,壓測結果是可以支撐2000的QPS。這個指標令我詫異。爲什麼能有這麼好的性能?首先是,沒有複雜的查詢邏輯,所有查詢都在一個表裏操作,沒有跨表事務處理,複雜的處理,分解爲多個語句來執行。最複雜的一個action中,執行了將近20次數據查詢。其次,也是最重要的因素,這裏用的是SSD磁盤。從目前情況看,撐到年底應該是可以的,這也爲我們技改爭取了足夠的時間。儘管這樣,對mysql還是沒有把握。每次運營部門搞活動,我們都玩膽戰心驚地盯着,祈禱活動不要太有效果。

從應用層來看,目前讀寫比在10:1,接口日訪問量10億。高峯期訪問量在300QPS。公司業務增長迅猛,數據量半年翻一番,訪問量預估10倍增長。還有一個嚴峻的挑戰,產品同學揚言要搞秒殺,秒殺…每秒十萬的量必須支持到。這就超過MYSQL能承受的壓力範圍,需要把讀操作切到內存數據庫上,但是在SSH架構下,讀寫分離實現就得傷筋動骨了。另外由於Hibernate封裝了對數據庫的操作,不用寫SQL了,精細優化也搞不定了。每次系統變慢,就得求DBA,幫看看有那些SQL被卡住了。每隔一段時間,還得請DBA導出SQL語句,研究怎麼建索引。

系統臃腫,學習週期長

100多個接口,分爲三個大項目。最大項目有1300多個類,其次是600多個和300多個類。SSH架構,SVN版本控制,resin作爲容器,Nginx前置路由。路由這個讓人欣慰,它是整個重構工作的有力支撐。純後端的項目,爲移動端app,PCWEB應用提供接口。這也使得重構工作難度大大降低。如果把前端也耦合進來,那就更酸爽了。

龐大的系統規模爲團隊成員接手帶來困難。 支付業務獨立出來後,開發人員從原來的5人,在2個月內擴充到10人。與此同時,興奮的產品同學也都跟打雞血一樣,各種想法紛紛變爲產品,開發壓力驟增。但是新增的同學,看着幾百個類,往往一片茫然,無法下手。不知道哪些功能實現了,哪些功能是待改進的。一直到3個月後,新員工才逐步進入角色。儘管如此,還是有不少恐龍級代碼,無人敢挑戰。最大的一個類的規模是2000多行, 核心方法超過500行,大量重複代碼, 每次調整都以失敗告終。

合作成本高

隨着項目組人員增加,每次新版本開發都需要多人一起合作,修改同一個項目代碼。 雖然使用版本控制工具來對分支進行管理,但是不可避免的,大量的時間花費在代碼衝突處理上。新增功能,增強功能,bug修復,支持各種客戶端,都在一個項目上進行,需要建立不同的分支,高峯期五六個分支同時進行都是常見的。這種情況下,代碼衝突的頻率非常高。一個周的小版本開發,1天時間在解決衝突都是很正常的。

測試難度大

 

測試工作也逐步的惡化了。

測試環境構建難度高。隨着分支的增加,每個進入測試的分支,都需要準備獨立的測試環境。環境構建成本高。

剛測試完的功能,由於分支合併衝突處理,又得重新跑一遍。嚴重影響項目進度。

上線風險高

 

隨着系統複雜度的增加,上線風險也越來也大。一個小功能的修改,打印一個日誌,修復一個bug,都需要整體上線。一旦有一個地方修改錯了,這個系統就崩潰了。上線時間長,一次上線,半晚上是必須的

 

 

微服務改造優點

在開始支付項目改造之前,我們剛剛完成了公司數據倉庫項目的微服務架構改進。這個項目實施詳細過程,在dockone社區做了分享,詳情參見這裏。 我們認爲調整爲微服務架構可以解決上述問題。

性能問題

對於性能要求高的接口,可以通過建立數據緩存的方式進行優化。

學習週期

一個項目僅包含少數緊耦合的接口,接口的業務邏輯單一,開發人員1-2小時通讀代碼,即可快速上手。

合作成本

每個項目相對獨立,項目之間僅通過接口來交互。確定完接口後,開發、測試、上線,都是獨立進行的,從而降低了溝通成本。

版本控制

由於項目之間是接口依賴而不是代碼依賴,每個項目都可以建立獨立的代碼庫。同時項目切分的比較細,每個項目開發時,僅會有一個開發人員對其做修改。這基本就不存在代碼合併工作,也避免了代碼合併過程中的各種問題。實際上,基於微服務架構的開發,我們並沒有採用分支策略,而是直接用主幹開發。

測試難度

每個項目獨立部署、獨立測試。由於消除了代碼分支,沒有代碼合併的隱患,重複測試的工作量減少了。

上線風險

每個項目獨立上線,就算出現問題了,也僅影響到少數接口。

新技術

在微服務改造進行一個季度後,各種新技術被引入到系統中,開發不再侷限於SSH架構。Spark, Hadoop, Hbase等大數據處理相關的技術,Couchbase, Redis等緩存系統,都開始在項目中使用,並有效地解決的業務上存在的問題。

當然,有利必有弊,微服務帶來的問題,也不少,包括項目多、出問題時排查難等

2 .如何保證大數據流量下用戶登錄信息等數據一致性問題?

使用Redis作爲分佈式緩存,還會涉及緩存一致性、緩存穿透/擊穿、緩存雪崩、熱點數據集中失效等問題。

先刪除緩存中的數據,然後再去更新數據庫,最後更新緩存中的數據
寫請求過來,我們先刪除緩存中的數據,
刪除成功之後,我們再更新數據庫中的數據,此時如果更新數據庫中的數據失敗,則整個寫請求失敗,直接返回,數據沒有發生變化,此時讀請求過來,發現緩存中沒有對應的數據,則會從數據庫中讀取數據,同時將數據寫入到緩存中,此時緩存中的數據和數據庫中的數據都是一樣的, 不存在數據一致性的問題
更新數據庫中的數據之後 ,再來更新緩存中的數據,此時更新緩存中的數據失敗,直接返回,數據庫中的數據是最新的數據,開始讀請求過來,發現緩存中沒有對應的數據,則會從數據庫中讀取數據,同時將數據寫入到緩存中,此時緩存中的數據和數據庫中的數據都是一樣的, 不存在數據一致性的問題
更新緩存成功,此時緩存中的數據和數據庫的數據是一致的,不存在數據一致性的問題

乍一看,這種方案完美的解決了數據一致性的問題,我們不妨再來將業務場景複雜點,併發量再大一點,比如說每秒的讀QPS爲1w+,這是我們再來分析下上述方案的業務邏輯:

用戶寫請求過來,我們還是先刪除緩存,然後再更新數據庫
在更新數據庫的過程中,此時更新還沒有完成,數據庫的值依舊是原來的舊值,這時一個讀請求過來
發現緩存中沒有值,就會到數據庫中去查詢數據,然後寫入到緩存中,此時數據庫還沒有更新結束,讀請求獲取的數據依舊是原來的舊數據
這時數據庫更新完成,但是更新緩存失敗,此時緩存中是用的之前的舊數據與數據庫中的新數據就會出現數據不一致的情況,數據一致性的問題又出現了
 

由此可見,上述的方案也是存在問題的,尤其是併發量很大的情況下,這類現象出現的機率就很大;對於這種情況我們該如何處理呢?

我們仔細分析上述的情況,可以發現,讀請求和寫請求是並行的,這是導致數據一致性的根本原因,並行的請求會導致數據一致性的問題,那麼解決此類問題的思路就有了——將請求串行!

具體的業務邏輯如下:

寫請求過來,將寫請求緩存到緩存隊列中,並且開始執行寫請求的具體操作(刪除緩存中的數據,更新數據庫,更新緩存)
如果在更新數據庫過程中,又來了個讀請求,將讀請求再次存入到緩存隊列中,等待隊列前的寫請求執行完成,纔會執行讀請求
之前的寫請求刪除緩存失敗,直接返回,此時數據庫中的數據是舊值,並且與緩存中的數據是一致的,不會出現緩存一致性的問題
寫請求刪除緩存成功,則更新數據庫,如果更新數據庫失敗,則直接返回,寫請求結束,此時數據庫中的值依舊是舊值,讀請求過來後,發現緩存中沒有數據, 則會直接向數據庫中請求,同時將數據寫入到緩存中,此時也不會出現數據一致性的問題
更新數據成功之後,再更新緩存,如果此時更新緩存失敗,則緩存中沒有數據,數據庫中是新值 ,寫請求結束,此時讀請求還是一樣,發現緩存中沒有數據,同樣會從數據庫中讀取數據,並且存入到緩存中,其實這裏不管更新緩存成功還是失敗, 都不會出現數據一致性的問題

image

發佈了27 篇原創文章 · 獲贊 32 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章