為什么分庫分表后不建議跨分片查詢

寫在前面:如果對(duì)分庫分表還不是很熟悉的,可以參考筆者之前的文章《分庫分表技術(shù)演進(jìn)暨最佳實(shí)踐》。

在這篇文章中提到了一個(gè)場(chǎng)景,即電商的訂單讹语。我們都知道訂單表有三大主要查詢:基于訂單ID查詢基于商戶編號(hào)查詢蜂科,基于用戶ID查詢顽决。且那篇文章給出的方案是基于訂單ID、商戶編號(hào)导匣、用戶ID都有一份分庫分表的數(shù)據(jù)才菠。那么為什么要這么做?能否只基于某一列例如用戶ID分庫分表贡定,答案肯定是不能赋访。

筆者基于sharding-sphere(GitHub地址:https://github.com/apache/incubator-shardingsphere)進(jìn)行了一個(gè)簡(jiǎn)單的測(cè)試,測(cè)試環(huán)境如下:

  1. 128個(gè)分表:image_${0..127}缓待;
  2. 數(shù)據(jù)庫服務(wù)器:32C64G蚓耽;
  3. 數(shù)據(jù)庫版本:MySQL-5.7.23;
  4. 操作系統(tǒng):CentOS 6.9 Final旋炒;
  5. 連接池:druid 1.1.6步悠;
  6. mysql-connector-java:6.0.5;
  7. mybatis:3.4.5国葬;
  8. mybatis-spring:1.3.1贤徒;
  9. springboot:1.5.9.RELEASE芹壕;
  10. sharding-sphere-3.1.0汇四;
  11. JVM參數(shù):-Xmx2g -Xms2g -Xmn1g -Xss256k -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -XX:+AlwaysPreTouch;
  12. druid配置:默認(rèn)參數(shù)踢涌;

表信息如下:

-- id是分片鍵通孽。備注,DDL是偽SQL
CREATE TABLE `image_${0..127}` (
  `id` varchar(32) NOT NULL,
  `image_no` varchar(50) NOT NULL,
  `file_name` varchar(200) NOT NULL COMMENT '影像文件名稱',
  `source` varchar(32) DEFAULT NULL COMMENT '影像來源',
  `create_date` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '影像文件創(chuàng)建時(shí)間',
  PRIMARY KEY (`id`),
  KEY `idx_image_no` (`image_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

第1個(gè)測(cè)試場(chǎng)景如下:

  • 每個(gè)分表大概160w數(shù)據(jù)睁壁;
  • 累計(jì)1w次跨分片(imageNo)查詢 PK. 帶分片(id)查詢背苦;

測(cè)試結(jié)果如下:


分片鍵PK.跨分片鍵

結(jié)論:由測(cè)試結(jié)果可知,跨分片查詢相比帶分片鍵查詢的性能衰減了很多潘明。

第2個(gè)測(cè)試場(chǎng)景如下:

  • 每個(gè)分表大概160w數(shù)據(jù)行剂;
  • 累計(jì)1w次分別測(cè)試跨1個(gè)分表,8個(gè)分表钳降、16個(gè)分表厚宰、32個(gè)分表、64個(gè)分表、128個(gè)分表铲觉,結(jié)果如下:
跨分片鍵查詢壓力測(cè)試

結(jié)論:跨的分表數(shù)量越大澈蝙,跨分表查詢的性能越差;


  • 為什么慢

我們要弄明白跨分片查詢?yōu)槭裁催@么慢之前撵幽,首先要掌握跨分片查詢?cè)淼朴R詓harding-sphere為例,其跨分片查詢的原理是:通過線程池并發(fā)請(qǐng)求到所有符合路由規(guī)則的目標(biāo)分表盐杂,然后對(duì)所有結(jié)果進(jìn)行歸并逗载。需要說明的是,當(dāng)路由結(jié)果只有1個(gè)链烈,即不跨分片操作時(shí)sharding-sphere不會(huì)通過線程池異步執(zhí)行撕贞,而是直接同步執(zhí)行,這么做的原因是為了減少線程開銷测垛,核心源碼在ShardingExecuteEngine.java中)捏膨。

既然是這個(gè)執(zhí)行原理,為什么跨分片查詢食侮,隨著跨分片數(shù)量越多号涯,性能會(huì)越來越差?我們?cè)倏匆幌碌?個(gè)測(cè)試場(chǎng)景锯七,當(dāng)測(cè)試跨1個(gè)分表時(shí)链快,1w次查詢只需要5889ms,即平均1次查詢不到1ms眉尸。所以性能瓶頸不應(yīng)該在SQL執(zhí)行階段域蜗,而應(yīng)該在結(jié)果歸并階段。為了驗(yàn)證這個(gè)猜想噪猾,筆者空跑sharding-sphere依賴的并發(fā)執(zhí)行組件google-guava的MoreExecutors霉祸。其結(jié)果如下:


Multi-Thread Executor Test

結(jié)論:由這個(gè)測(cè)試結(jié)果可知,當(dāng)并發(fā)執(zhí)行越來越多袱蜡,其結(jié)果歸并的代價(jià)越來越大丝蹭。

附--空跑sharding-sphere依賴的并發(fā)執(zhí)行組件google-guava的MoreExecutors的部分源碼如下:

public class ConcurrentExecutorTest {
    private static final ListeningExecutorService executorService;
    public static final int CONCURRENT_COUNT = 64;
    public static final int batchSize = CONCURRENT_COUNT;
    public static final int EXECUTOR_SIZE = 8;
    static {
        executorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(EXECUTOR_SIZE));
        MoreExecutors.addDelayedShutdownHook(executorService, 60, TimeUnit.SECONDS);
    }

    private static <I, O> List<O> execute(final Collection<I> inputs) {
        if (inputs.isEmpty()) {
            return Collections.emptyList();
        }
        // 并發(fā)執(zhí)行
        Collection<ListenableFuture<O>> allFutures = asyncExecute(inputs);
        // 結(jié)果歸并
        return getResults(allFutures);
    }

    private static <I, O> Collection<ListenableFuture<O>> asyncExecute(final Collection<I> inputs) {
        Collection<ListenableFuture<O>> result = new ArrayList<>(inputs.size());
        for (final I each : inputs) {
            // 異步執(zhí)行時(shí)直接返回結(jié)果
            result.add(executorService.submit(() -> (O) each));
        }
        return result;
    }

    private static <O> List<O> getResults(final Collection<ListenableFuture<O>> allFutures) {
        List<O> result = new LinkedList<>();
        for (ListenableFuture<O> each : allFutures) {
            result.add(each.get());
        }
        return result;
    }
}

-- 最后總結(jié)

跨分片查詢的性能這么差,為什么sharding-sphere還要去做呢坪蚁?筆者認(rèn)為首先sharding-sphere是一個(gè)通用的分庫分表中間件奔穿,而不是在某些特定條件才能使用的中間件,所以應(yīng)該要盡可能的兼容所有SQL敏晤。其次贱田,即使跨分片查詢性能這么差,這個(gè)主要是在OLTP系統(tǒng)中使用時(shí)要小心嘴脾,在一些OLAP或者后臺(tái)管理系統(tǒng)等一些低頻次操作的系統(tǒng)中男摧,還是可以使用的。

比如,賬戶表已經(jīng)根據(jù)賬戶ID分表彩倚,但是在運(yùn)營(yíng)操作的后臺(tái)管理系統(tǒng)中維護(hù)賬戶信息時(shí)筹我,肯定有一些操作的SQL是不會(huì)帶有分片鍵賬戶ID的,比如查詢賬戶余額最多的88個(gè)土豪用戶帆离。這個(gè)時(shí)候蔬蕊,我們可以通過sharding-sphere中間件直接執(zhí)行這條低頻次SQL。而不需要為了這些操作引入es或者其他組件來解決這種低頻次的問題(當(dāng)然哥谷,隨著系統(tǒng)的演進(jìn)岸夯,最后可能還是需要引入es等一些中間件來解決這些問題)。所以们妥,分庫分表中間件的跨分片查詢?cè)陧?xiàng)目特定階段能夠大大減少開發(fā)成本猜扮,從而以最短的時(shí)間上線業(yè)務(wù)需求

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末监婶,一起剝皮案震驚了整個(gè)濱河市旅赢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌惑惶,老刑警劉巖煮盼,帶你破解...
    沈念sama閱讀 222,627評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異带污,居然都是意外死亡僵控,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門鱼冀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來报破,“玉大人,你說我怎么就攤上這事千绪〕湟祝” “怎么了?”我有些...
    開封第一講書人閱讀 169,346評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵翘紊,是天一觀的道長(zhǎng)蔽氨。 經(jīng)常有香客問我藐唠,道長(zhǎng)帆疟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,097評(píng)論 1 300
  • 正文 為了忘掉前任宇立,我火速辦了婚禮踪宠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘妈嘹。我一直安慰自己柳琢,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著柬脸,像睡著了一般他去。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上倒堕,一...
    開封第一講書人閱讀 52,696評(píng)論 1 312
  • 那天灾测,我揣著相機(jī)與錄音,去河邊找鬼垦巴。 笑死媳搪,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的骤宣。 我是一名探鬼主播秦爆,決...
    沈念sama閱讀 41,165評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼憔披!你這毒婦竟也來了等限?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,108評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤芬膝,失蹤者是張志新(化名)和其女友劉穎精刷,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蔗候,經(jīng)...
    沈念sama閱讀 46,646評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡怒允,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了锈遥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纫事。...
    茶點(diǎn)故事閱讀 40,861評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖所灸,靈堂內(nèi)的尸體忽然破棺而出丽惶,到底是詐尸還是另有隱情,我是刑警寧澤爬立,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布钾唬,位于F島的核電站,受9級(jí)特大地震影響侠驯,放射性物質(zhì)發(fā)生泄漏抡秆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評(píng)論 3 336
  • 文/蒙蒙 一吟策、第九天 我趴在偏房一處隱蔽的房頂上張望儒士。 院中可真熱鬧,春花似錦檩坚、人聲如沸着撩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拖叙。三九已至氓润,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間薯鳍,已是汗流浹背旺芽。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留辐啄,地道東北人采章。 一個(gè)月前我還...
    沈念sama閱讀 49,287評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像壶辜,于是被迫代替她去往敵國(guó)和親悯舟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容