導航:首頁 > 源碼編譯 > 大廠面試題源碼

大廠面試題源碼

發布時間:2023-09-18 22:36:46

Ⅰ 【面試題解析】從 Vue 源碼分析 key 的作用

最近看了面試題中有一個這樣的題, v-for 為什麼要綁定 key?

Vue 中 key 很多人都弄不清楚有什麼作用,甚至還有些人認為不綁定 key 就會報錯。

其實沒綁定 key 的話,Vue 還是可以正常運行的,報警告是因為沒通過 Eslint 的檢查。

接下來將通過源碼一步步分析這個 key 的作用。

Virtual DOM 最主要保留了 DOM 元素的層級關系和一些基本屬性,本質上就是一個 JS 對象。相對於真實的 DOM,Virtual DOM 更簡單,操作起來速度更快。

如果需要改變 DOM,則會通過新舊 Virtual DOM 對比,找出需要修改的節點進行真實的 DOM 操作,從而減小性能消耗。

傳統的 Diff 演算法需要遍歷一個樹的每個節點,與另一棵樹的每個節點對比,時間復雜度為 O(n²)。

Vue 採用的 Diff 演算法則通過逐級對比,大大降低了復雜性,時間復雜度為 O(n)。

VNode 更新首先會經過 patch 函數, patch 函數源碼如下:

vnode 表示更新後的節點,oldVnode 表示更新前的節點,通過對比新舊節點進行操作。

1、vnode 未定義,oldVnode 存在則觸發 destroy 的鉤子函數

2、oldVnode 未定義,則根據 vnode 創建新的元素

3、oldVnode 不為真實元素並且 oldVnode 與 vnode 為同一節點,則會調用 patchVnode 觸發更新

4、oldVnode 為真實元素或者 oldVnode 與 vnode 不是同一節點,另做處理

接下來會進入 patchVnode 函數,源碼如下:

1、vnode 的 text 不存在,則會比對 oldVnode 與 vnode 的 children 節點進行更新操作

2、vnode 的 text 存在,則會修改 DOM 節點的 text

接下來在 updateChildren 函數內就可以看到 key 的用處。

key 的作用主要是給 VNode 添加唯一標識,通過這個 key,可以更快找到新舊 VNode 的變化,從而進一步操作。

key 的作用主要表現在以下這段源碼中。

updateChildren 過程為:

1、分別用兩個指針(startIndex, endIndex)表示 oldCh 和 newCh 的頭尾節點

2、對指針所對應的節點做一個兩兩比較,判斷是否屬於同一節點

3、如果4種比較都沒有匹配,那麼判斷是否有 key,有 key 就會用 key 去做一個比較;無 key 則會通過遍歷的形式進行比較

4、比較的過程中,指針往中間靠,當有一個 startIndex > endIndex,則表示有一個已經遍歷完了,比較結束

從 VNode 的渲染過程可以得知,Vue 的 Diff 演算法先進行的是同級比較,然後再比較子節點。

子節點比較會通過 startIndex、endIndex 兩個指針進行兩兩比較,再通過 key 比對子節點。如果沒設置 key,則會通過遍歷的方式匹配節點,增加性能消耗。

所以不綁定 key 並不會有問題,綁定 key 之後在性能上有一定的提升。

綜上,key 主要是應用在 Diff 演算法中,作用是為了更快速定位出相同的新舊節點,盡量減少 DOM 的創建和銷毀的操作。

希望以上內容能夠對各位小夥伴有所幫助,祝大家面試順利。

Vue 的文檔中對 key 的說明如下:

關於就地修改,關鍵在於 sameVnode 的實現,源碼如下:

可以看出,當 key 未綁定時,主要通過元素的標簽等進行判斷,在 updateChildren 內會將 oldStartVnode 與 newStartVnode 判斷為同一節點。

如果 VNode 中只包含了文本節點,在 patchVnode 中可以直接替換文本節點,而不需要移動節點的位置,確實在不綁定 key 的情況下效率要高一丟丟。

某些情況下不綁定 key 的效率更高,那為什麼大部分Eslint的規則還是要求綁定 key 呢?

因為在實際項目中,大多數情況下 v-for 的節點內並不只有文本節點,那麼 VNode 的位元組點就要進行銷毀和創建的操作。

相比替換文本帶來的一丟丟提升,這部分會消耗更多的性能,得不償失。

了解了就地修改,那麼我們在一些簡單節點上可以選擇不綁定 key,從而提高性能。

如果你喜歡我的文章,希望可以關注一下我的公眾號【前端develop】

Ⅱ 大廠數據分析面試題,大數據結構化面試

作為程序員,你認為代碼只要實現功能就可以了嗎?
其實,工作2~3年後,你會陪蠢發現隨著工作的深入,工作中遇到的問題會變大,處理的數據量也會變大。
一開始,我可能會耐心加班,等機器處理好了再回家,但最後,處理完這些數據通常是在深夜。
面對這樣的問題,其實可以用數據結構解決。 仔細整理開發中遇到的問題,會發現很多工作中的問題,用簡單的邏輯就能解決。
舉個例子,你很熟悉。 如何實時統計99%的業務介面響應時間?
您可能會首先想到,每次查詢時,都會按照從小到大的順序對所有響應時間進行排序。 如果總共有1200個數據,第1188個數據將有99%的響應時間。
很明顯,每次用這種方法查詢都要排序,效率非常低。
但是,如果知道「堆」數據結構,兩個堆就可以非常有效地解決這個問題。
因此,數據結構是提高我們程序員工作效率的利器!
另外,已經工作了2到3年的你,可能想跳槽進入大工廠。
但是,當你去面試時,你經常會碰到數據結構和演算法的主題。
目前,數據結構和演算法是許多知名企業面試的必考問題。
國內外各大互聯網公司在面試過程中,都多少聽說了一些有關數據結構和演算法的主題。
而且,規模越大的公司,越重視數據結構和演算法。
例如,2019年6月,阿裡面試中涉及的數據結構主題:
2019年華為面試涉及的數據結構主題:
目前,許多中小企業的面試問題都涉瞎盯及數據結構知識。
其實,你會發現,即使是大小公司,為了篩選更優秀的人磨亂和才,面試問題的難度也會越來越大。
因此,數據結構是進入大廠的重要門檻。
總之,如果你想提高工作效率,進入更大的公司,數據結構和演算法是你必須跨越的一道坎。
從易傳傳媒、亞信、奧鵬教育、程序員到架構師再到技術經理樊延欣老師,前後六年通過各種工作方式打好數據結構基礎,在過程中梳理了許多心得,進行了深入思考。
和樊延欣老師一起,死戰數據結構,跳過代碼陷阱,盡快完成數據結構通關,有機會升職更好。
掃描堆場上的二維碼,點擊組,立即搶購
原價69元,限時優惠49元
老師怎麼解釋這門課?#
老師介紹枯燥抽象的結構規則用詳細的方法映射到實際項目中。 然後盡量脫離復雜的數學基礎,在許多常見的應用場合映射相關理論,降低學習者的理解門檻,使其零基礎也能學習。
同時,該課程至少涵蓋了50%常見互聯網公司中數據結構方面的面試問題綱領,序列和棧是基礎性主題,樹是更高級的主題,可以理解和把握,發揮面試信心,更上一層樓
#課程介紹#
#我能得到什麼? #
1、提高編程效率和質量
熟悉數據結構原理,復雜的項目無需為需求實現原理而煩惱。
2、優化能力提升
隨著了解的加深,能夠發現與工作中數據結構特性相違背的代碼,並具有優化修改的能力。
3、提高面試成功率
學習50%以上互聯網公司數據結構的面試問題綱領,提高面試合格率。
#使用者群組#
1、開發業務系統2年,有相關項目經驗,不斷重復製作業務車輪希望提高的程序員。
有2、3~5年開發經驗,但基礎不牢固,想改變體系結構的程序員。
3、基礎扎實,需要大量用例和思考才能鞏固基礎的優秀畢業生/在校生。
#新課初優惠#
限時49元
(成本69 )。
每百人加價十元
第26節課,平均每課2元,持續一個月,改變報關大廠面試機會
享受七折的折扣

自考/成考有疑問、不知道自考/成考考點內容、不清楚當地自考/成考政策,點擊底部咨詢官網老師,免費領取復習資料:https://www.87dh.com/xl/

Ⅲ 把大廠都面試一遍後,我總結了13條面試經驗和面試題(附答案)

近期大大小小面了十幾家公司,花了一點時間整理了14條面試經驗,希望能幫助到你。

1.面試前要認真准備,及時梳理

你會的和面試中你能講清楚完全是兩碼事。不是為了背知識點出去吹牛逼,而是要把自己會的梳理好思路,組織好語言。哪怕幾個月前才做過的項目,如果沒有做項目復盤,突然讓你講,恐怕未必所有細節都能記得清楚。

2.每面完一家一定要復盤

面試完把沒表達好的地方再打磨打磨,一些高頻問題的答案組織好提綱,尤其是關於項目的。現場的答案通常邏輯都會很混亂,筆者自己面到最後,依然感覺很難把項目說出亮點來,畢竟我前東家是外包公司,很多技術點沒機會做得深入。

3.簡歷不是一成不變的,要及時調整

基本每面一家都建議調整一下細節,應聘崗位不同,簡歷所呈現的重點也應不同,所以針對投遞的職位,簡歷要做不同程度的優化。比較心儀的崗位需要根據崗位描述有偏向性地單獨准備簡歷。這樣通過率才會更高,在面試中也會讓你過面試官更容易抓到你與該崗位的契合點。

4.不要把內推想的太神奇,除非你有夠硬的關系。

對大部分人而言,內推的作用就是過簡歷關,其他方面的作用我不太好評估,每個人的資源不一樣。你拿Offer了,內推人拿推薦獎金,你面掛了,推薦人也不會怎麼樣,打鐵還需自身硬,當然這只是自己的看法。

5.控制自己的面試節奏,否則可能會非常辛苦。

每個公司的面試節奏不一樣,可以提前找HR問清楚,比如阿里就是平均一個崗位要面一個月,而滴滴我當時早晨一面下午二面,2天後就三面了,進度很快。筆者面試中節奏安排基本是錯亂的,中間有幾天平均每天1.5個電話面,真的很考驗體能。建議綜合調研一下可以投的崗位,按照【保底】【滿意】【挑戰】三個檔拉開梯度投簡歷,畢竟你最後只能選一個,都投到一個檔次里意義不大。

6.謹慎面對各大招聘軟體上的邀約

招聘軟體上會有很多人問你要簡歷,他們並不是真的對你感興趣,只是群發消息,建議不要隨便給簡歷,很嚇人的。筆者自己第一個螞蟻金服的面試,就是招聘軟體里對方說「先看一下簡歷」,結果轉手就給內推了,當時沒有經驗,完全不知道面的什麼部門什麼要求,也不知道面試預約了還可以推掉,結果趕鴨子上架第一個面試一面就栽了,面評表上吃了個很難看的差評,很影響心情。

7.面試中對待不同的面試官要有好的心態

不要把人想的太壞,也不要把人想的太好,想讓你過的會幫你找亮點,讓你有闡述的機會,不想讓你過的就會盯著你不會的點一直問,隨時等著放大你任何一個漏洞,面試的過程中你會遇到各種各樣的人,當成一種閱歷,不卑不亢就好。給我印象比較深刻的是政采雲的技面官,花名堂主,面試之餘給了我很多忠告和指點,受益匪淺。

8.在面試過程中盡量不要話太多

每個面試官喜好不同,有的人希望你不知道的就說不知道,有的人希望聽你的思路和推測,我自己在面試中,有的面試官就說「不知道沒關系,你可以講講思路,或者如果讓你來做,你會怎麼做」,也有的面試官開場就說「我問的每個點你簡單陳述就行,如果我感興趣就會自己展開問」,在不明確對方偏好的情況下,建議話少點,說的越多漏洞越多,也容易碰到雷區引起反感。

9.簡歷盡量投給HR和你認識的搞技術的朋友

這樣即便最終沒有通過,也大概能知道問題出在哪,原則上面評結果是保密的,但是可以拜託對方針對自己的不足點提供一些關鍵信息,以便明確下一步努力的方向,面試從來都不是一次決定最終結果的事情,一次栽了,再面其他的就行,如果真的非常嚮往某個公司或崗位,過一兩年再來就行了,重點是你要先敢面。如果簡歷給到獵頭,那麼當你面對同等資歷的競爭者時可能就會被Pass,因為如果招了你,是需要給獵頭付費的,如果簡歷給了不認識的人內推,極有可能後續什麼消息都打聽不到,干著急。

10.我強烈建議大家去嘗試參加面試

定期去了解大廠的技術動向和對於你這個水平的面試者的評定條件,每個廠都不一樣,你的學校、專業技術、工作履歷、工作年限、項目管理經驗等等都可能被作為指標,尤其是像筆者這種半路出家的野路子碼農,千萬不要用網上那些經驗往自己身上套,差別太大了。很多人都會覺得自己「水平差」,感覺自己「啥都不會」,但是自己感覺自己差和面試中被人吊打完全是兩種感覺,後者雖然不好受,但能迫使你做出改變,走出舒適區。

11.面試是一場匹配游戲

不是你越牛逼結果就越理想,面試的關鍵詞是【匹配】。大多數面試者都是劣勢的一方,請對自己好點,通過了,告訴自己"運氣不錯,繼續努力,要對得起別人的賞識",沒過,也沒關系,告訴自己"運氣不太好,繼續努力就好,總有一天會有人賞識"。對面試中暴露出的技能短板要足夠重視,但對於結果,真的沒必要太較真,有時候公司的想法並沒有那麼復雜,就是想招個更年輕更便宜的而已。

12.大廠對於大齡程序員是有「把控」的,不管招聘方承不承認。

13.一定要做一個有亮點的程序員

無論是什麼,一定得有跟普通應聘者不一樣的地方,可能是業務梳理能力,資源協調能力,跨端開發,跨棧開發,或者某個專項的技術玩的很溜都可以,但一定得有,如果還沒有,那就開始培養一個。

你近期面試了嗎?歡迎在評論區一起討論,我這里整理的一些大廠面試資料(附答案)可免費提供,添加QQ群:1020139748  備注即可。

java面試題,請大家幫忙看一下,請排列下列源代碼順序,完成枚舉定義:

public enum Signal {

YELLOW, BLUE, RED {
public String info() {
return "Stop";
}
};
public String info() {
return "Signal Data";
}

}

B和E答案有誤。。。。
兩個答案是一樣的。。。
其中有一個應該是};
後面有個分號。。。

假設B.}; E.}
那麼排序結果應該是: DCBAE

希望能幫到你。。。。仍有問題可以HI我。。。

Ⅳ 2022史上最全android面試題歸納匯總(附答案解析)

我經歷過這么多年的摸爬滾打,面試過也被面試過。現總結與歸納Android開發相關面試題:

1、Activity啟動模式有哪些,分別有什麼不同?

2、Service啟動模式有哪些,對應的生命周期?IntentService呢?

3、ContentProvider的作用,是否支持多線程和多進程

4、Broadcast的注冊方式,對應的生命周期是什麼,有序和無序那種可以中斷廣播?

5、AsyncTask的作用,如何使用(包括有哪些方法,能說出同步非同步,能說出不同Android版本下的區別加分)

6、有哪些非同步的方式?

7、Handler機制

8、Dialog的使用及其生命周期

9、Activity的生命周期,能否改?

10、Fragment的生命周期,能否改?

11、Activity和Fragment如何通信

12、View的繪制機制

13、View的事件傳遞機制

14、如何監聽手勢

15、ImageView設置圖片顯示有哪幾種模式,有什麼區別?

16、有哪些存儲方式

17、SharedPreferences是否支持多進程、多線程

別看以上常問的是入門級的,但是有兩三年開發經驗能回答圓滿的人不多。

1、如何理解Activity的任務親和性

2、如何讓Service為單獨的進程

3、IntentService的實現原理

4、LocalBroadcast的作用,實現原理,相對於Broadcast的優勢在哪,劣勢在哪

5、Handler的缺點,會不會造成內存泄漏,有則如何解決

6、Fragment與Activity的區別和聯系

7、Fragment如何緩存布局

8、Fragment與ViewPager的搭配使用,有沒有問題重疊問題,怎麼解決

9、同時提供側滑和上下滑動,如何解決事件傳播問題

10、是否使用過Design包

11、嵌套滑動理解

12、behavior的原理

13、對設計模式有什麼看法,經常使用的有哪些?

中級的稍微偏底層一些,這個主要考察平時是否關注而不是一味地懟業務需求

1、Activity的啟動過程

2、Service創建為單獨進程會有哪些問題?

3、簡述AIDL的構建過程

4、IPC機制有哪些?

5、android多進程通信方式,內部原理

6、App啟動的入口在哪?

7、LRU緩存演算法

8、Bitmap的有哪幾種壓縮演算法,有啥區別?

9、圖片在手機本地存儲大小和在內存大小是否一致,為什麼,Android默認像素一般占幾個位元組?

10、第三方框架的熟練程度,如:

11、SharedPreference內部實現原理

12、模塊化、插件話、組件化等分別有什麼區別,對用有什麼好處

13、說說MV * 模式,並畫出做過項目的架構圖

14、對跨平台方案有哪些了解,使用過哪些? 比如RN

15、對大前端有什麼看法,了解多少?使用過什麼?

16、對其他語言的了解,kotlin,pythonphp、c++等

17、興趣愛好是什麼?對未來有什麼規劃?

目前是一些經常會被問到的,當然只是列舉了Android 開發方向的,Java的一些還沒列舉,比如異常、網路、多線程、JCF等等

以上問題的答案在下面都有詳細解答,我們不僅整理了這些資料,而且還有一份長達"635頁"的Android資料匯總:

包括:底層原理+項目實戰+面試專題

雖說Android早已不像過去那般火爆,但各大廠對於中高級開發者仍舊是求賢若渴,想要獲取更豐厚的薪資,打鐵還得自身硬。對於框架、源碼、原理、項目實操經驗,都必須有足夠的知識儲備,才可以在面試中擊敗面試官。但是由於網上的資料魚龍混雜,也不成體系,很多人在自我提升的過程中都頭疼不已。 這里就給大家分享一份位元組大佬整理的《Android中高級面試題匯總(2022)》,幫助大家系統的梳理中高級Android知識!裡麵包含了所有Android面試的知識點,刷完進大廠妥妥的

(含:靜態內部類和非靜態內部類的比較,多態的理解與應用, java方法的多態性理解,java中介面和繼承的區別,線程池的好處,詳解,單例,線程池的優點及其原理,線程池的優點,為什麼不推薦通過Executors直接創建線程池,創建線程或線程池時請指定有意義的線程名稱,方便出錯時回溯,深入理解ReentrantLock與Condition,Java多線程:線程間通信之Lock,Synchronized 關鍵字原理,ReentrantLock原理,HashMap中的Hash沖突解決和擴容機制, JVM常見面試題, JVM內存結構,類載入機制/雙親委託…)

(含:Activity知識點, Fragment知識點, Service知識點, Intent知識點…)

(含:屏幕適配,主要控制項優化,事件分發與嵌套滾動…)

(含:MVP架構設計,組件化架構…)

(含:啟動優化,內存優化,繪制優化,安裝包優化…)

(含:開源庫源碼分析,Glide源碼分析,OkHttp源碼分析,Retrofit源碼分析,RxJava源碼分析…)

(含:開源文檔,面試合集…)

Ⅵ 已拿32k小米Android高級開發offer(面試題回顧)

到現在我入職也有一段時間了,這才有空梳理一下當時的面試題。簡單說下我的情況:這是一次比較平常的跳槽,不是什麼逆襲大廠的劇本,只是薪資有所漲幅。

個人經歷不詳說,面試題對大家來說可能更有參考性,本篇先整理小米的面試題,我前後也面了很多個大廠,有空把其他幾個大廠的面試題也總結一下。

Java基礎肯定是少不了要問的,這輪面試Kotlin相對來說是我這些面試中問得比較多的,所以說准備面試還是要面面俱到。

我有點佩服我的記憶力了。這部分涉及到更多的 源碼、原理和優化 方面的問題,Android高級開發需要具備一些什麼能力大家也應該有所衡量了。

最後給大家分享一份 2246頁 Android大廠高頻面試題解析大全 ,基本上把我的面試內容都涵蓋到了: Android、性能優化、Java、Kotlin、網路、插件化、熱修復、模塊化、組件化、增量更新、Gradle、圖片、Flutter等。

這份資料免費提供給大家復習,文末查看領取方式,搞定Android面試這一份肯定夠了。

第一章 Android相關 (源碼分析、性能優化、Framework等)

第二章 性能優化 (GC原理、布局優化、繪制優化、內存優化等)

第三章 Java相關 (四種線程池、JVM、內存管理、垃圾回收、引用等)

第四章 Kotlin相關 (延遲初始化、Reified、Extension Functions、函數等)

第五章 網路相關 (HTTP 知識體系、HttpDns 原理、TCP,UDP,HTTP,SOCKET 之間的區別等)

第六章 插件化&熱修復&模塊化&組件化&增量更新&Gradle

第七章 圖片相關 (圖片庫對比、LRUCache原理、圖片載入原理、Glide等)

第八章 Flutter相關 (Flutter原理、Flutter Hot Reload、Flutter 動態化 探索 、Flutter Platform Channel等)

需要這份資料的朋友私信我【面試題】就可以免費領取。

希望大家都可以把握住每一次自我提升的機會,把每一步都走踏實了,漲薪升職什麼的都會迎你而來。

也歡迎大家和我一起交流Android方面的事情。

Ⅶ 騰訊大佬整理推薦《Android Framework 開發揭秘》突破面試!(附面試寶典)

隨著 Android 開發者越來越多,企業在篩選 Android 程序員時越來越看中一個程序員對於 Android 底層原理的理解和思考。

經常面試的人就知道,現在 Framework 算是面試必問知識點了,比如下面一些大廠面試題:

Framework 為開發應用程序提供了非常多的 API,通過調用特殊的 API 構造 APP,滿足業務上的需求。正因為有了 Framework 層,應用開發才能事半功倍,專注於業務邏輯實現。

這里給大家分享一份由 騰訊大佬整理推薦的《Android Framework 開發揭秘》以及《2022最新Android中高級面試題合集》。

這份1932頁的《2022Android中高級面試題匯總》是總結了2020-2021期間大廠面試中的高頻面試題匯總,其中包括騰訊、位元組、美團、阿里、網路…等一線互聯網大廠。

資料包含: Java基礎、Android基礎、UI控制項、網路通信、架構設計、性能優化、源碼流程…

想要深入學習了解 Framework ,突破面試難關,那麼這兩份《Android Framework 開發揭秘》《2022最新Android中高級面試題合集》一定不要錯過。

Ⅷ 大廠面試題詳解:如何用Redis實現分布式鎖

說一道常見面試題:

一個很簡單的答案就是去使用 Redission 客戶端。Redission 中的鎖方案就是 Redis 分布式鎖得比較完美的詳細方案。

那麼,Redission 中的鎖方案為什麼會比較完美呢?

正好,我用 Redis 做分布式鎖經驗十分豐富,在實際工作中,也 探索 過許多種使用 Redis 做分布式鎖的方案,經過了無數血淚教訓。

所以,在談及 Redission 鎖為什麼比較完美之前,先給大家看看我曾經使用 Redis 做分布式鎖是遇到過的問題。

我曾經用 Redis 做分布式鎖是想去解決一個用戶搶優惠券的問題。這個業務需求是這樣的:當用戶領完一張優惠券後,優惠券的數量必須相應減一,如果優惠券搶光了,就不允許用戶再搶了。

在實現時,先從資料庫中先讀出優惠券的數量進行判斷,當優惠券大於 0,就進行允許領取優惠券,然後,再將優惠券數量減一後,寫回資料庫。

當時由於請求數量比較多,所以,我們使用了三台伺服器去做分流。

這個時候會出現一個問題:

如果其中一台伺服器上的 A 應用獲取到了優惠券的數量之後,由於處理相關業務邏輯,未及時更新資料庫的優惠券數量;在 A 應用處理業務邏輯的時候,另一台伺服器上的 B 應用更新了優惠券數量。那麼,等 A 應用去更新資料庫中優惠券數量時,就會把 B 應用更新的優惠券數量覆蓋掉。

看到這里,可能有人比較奇怪,為什麼這里不直接使用 SQL:

原因是這樣做,在沒有分布式鎖的協調下,優惠券數量可能直接會出現負數。因為當前優惠券數量為 1 的時候,如果兩個用戶通過兩台伺服器同時發起搶優惠券的請求,都滿足優惠券大於 0 每個條件,然後都執行這條 SQL 說了句,結果優惠券數量直接變成 -1 了。

還有人說可以用樂觀鎖,比如使用如下 SQL:

這種方式就在一定幾率下,很可能出現數據一直更新不上,導致長時間重試的情況。

所以,經過綜合考慮,我們就採用了 Redis 分布式鎖,通過互斥的方式,以防止多個客戶端同時更新優惠券數量的方案。

當時,我們首先想到的就是使用 Redis 的 setnx 命令,setnx 命令其實就是 set if not exists 的簡寫。

當 key 設置值成功後,則返回 1,否則就返回 0。所以,這里 setnx 設置成功可以表示成獲取到鎖,如果失敗,則說明已經有鎖,可以被視作獲取鎖失敗。

如果想要釋放鎖,執行任務 del 指令,把 key 刪除即可。

利用這個特性,我們就可以讓系統在執行優惠券邏輯之前,先去 Redis 中執行 setnx 指令。再根據指令執行結果,去判斷是否獲取到鎖。如果獲取到了,就繼續執行業務,執行完再使用 del 指令去釋放鎖。如果沒有獲取到,就等待一定時間,重新再去獲取鎖。

乍一看,這一切沒什麼問題,使用 setnx 指令確實起到了想要的互斥效果。

但是,這是建立在所有運行環境都是正常的情況下的。一旦運行環境出現了異常,問題就出現了。

想一下,持有鎖的應用突然崩潰了,或者所在的伺服器宕機了,會出現什麼情況?

這會造成死鎖——持有鎖的應用無法釋放鎖,其他應用根本也沒有機會再去獲取鎖了。這會造成巨大的線上事故,我們要改進方案,解決這個問題。

怎麼解決呢?咱們可以看到,造成死鎖的根源是,一旦持有鎖的應用出現問題,就不會去釋放鎖。從這個方向思考,可以在 Redis 上給 key 一個過期時間。

這樣的話,即使出現問題,key 也會在一段時間後釋放,是不是就解決了這個問題呢?實際上,大家也確實是這么做的。

不過,由於 setnx 這個指令本身無法設置超時時間,所以一般會採用兩種辦法來做這件事:

1、採用 lua 腳本,在使用 setnx 指令之後,再使用 expire 命令去給 key 設置過期時間。

2、直接使用 set(key,value,NX,EX,timeout) 指令,同時設置鎖和超時時間。

以上兩種方法,使用哪種方式都可以。

釋放鎖的腳本兩種方式都一樣,直接調用 Redis 的 del 指令即可。

到目前為止,我們的鎖既起到了互斥效果,又不會因為某些持有鎖的系統出現問題,導致死鎖了。這樣就完美了嗎?

假設有這樣一種情況,如果一個持有鎖的應用,其持有的時間超過了我們設定的超時時間會怎樣呢?會出現兩種情況:

出現第一種情況比較正常。因為你畢竟執行任務超時了,key 被正常清除也是符合邏輯的。

但是最可怕的是第二種情況,發現設置的 key 還存在。這說明什麼?說明當前存在的 key,是另外的應用設置的。

這時候如果持有鎖超時的應用調用 del 指令去刪除鎖時,就會把別人設置的鎖誤刪除,這會直接導致系統業務出現問題。

所以,為了解決這個問題,我們需要繼續對 Redis 腳本進行改動……毀滅吧,累了……

首先,我們要讓應用在獲取鎖的時候,去設置一個只有應用自己知道的獨一無二的值。

通過這個唯一值,系統在釋放鎖的時候,就能識別出這鎖是不是自己設置的。如果是自己設置的,就釋放鎖,也就是刪除 key;如果不是,則什麼都不做。

腳本如下:

或者

這里,ARGV[1] 是一個可傳入的參數變數,可以傳入唯一值。比如一個只有自己知道的 UUID 的值,或者通過雪球演算法,生成只有自己持有的唯一 ID。

釋放鎖的腳本改成這樣:

可以看到,從業務角度,無論如何,我們的分布式鎖已經可以滿足真正的業務需求了。能互斥,不死鎖,不會誤刪除別人的鎖,只有自己上的鎖,自己可以釋放。

一切都是那麼美好!!!

可惜,還有個隱患,我們並未排除。這個隱患就是 Redis 自身。

要知道,lua 腳本都是用在 Redis 的單例上的。一旦 Redis 本身出現了問題,我們的分布式鎖就沒法用了,分布式鎖沒法用,對業務的正常運行會造成重大影響,這是我們無法接受的。

所以,我們需要把 Redis 搞成高可用的。一般來講,解決 Redis 高可用的問題,都是使用主從集群。

但是搞主從集群,又會引入新的問題。主要問題在於,Redis 的主從數據同步有延遲。這種延遲會產生一個邊界條件:當主機上的 Redis 已經被人建好了鎖,但是鎖數據還未同步到從機時,主機宕了。隨後,從機提升為主機,此時從機上是沒有以前主機設置好的鎖數據的——鎖丟了……丟了……了……

到這里,終於可以介紹 Redission(開源 Redis 客戶端)了,我們來看看它怎麼是實現 Redis 分布式鎖的。

Redission 實現分布式鎖的思想很簡單,無論是主從集群還是 Redis Cluster 集群,它會對集群中的每個 Redis,挨個去執行設置 Redis 鎖的腳本,也就是集群中的每個 Redis 都會包含設置好的鎖數據。

我們通過一個例子來介紹一下。

假設 Redis 集群有 5 台機器,同時根據評估,鎖的超時時間設置成 10 秒比較合適。

第 1 步,咱們先算出集群總的等待時間,集群總的等待時間是 5 秒(鎖的超時時間 10 秒 / 2)。

第 2 步,用 5 秒除以 5 台機器數量,結果是 1 秒。這個 1 秒是連接每台 Redis 可接受的等待時間。

第 3 步,依次連接 5 台 Redis,並執行 lua 腳本設置鎖,然後再做判斷:

再額外多說一句,在很多業務邏輯里,其實對鎖的超時時間是沒有需求的。

比如,凌晨批量執行處理的任務,可能需要分布式鎖保證任務不會被重復執行。此時,任務要執行多長時間是不明確的。如果設置分布式鎖的超時時間在這里,並沒有太大意義。但是,不設置超時時間,又會引發死鎖問題。

所以,解決這種問題的通用辦法是,每個持有鎖的客戶端都啟動一個後台線程,通過執行特定的 lua 腳本,去不斷地刷新 Redis 中的 key 超時時間,使得在任務執行完成前,key 不會被清除掉。

腳本如下:

其中,ARGV[1] 是可傳入的參數變數,表示持有鎖的系統的唯一值,也就是只有持有鎖的客戶端才能刷新 key 的超時時間。

到此為止,一個完整的分布式鎖才算實現完畢。總結實現方案如下:

這個分布式鎖滿足如下四個條件:

當然,在 Redission 中的腳本,為了保證鎖的可重入,又對 lua 腳本做了一定的修改,現在把完整的 lua 腳本貼在下面。

獲取鎖的 lua 腳本:

對應的刷新鎖超時時間的腳本:

對應的釋放鎖的腳本:

到現在為止,使用 Redis 作為分布式鎖的詳細方案就寫完了。

我既寫了一步一坑的坎坷經歷,也寫明了各個問題和解決問題的細節,希望大家看完能有所收獲。

最後再給大家提個醒,使用 Redis 集群做分布式鎖,有一定的爭議性,還需要大家在實際用的時候,根據現實情況,做出更好的選擇和取捨。

原文 https://www.cnblogs.com/siyuanwai/p/16011836.html

閱讀全文

與大廠面試題源碼相關的資料

熱點內容
伺服器如何確認有沒有裝系統 瀏覽:490
匯編語言debugg命令 瀏覽:491
買菜app的菜怎麼來的 瀏覽:174
51單片機如何自檢 瀏覽:80
單片機用延時來實現pwm 瀏覽:739
php在線問卷調查 瀏覽:2
java字元串填充 瀏覽:612
c嵌入式編程設計式pdf 瀏覽:791
如何讓安卓手機定時播放音樂 瀏覽:624
學霸教你學cpa什麼app 瀏覽:870
iso系統文件夾最多多大 瀏覽:441
java線程啟動方法是 瀏覽:571
亞洲文件夾 瀏覽:375
python執行linux命令 瀏覽:324
單片機消毒櫃 瀏覽:888
企業伺服器如何選 瀏覽:717
java選課管理 瀏覽:91
程序員疲勞圖片 瀏覽:40
曼哈頓距離和歐式距離python 瀏覽:274
程序員軟考高級哪個好考 瀏覽:309