欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

MySQL分庫分表詳情

 更新時間:2021年09月24日 15:35:42   作者:消滅知識盲區(qū)  
互聯網項目中常用到的關系型數據庫是MySQL,隨著用戶和業(yè)務的增長,傳統(tǒng)的單庫單表模式難以滿足大量的業(yè)務數據存儲以及查詢,單庫單表中大量的數據會使寫入、查詢效率非常之慢,此時應該采取分庫分表策略來解決。本篇文章主要介紹MySQL分庫分表,需要的朋友可以參考一下

一、業(yè)務場景介紹

假設目前有一個電商系統(tǒng)使用的是MySQL,要設計大數據量存儲、高并發(fā)、高性能可擴展的方案,數據庫中有用戶表。用戶會非常多,并且要實現高擴展性,你會怎么去設計? OK咱們先看傳統(tǒng)的分庫分表方式

當然還有些小伙伴知道按照省份/地區(qū)或一定的業(yè)務關系進行數據庫拆分

OK,問題來了,如何保證合理的讓數據存儲在不同的庫不同的表里呢?讓庫減少并發(fā)壓力?應該怎么去制定分庫分表的規(guī)則?不用急,這不就來了

二、水平分庫分表方法

1.RANGE

第一種方法們可以指定一個數據范圍來進行分表,例如從1~1000000,1000001-2000000,使用一百萬一張表的方式,如下圖所示

在這里插入圖片描述 當然這種方法需要維護表的ID,特別是分布式環(huán)境下,這種分布式ID,在不使用第三方分表工具的情況下,建議使用RedisRedisincr操作可以輕松的維護分布式的表ID。

RANGE方法優(yōu)點: 擴容簡單,提前建好庫、表就好

RANGE方法缺點: 大部分讀和寫都訪會問新的數據,有IO瓶頸,這樣子造成新庫壓力過大,不建議采用。

2.HASH取模

針對上述RANGE方式分表有IO瓶頸的問題,咱們可以采用根據用戶ID HASG取模的方式進行分庫分表,如圖所示:

這樣就可以將數據分散在不同的庫、表中,避免了IO瓶頸的問題。

HASH取模方法優(yōu)點: 能保證數據較均勻的分散落在不同的庫、表中,減輕了數據庫壓力

HASH取模方法缺點: 擴容麻煩、遷移數據時每次都需要重新計算hash值分配到不同的庫和表

3.一致性HASH

通過HASH取模也不是最完美的辦法,那什么才是呢?

使用一致性HASH算法能完美的解決問題

普通HASH算法:

普通哈希算法將任意長度的二進制值映射為較短的固定長度的二進制值,這個小的二進制值稱為哈希值。哈希值是一段數據唯一且極其緊湊的數值表示形式。

普通的hash算法在分布式應用中的不足:在分布式的存儲系統(tǒng)中,要將數據存儲到具體的節(jié)點上,如果我們采用普通的hash算法進行路由,將數據映射到具體的節(jié)點上,如key%n,key是數據的key,n是機器節(jié)點數,如果有一個機器加入或退出集群,則所有的數據映射都無效了,如果是持久化存儲則要做數據遷移,如果是分布式緩存,則其他緩存就失效了。

一致性HASH算法: 按照常用的hash算法來將對應的key哈希到一個具有2^32次方個節(jié)點的空間中,即0~ (2^32)-1的數字空間中?,F在我們可以將這些數字頭尾相連,想象成一個閉合的環(huán)形,如下圖所示。

這個圓環(huán)首尾相連,那么假設現在有三個數據庫服務器節(jié)點node1、node2、node3三個節(jié)點,每個節(jié)點負責自己這部分的用戶數據存儲,假設有用戶user1、user2、user3,我們可以對服務器節(jié)點進行HASH運算,假設HASH計算后,user1落在node1上,user2落在node2上,user3落在user3上

OK,現在咱們假設node3節(jié)點失效了

 user3將會落到node1上,而之前的node1和node2數據不會改變,再假設新增了節(jié)點node4

你會發(fā)現user3會落到node4上,你會發(fā)現,通過對節(jié)點的添加和刪除的分析,一致性哈希算法在保持了單調性的同時,還是數據的遷移達到了最小,這樣的算法對分布式集群來說是非常合適的,避免了大量數據遷移,減小了服務器的的壓力。

當然還有一個問題還需要解決,那就是平衡性。從圖我們可以看出,當服務器節(jié)點比較少的時候,會出現一個問題,就是此時必然造成大量數據集中到一個節(jié)點上面,極少數數據集中到另外的節(jié)點上面。

為了解決這種數據傾斜問題,一致性哈希算法引入了虛擬節(jié)點機制,即對每一個服務節(jié)點計算多個哈希,每個計算結果位置都放置一個節(jié)點,稱為虛擬節(jié)點。具體做法可以先確定每個物理節(jié)點關聯的虛擬節(jié)點數量,然后在ip或者主機名后面增加編號。例如上面的情況,可以為每臺服務器計算三個虛擬節(jié)點,于是可以分別計算 “node 1-1”、“node 1-2”、“node 1-3”、“node 2-1”、“node 2-2”、“node 2-3”、“node 3-1”、“node 3-2”、“node 3-3”的哈希值,這樣形成九個虛擬節(jié)點

例如user1定位到node 1-1、node 1-2node 1-3上其實都是定位到node1這個節(jié)點上,這樣能夠解決服務節(jié)點少時數據傾斜的問題,當然這個虛擬節(jié)點的個數不是說固定三個或者至多、至少三個,這里只是一個例子,具體虛擬節(jié)點的多少,需要根據實際的業(yè)務情況而定。

一致性HASH方法優(yōu)點: 通過虛擬節(jié)點方式能保證數據較均勻的分散落在不同的庫、表中,并且新增、刪除節(jié)點不影響其他節(jié)點的數據,高可用、容災性強。

一致性取模方法缺點: 嗯,比起以上兩種,可以認為沒有。

三、單元測試

OK,不廢話,接下來上單元測試,假設有三個節(jié)點,每個節(jié)點有三個虛擬節(jié)點的情況

package com.hyh.core.test;

import com.hyh.utils.common.StringUtils;
import org.junit.Test;

import java.util.LinkedList;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * 一致性HASH TEST
 *
 * @Author heyuhua
 * @create 2021/1/31 19:50
 */
public class ConsistentHashTest {

    //待添加入Hash環(huán)的服務器列表
    private static String[] servers = {"192.168.5.1", "192.168.5.2", "192.168.5.3"};

    //真實結點列表,考慮到服務器上線、下線的場景,即添加、刪除的場景會比較頻繁,這里使用LinkedList會更好
    private static List<String> realNodes = new LinkedList<>();

    //虛擬節(jié)點,key表示虛擬節(jié)點的hash值,value表示虛擬節(jié)點的名稱
    private static SortedMap<Integer, String> virtualNodes = new TreeMap<>();

    //一個真實結點對應3個虛擬節(jié)點
    private static final int VIRTUAL_NODES = 3;

    /**
     * 測試有虛擬節(jié)點的一致性HASH
     */
    @Test
    public void testConsistentHash() {
        initNodes();
        String[] users = {"user1", "user2", "user3", "user4", "user5", "user6", "user7", "user8", "user9"};
        for (int i = 0; i < users.length; i++)
            System.out.println("[" + users[i] + "]的hash值為" +
                    getHash(users[i]) + ", 被路由到結點[" + getServer(users[i]) + "]");
    }

    /**
     * 先把原始的服務器添加到真實結點列表中
     */
    public void initNodes() {
        for (int i = 0; i < servers.length; i++)
            realNodes.add(servers[i]);
        for (String str : realNodes) {
            for (int i = 0; i < VIRTUAL_NODES; i++) {
                String virtualNodeName = str + "-虛擬節(jié)點" + String.valueOf(i);
                int hash = getHash(virtualNodeName);
                System.out.println("虛擬節(jié)點[" + virtualNodeName + "]被添加, hash值為" + hash);
                virtualNodes.put(hash, virtualNodeName);
            }
        }
        System.out.println();
    }

    //使用FNV1_32_HASH算法計算服務器的Hash值,這里不使用重寫hashCode的方法,最終效果沒區(qū)別
    private static int getHash(String str) {
        final int p = 16777619;
        int hash = (int) 2166136261L;
        for (int i = 0; i < str.length(); i++)
            hash = (hash ^ str.charAt(i)) * p;
        hash += hash << 13;
        hash ^= hash >> 7;
        hash += hash << 3;
        hash ^= hash >> 17;
        hash += hash << 5;

        // 如果算出來的值為負數則取其絕對值
        if (hash < 0)
            hash = Math.abs(hash);
        return hash;
    }

    //得到應當路由到的結點
    private static String getServer(String key) {
        //得到該key的hash值
        int hash = getHash(key);
        // 得到大于該Hash值的所有Map
        SortedMap<Integer, String> subMap = virtualNodes.tailMap(hash);
        String virtualNode;
        if (subMap.isEmpty()) {
            //如果沒有比該key的hash值大的,則從第一個node開始
            Integer i = virtualNodes.firstKey();
            //返回對應的服務器
            virtualNode = virtualNodes.get(i);
        } else {
            //第一個Key就是順時針過去離node最近的那個結點
            Integer i = subMap.firstKey();
            //返回對應的服務器
            virtualNode = subMap.get(i);
        }
        //virtualNode虛擬節(jié)點名稱要截取一下
        if (StringUtils.isNotBlank(virtualNode)) {
            return virtualNode.substring(0, virtualNode.indexOf("-"));
        }
        return null;
    }
}

這里模擬9個用戶對象hash后被路由的情況,看下結果

總結:

分庫分表在分布式微服務架構環(huán)境下建議強烈使用一致性HASH算法來做,當然分布式環(huán)境下也會產生業(yè)務數據數據一致性、分布式事務問題,下期咱們再來探討數據一致性、分布式事務的解決方案

到此這篇關于MySQL分庫分表詳情的文章就介紹到這了,更多相關MySQL分庫分表內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • SQL語句之如何用JOIN連接多個表

    SQL語句之如何用JOIN連接多個表

    這篇文章主要介紹了SQL語句之如何用JOIN連接多個表,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • Mysql DBA 20天速成教程

    Mysql DBA 20天速成教程

    準備一臺pc,一根網線和20天無打擾的空余時間,把MySQL 5.1參考手冊設置為瀏覽器首頁,按下面列表逐條學習即可,這本中文手冊包括基本上所有的內容,補充知識google也都能查到,學習平臺采用linux
    2014-03-03
  • 什么是分表和分區(qū) MySql數據庫分區(qū)和分表方法

    什么是分表和分區(qū) MySql數據庫分區(qū)和分表方法

    這篇文章主要為大家詳細介紹了MySql數據庫分區(qū)和分表方法,告訴大家什么是分表和分區(qū),mysql分表和分區(qū)有什么聯系,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-02-02
  • windows2008 64位系統(tǒng)下MySQL 5.7綠色版的安裝教程

    windows2008 64位系統(tǒng)下MySQL 5.7綠色版的安裝教程

    這篇文章主要給大家分享了在windows2008 64位系統(tǒng)下MySQL 5.7綠色版的安裝教程,文中將安裝步驟介紹的非常詳細,相信會對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起看看吧。
    2017-05-05
  • MySQL 5.6下table_open_cache參數優(yōu)化合理配置詳解

    MySQL 5.6下table_open_cache參數優(yōu)化合理配置詳解

    這篇文章主要介紹了MySQL 5.6下table_open_cache參數合理配置詳解,需要的朋友可以參考下
    2018-03-03
  • mysql?sum(if())和count(if())的用法說明

    mysql?sum(if())和count(if())的用法說明

    這篇文章主要介紹了mysql?sum(if())和count(if())的用法說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • 一文搞懂MySQL索引特性(清晰明了)

    一文搞懂MySQL索引特性(清晰明了)

    索引可以提高數據庫的性能,提高一個海量數據的檢索速度,但是插入,更新,刪除的速度相應會降低,下面這篇文章主要給大家介紹了關于MySQL索引特性的相關資料,需要的朋友可以參考下
    2023-04-04
  • 虛擬機linux端mysql數據庫無法遠程訪問的解決辦法

    虛擬機linux端mysql數據庫無法遠程訪問的解決辦法

    最近在項目搭建過程中遇到一問題,有關虛擬機linux端mysql數據庫無法遠程訪問,通過查閱相關數據庫資料問題解決,下面把具體的解決辦法分享給大家,有需要的朋友可以參考下
    2015-08-08
  • MySql增加用戶、授權、修改密碼等語句

    MySql增加用戶、授權、修改密碼等語句

    MySql 新建用戶,新建數據庫,用戶授權,刪除用戶,修改密碼
    2008-09-09
  • MySQL查詢數據庫所有表名以及表結構其注釋(小白專用)

    MySQL查詢數據庫所有表名以及表結構其注釋(小白專用)

    查詢數據庫所有表的表名、備注,其實也是比較常見的操作,這篇文章主要給大家介紹了關于MySQL查詢數據庫所有表名以及表結構其注釋的相關資料,文中通過圖文介紹的非常詳細,需要的朋友可以參考下
    2024-08-08

最新評論