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

MySQL分庫分表詳情

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

一、業(yè)務(wù)場(chǎng)景介紹

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

當(dāng)然還有些小伙伴知道按照省份/地區(qū)或一定的業(yè)務(wù)關(guān)系進(jìn)行數(shù)據(jù)庫拆分

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

二、水平分庫分表方法

1.RANGE

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

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

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

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

2.HASH取模

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

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

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

HASH取模方法缺點(diǎn): 擴(kuò)容麻煩、遷移數(shù)據(jù)時(shí)每次都需要重新計(jì)算hash值分配到不同的庫和表

3.一致性HASH

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

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

普通HASH算法:

普通哈希算法將任意長(zhǎng)度的二進(jìn)制值映射為較短的固定長(zhǎng)度的二進(jìn)制值,這個(gè)小的二進(jìn)制值稱為哈希值。哈希值是一段數(shù)據(jù)唯一且極其緊湊的數(shù)值表示形式。

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

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

這個(gè)圓環(huán)首尾相連,那么假設(shè)現(xiàn)在有三個(gè)數(shù)據(jù)庫服務(wù)器節(jié)點(diǎn)node1、node2、node3三個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)負(fù)責(zé)自己這部分的用戶數(shù)據(jù)存儲(chǔ),假設(shè)有用戶user1、user2、user3,我們可以對(duì)服務(wù)器節(jié)點(diǎn)進(jìn)行HASH運(yùn)算,假設(shè)HASH計(jì)算后,user1落在node1上,user2落在node2上,user3落在user3上

OK,現(xiàn)在咱們假設(shè)node3節(jié)點(diǎn)失效了

 user3將會(huì)落到node1上,而之前的node1和node2數(shù)據(jù)不會(huì)改變,再假設(shè)新增了節(jié)點(diǎn)node4

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

當(dāng)然還有一個(gè)問題還需要解決,那就是平衡性。從圖我們可以看出,當(dāng)服務(wù)器節(jié)點(diǎn)比較少的時(shí)候,會(huì)出現(xiàn)一個(gè)問題,就是此時(shí)必然造成大量數(shù)據(jù)集中到一個(gè)節(jié)點(diǎn)上面,極少數(shù)數(shù)據(jù)集中到另外的節(jié)點(diǎn)上面。

為了解決這種數(shù)據(jù)傾斜問題,一致性哈希算法引入了虛擬節(jié)點(diǎn)機(jī)制,即對(duì)每一個(gè)服務(wù)節(jié)點(diǎn)計(jì)算多個(gè)哈希,每個(gè)計(jì)算結(jié)果位置都放置一個(gè)節(jié)點(diǎn),稱為虛擬節(jié)點(diǎn)。具體做法可以先確定每個(gè)物理節(jié)點(diǎn)關(guān)聯(lián)的虛擬節(jié)點(diǎn)數(shù)量,然后在ip或者主機(jī)名后面增加編號(hào)。例如上面的情況,可以為每臺(tái)服務(wù)器計(jì)算三個(gè)虛擬節(jié)點(diǎn),于是可以分別計(jì)算 “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”的哈希值,這樣形成九個(gè)虛擬節(jié)點(diǎn)

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

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

一致性取模方法缺點(diǎn): 嗯,比起以上兩種,可以認(rèn)為沒有。

三、單元測(cè)試

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

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)的服務(wù)器列表
    private static String[] servers = {"192.168.5.1", "192.168.5.2", "192.168.5.3"};

    //真實(shí)結(jié)點(diǎn)列表,考慮到服務(wù)器上線、下線的場(chǎng)景,即添加、刪除的場(chǎng)景會(huì)比較頻繁,這里使用LinkedList會(huì)更好
    private static List<String> realNodes = new LinkedList<>();

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

    //一個(gè)真實(shí)結(jié)點(diǎn)對(duì)應(yīng)3個(gè)虛擬節(jié)點(diǎn)
    private static final int VIRTUAL_NODES = 3;

    /**
     * 測(cè)試有虛擬節(jié)點(diǎn)的一致性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]) + ", 被路由到結(jié)點(diǎn)[" + getServer(users[i]) + "]");
    }

    /**
     * 先把原始的服務(wù)器添加到真實(shí)結(jié)點(diǎn)列表中
     */
    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é)點(diǎn)" + String.valueOf(i);
                int hash = getHash(virtualNodeName);
                System.out.println("虛擬節(jié)點(diǎn)[" + virtualNodeName + "]被添加, hash值為" + hash);
                virtualNodes.put(hash, virtualNodeName);
            }
        }
        System.out.println();
    }

    //使用FNV1_32_HASH算法計(jì)算服務(wù)器的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;

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

    //得到應(yīng)當(dāng)路由到的結(jié)點(diǎn)
    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值大的,則從第一個(gè)node開始
            Integer i = virtualNodes.firstKey();
            //返回對(duì)應(yīng)的服務(wù)器
            virtualNode = virtualNodes.get(i);
        } else {
            //第一個(gè)Key就是順時(shí)針過去離node最近的那個(gè)結(jié)點(diǎn)
            Integer i = subMap.firstKey();
            //返回對(duì)應(yīng)的服務(wù)器
            virtualNode = subMap.get(i);
        }
        //virtualNode虛擬節(jié)點(diǎn)名稱要截取一下
        if (StringUtils.isNotBlank(virtualNode)) {
            return virtualNode.substring(0, virtualNode.indexOf("-"));
        }
        return null;
    }
}

這里模擬9個(gè)用戶對(duì)象hash后被路由的情況,看下結(jié)果

總結(jié):

分庫分表在分布式微服務(wù)架構(gòu)環(huán)境下建議強(qiáng)烈使用一致性HASH算法來做,當(dāng)然分布式環(huán)境下也會(huì)產(chǎn)生業(yè)務(wù)數(shù)據(jù)數(shù)據(jù)一致性、分布式事務(wù)問題,下期咱們?cè)賮硖接憯?shù)據(jù)一致性、分布式事務(wù)的解決方案

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

相關(guān)文章

  • SQL語句之如何用JOIN連接多個(gè)表

    SQL語句之如何用JOIN連接多個(gè)表

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

    Mysql DBA 20天速成教程

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

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

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

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

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

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

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

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

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

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

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

    虛擬機(jī)linux端mysql數(shù)據(jù)庫無法遠(yuǎn)程訪問的解決辦法

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

    MySql增加用戶、授權(quán)、修改密碼等語句

    MySql 新建用戶,新建數(shù)據(jù)庫,用戶授權(quán),刪除用戶,修改密碼
    2008-09-09
  • MySQL查詢數(shù)據(jù)庫所有表名以及表結(jié)構(gòu)其注釋(小白專用)

    MySQL查詢數(shù)據(jù)庫所有表名以及表結(jié)構(gòu)其注釋(小白專用)

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

最新評(píng)論