數據分區?分片?你不想了解嗎?

引言

爲什麼需要數據分區,在我們面臨海量數據的時候,單個節點顯然是無法承受所有數據的存儲以及查詢的,這個時候我們需要將數據拆分,這就是分區.它的定義是這樣的,即:每一條數據只屬於某一個特定的分區,這樣每一個分區都可當做一個完整的數據庫.雖然是這樣,每個節點仍會存有副本以提高容錯性,就類似於一個單主節點的複製.

分區的目的在於提高可擴展性和性能.分區以後一個大數據集就可以分散在更多的機器中,這也使得負載分散開了.而且每個分區是可以執行獨立的查詢的,這樣可以做到跨節點的並行處理,這也就意味着理想情況下集羣的性能是可以線性提升的.

分區的幾種方式

數據分區的重點就是均勻分配,如果可以做到真正意義上的均衡,理論上就是線性的處理能力提升,但是如果負載並不均衡的話,可能會導致一個節點已經達到極限,其他的節點還是空閒狀態,這樣就喪失了我們使用分區的意義了,還有一個很大的缺點就是如何知道特定順序存儲在哪裏?難道一定要把全部節點查詢一遍嗎?

  1. 基於關鍵字:也許叫範圍分區更好,爲每個分區分配一段關鍵字,相當與每個節點都是一個區間,通過加入的數據處於那個區間,我們可以很容易的進行特定數據的查詢.關鍵字當然也不一定是均勻的,因爲其中的數據就可能不是均勻的,具體怎麼分配還是要看數據的分佈.在分區內部還可以按照關鍵字(比如時間戳)進行排序,這樣也可以支持區間查詢,即以關鍵字爲索引.這樣的缺點是是可能使得某些訪問模式會導致熱點查詢,一個系列寫入導致所有的數據都插入了一個分區,這樣使得一個分區是高負荷,其他分區則是空閒的,所以在選擇關鍵字的時候需要仔細考慮,不要已單獨的時間戳爲關鍵字.
  2. 基於哈希值:這是一個非常常見的方式.首先好的哈希函數可以確保數據均勻分佈.我們可以給每一個分區分配一個範圍,哈希值在其範圍內就存儲在這個分區中.這樣當然也有壞處,就是不支持範圍查詢,因爲邏輯上相鄰的數據可能哈希值相差十萬八千里.這樣我們要麼不支持範圍查詢,要麼就把請求發送給所有的節點.Redis的做法是如果一個查詢的數據分配在不同節點,直接拒絕這個語句.基於哈希值的分區最著名的當屬一致性哈希算法了.當然還有Redis集羣使用的哈希槽,他們的本質其實都是一樣的,就是避開了對總結點數的依賴.

當然還有一種折中的算法,就是關鍵字的一部分用於哈希分區,一部分用作在分區內排序,這樣就可以在確定分區以後進行範圍查詢了.

分區與二級索引

二級索引(MySQL中CREATE INDEX一下的那個東西)通常不能唯一標識一條記錄,而是用來加速特定值的查詢,二級索引帶來的主要挑戰是它們不能規整地映射到分區中,因爲索引一般是包含所有已知項的,而這些值此時分佈在多個結點.有兩種主要的方法來支持對二級索引進行分區:基於文檔的分區和基於詞條的分區.說成大白話就是每個結點建立一個索引或者一個大索引分配在不同的結點.

  1. 基於文檔的分區:就是每個分區完全獨立,分別維護自己的分區,這樣在單個分區內可加速查詢,但是如果數據分佈在多個結點的話我們需要向每個結點發出消息,然後在客戶端合併.這種方法也被稱作scatter/gather,確實在範圍查詢的時候可能造成讀的延遲.
  2. 基於詞條的分區:對所有的數據構建全局索引,而不是每個分區維護自己的本地索引.而且,爲了避免成爲瓶頸,不能將全局索引存儲在一個節點上,否則就破壞了設計分區均衡的目標.所以,全局索引也必須進行分區,且可以與數據關鍵字採用不同的分區策略.這樣的優點是在查詢時只需要向包含索引的分區發送讀請求就可以了,缺點也很明顯,就是更新代價很大,可能一個更新涉及到多個節點的更新,這樣使得寫的代價過高.

分區平衡

這個用大白話說就是在新加入節點時如何使得分區平衡.因爲我們的集羣是動態的,所以會在運行中遇到以下問題:

(1)查詢壓力增大,因此需要更多的CPU來處理負載。
(2)數據規模增加,因此需要更多的磁盤和內存來存儲數據。
(3)節點可能出現故障,因此需要其他機器來接管失效的節點。

所以我們需要把數據從一個節點遷移到另外一個節點.但需要滿足以下幾點:

(1)平衡之後,負載、數據存儲、讀寫請求等應該在集羣範圍內更均勻分佈。
(2)再平衡執行過程中,數據庫應該可以繼續正常提供讀寫服務。
(3)避免不必要的負載遷移,以加快動態再平衡,並儘量減少網絡和磁盤I/O影響。

爲了滿足以上要求.有以下集中方法:

  1. 固定數量分區:一致性哈希和哈希槽都使用了這樣的方法,分區不取決於節點數量可以使得在加入新節點的時候可以最少的遷移數據.
  2. 動態分區:使用關鍵字分區時如果邊界設置有問題的,可能使得一個分區的數據超限而其他分區數據很少,這個時候就使用了動態分區這種方法.當分區的數據增加超過一個可配的參數閾值,它就拆分成兩個分區.每個承擔一半的數據量.它的優點是可以自適應配置數據量,當數據少的時候分區也少,當數據多的時候數據是分配在多個節點,且數據都不超過配置值.
  3. 按節點比例分區:也就是每個節點擁有固定數量分區,當一個節點加入集羣的時候對已有的節點數據進行分裂,拿走其中一部分存儲在新加入的節點中,一致性哈希中就是這樣的.

如何找到數據存儲的節點

這是一個問題,因爲數據是動態的,且在前面我們已經分區,我們如何知道該請求哪個節點呢?

  1. 允許發送請求給任何節點,不在的話進行轉發(gossip協議同步數據信息).Redis集羣就是這樣做的.
  2. 將請求發送到一個路由層,類似於代理服務器.其負責轉發請求.ZooKeeper負責更新代理的信息.
  3. 客戶端感知節點和分區的分配關係直接查找.(這樣的話需要分區變化不明顯否則就需要其他工具,比如上面)

redis分區?

寫完這個文章想起了前幾天看到的一個面試題,redis分區的好處?第一次看到這個問題的時候確實是有點懵逼的,我想大家看到這個問題的時候把它當做另一個問題可能會好一點,即redis集羣的好處?畢竟分區某種意義上來說就是分佈式.

參考:
https://thinkwon.blog.csdn.net/article/details/103522351#RedisCPU_705

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章