這個問題是一個面試官問到的
到現在我也沒明白,他具體要問哪個?
有查了一些資料
本來大概也知道舊版的HashMap基本上就是傳統的數組+鏈表的方式實現,
1、對key進行hash算法,取模,比如取模20,那么數組的長度就是20
2、那么如果取模的話一定存在某些key在同一個數組索引中(也稱為同一個桶中),也可以叫hash沖突,這些概念都只是為了幫助理解,沒必要太糾結
那么如何解決hash沖突?就是上面說到的鏈表,桶中將會轉換成鏈表結構
我們可以理解為數組是一個一級索引,鏈表中才是真正的表數據
為什么不直接用全數組的形式:空間問題
缺陷:
1、哈希沖突頻繁情況下,性能問題:可能需要進行重新分配桶
2、鏈表數據量大的情況下,查詢性能的問題
Java8之后增加了紅黑樹的實現,紅黑樹是自平衡的二叉樹,能實現良好的查詢性能,相應的就是解決鏈表數據量大的情況下,查詢性能的問題(單桶數據量大)
那么我們再看看redis,redis中也是有hash的數據類型
由於redis使用的不是java語言,源碼並未過多分析,這邊參考下這個博客:https://blog.csdn.net/mccand1234/article/details/93411326
從這邊來看的,這里采用的應該和舊版的HashMap實現沒有太大差別。
所以我不太明白之前的面試官是挖坑給我,還是另有所指
所以在學習redis的同時,這邊又涉及到一個切片的問題,切片這邊指的是當系統承載的訪問量、數據量越來越多的情況下,單機甚至普通的集群業務分層都無法滿足的情況下,需要進行更細的切分
常用的三種切分方式:
1、取模Hash
2、隨機(適用於消息隊列模式,即不管你往哪一台機子存數據,都有消費者阻塞讀取,消費掉這個數據)
3、一致性Hash
這邊也涉及到了hash算法,所以我也不太清楚是否面試官問的是這個
取模算法理論上和Java的HashMap應該也是差別不大
一致性Hash則有些不同
1、構建一個0~2^32的一個環形空間(邏輯)
2、通過對nodeName或者IP等進行hash函數取值,對應到這個環形空間的某個位置,代表具體的物理節點
3、客戶端訪問的時候對數據也進行一樣的hash函數取值,對應到環形空間的某個位置,注意一般這里不會直接能找到物理節點,而是通過一個順時針或者逆時針的方式來獲取,這也是這個環形空間的存在意義(幫助理解)
存在的問題:
1、新增節點:會對相近的節點造成影響,導致原來指向相近節點的客戶端,被重新指向新節點,造成緩存穿透;但是一般只影響一個節點,且如果只是作為緩存使用(而非數據庫),應該是可以容忍的
2、數據傾斜的問題,數據分布可能會集中到某幾個節點中;這個和HashMap的桶中個別數據量特別大是一樣的道理。解決方式:可以通過一些虛擬節點,來讓環形中的節點更均勻