數據庫中間件/分庫分表相關知識點整理

來源

來自對大佬們文章的總結,參考的文章都列在最后啦

1 數據庫拆分

垂直拆分 -> 讀寫分離 -> 分庫分表(水平拆分)

1.1 垂直拆分

  • 多張表的數據庫 -> 多個小的數據庫
  • 大表 -> 小表(實際開發(fā)比較少用)
  • 服務化(SOA Service-Oriented Architecture)改造

1.2 讀寫分離

  • 一個 Master 節(jié)點(主庫)對應多個 Salve 節(jié)點(從庫)
    補充知識點:集群、mysql主從切換、主從復制、binlog

1.2.1 優(yōu)點

  • 減輕單個庫訪問壓力

1.2.1 挑戰(zhàn)

  • DBA(Database Administrator):
    多了很多集群運維工作
  • 開發(fā)人員:
    1. 基本讀寫分離功能:讀請求 寫請求
    2. 主從數據同步延遲問題:強一致性場景,寫/讀都走主庫
    3. 事務問題:跨多個庫事務,寫/讀都走主庫
    4. 感知集群信息變更:主從切換、增加新節(jié)點

1.3 分庫分表

垂直分庫 + Master/Salve 模式 -> 高并發(fā)訪問操作;但是業(yè)務表中的數據還是會很大 -> 維護和性能

  • 只分表
  • 只分庫
  • 分庫分表

1.3.1 優(yōu)點

  • 存儲能力的水平擴展:多個mysql主從復制集群
  • 寫能力的水平擴展:每個分片都有一個master寫入、索引開銷等

1.3.2 挑戰(zhàn)

希望像操作單庫單表一樣操作分庫分表

  • 基本的數據庫增刪改功能
    希望像操作單庫單表一樣操作分庫分表

    1. sql解析
    2. sql路由:庫路由和表路由
    3. sql改寫
    4. sql執(zhí)行:并發(fā)帶不同的庫
    5. 結果集合并
  • 分布式id
    單庫的自增主鍵id會沖突,需要一個全局的id生成器

  • 分布式事務

    1. XA事務
    2. 柔性事務
  • 動態(tài)擴容
    增加分庫分表的數量

2 主流數據庫中間件設計方案

單庫單表,通過連接池與數據庫建立連接,進行讀寫操作
讀寫分離和分庫分表,應用都要操作多個數據庫實例,需要使用數據庫中間件

2.1 設計方案

典型:proxy、smart-client

2.1.1 proxy模式

2.1.1.1 優(yōu)點

  • 多語言支持:以mysql為例,如果proxy本身實現了mysql的通信協(xié)議,可以就將其看成一個mysql服務器
  • 對業(yè)務開發(fā)同學透明:可以把proxy當成mysql服務器

2.1.1.2 缺點

  • 實現復雜:需要實現被代理的數據庫server端的通信協(xié)議,也許只能代理某一種數據庫,如mysql
  • proxy本身需要保證高可用:不能掛
  • 租戶隔離:多個應用都訪問proxy代理的底層數據庫時
    補充知識點:怎么隔離

2.1.2 smart-client模式

通常smart-client是在連接池或者driver的基礎上進行了一層封裝,smart-client內部與不同的庫建立連接,sql交給smart-client

  • 讀寫分離 -> 選擇走從庫還是主庫
  • 分庫分表 -> 進行sql解析、sql改寫等操作,然后路由到不同的分庫,將結果合并,返回給應用

2.1.2.1 優(yōu)點

  • 實現簡單:proxy需要實現數據庫的服務端協(xié)議,而smart-client不需要實現客戶端通信協(xié)議,有廠商提供的Driver
  • 天然去中心化:以sdk方式,被應用引用,部署到不同節(jié)點,且直連數據庫;相對proxy高可用

2.1.2.2 缺點

  • 通常僅支持某一種語言:例如tddl需使用java語言開發(fā)
  • 版本升級困難:多個應用都依賴某版本jar包,有bug都要升級;而proxy只要升級代理服務器

2.2 業(yè)界產品

各有優(yōu)缺點

proxy實現

目前的實現方案有:

  • 阿里巴巴開源的cobar
  • 阿里云上的drds
  • mycat團隊在cobar基礎上開發(fā)的mycat
  • mysql官方提供的mysql-proxy
  • 奇虎360在mysql-proxy基礎開發(fā)的atlas
  • 當當網開源的sharing-sphere
  • 等等

smart-client實現

目前的實現方案有:

  • 阿里巴巴開源的tddl
  • 大眾點評開源的zebra
  • 當當網開源的sharding-jdbc
  • 螞蟻金服的zal
  • 等等

3 讀寫分離核心要點

3.1 基本路由功能

3.1.1 sql類型判斷

  • write語句
  • query語句

3.1.2 強制走主庫

具體實現上有2種方案:hint 或API

  • hint:比如/*master*/select * from table_xx
  • Api:數據庫中間件決定

3.2 從庫路由策略

一些簡單的選擇策略包括:

  • 隨機選擇(random)
  • 按照權重進行選擇(weight)
  • 或者輪循(round-robin)
  • 等等
  • 就近路由:跨IDC(Internet Data Center)部署的數據庫集群

3.3 HA、Scalable相關

  • HA(High Available):主庫宕機,需要重新選主
  • Scalable:讀qps太高,增加從庫,分擔流量

3.3.1 配置中心

事實上:主從變更,增加從庫 -> 配置信息變更 -> 監(jiān)聽配置中心
配置中心的選擇:

  • 阿里的diamond
  • 百度的disconf
  • 點評開源的lion
  • 攜程開源的apollo
  • 等等

3.3.1.1 問題

  • 延遲:監(jiān)控服務監(jiān)控到集群信息變更 -> 配置中心 -> 數據庫中間件,必然存在一些延遲
    1. 主從切換
    2. 從庫切換,可以自動重試
    3. 大量的配置信息需要推送

3.3.2 輕量級的HA保障

  • 主動隔離,異步檢測

3.3.3 限流和降級

  • 爛sql攔截

4 分庫分表

核心要點:希望像操作單個數據庫實例那樣編寫sql,數據庫中間件幫忙屏蔽所有底層的復雜邏輯
示例場景:批量插入

4.1 SQL解析

目前較為流行的sql解析器包括:

  • FoundationDB SQL Parser
  • Jsqlparser
  • Druid SQL Parser:解析性能最好,支持數據庫方言最多

4.2 SQL路由

分庫分表的字段稱為路由字段,或者分區(qū)字段。
注意點:SQL中應該包含這個路由字段- INSERT- SELECT- UPDATE、DELETE。
路由規(guī)則有:

  • 庫規(guī)則:用于確定到哪一個分庫
  • 表規(guī)則:用于確定到哪一個分表

4.3 SQL改寫

很復雜,支持簡單的OLTP場景,邁向OLAP
補充知識點:OLTP(On-Line Transaction Processing,聯(lián)機事務處理),OLAP(On-Line Analytical Processing,聯(lián)機分析處理),HTAP

4.4 SQL執(zhí)行

拆出來的多個SQL,并發(fā)執(zhí)行

4.5 結果集合并

權衡實現復雜度、執(zhí)行效率,case by case分析

  • 對于查詢條件:
    分區(qū)字段 =、IN
    普通字段 NOT IN、BETWEEN…AND、LIKE、NOT LIKE等

  • 聚合函數:
    大部分支持MAX、MIN、COUNT、SUM
    部分支持AVG
    部分支持函數嵌套、GROUP BY

  • 子查詢:
    支持非常有限
    分為FROM部分的子查詢和WHERE部分的子查詢
    語法上兼容,但是無法識別子查詢中的分區(qū)字段,或者要求子查詢的表名必須與外部查詢表名相同,又或者只能支持一級嵌套子查詢

  • JOIN:
    很復雜
    不可能把兩個表的所有分表,全部拿到內存中來進行JOIN
    取巧的辦法,一個是Binding Table,另外一個是小表廣播

  • 分頁排序:
    分頁的效率較低
    ORDER BY和LIMIT

  • 關于JOIN的特屬說明:

    1. Binding Table:
      強關聯(lián)的表的路由規(guī)則設置為完全一樣,在同一個分庫中join

    2. 小表廣播:
      每個分庫內都實時同步一份完整的數據,在同一個分庫中join
      補充知識點:同步組件,canal、puma

4.6 二級索引(輔維度同步)

user_id分庫分表,同步到另一個集群,按phone_id分庫分表

4.7 分布式id生成器

  • 基于zk
  • 基于mysql
  • 基于緩存
  • 基于算法
    1. twitter的snowflake算法
    2. 美團開源的分布式ID生成系統(tǒng)Leaf
    3. 百度開源的分布式唯一ID生成器UidGenerator
    4. 等等

4.8 分布式事務

4.8.1 事務簡介

事務(Transaction)是訪問并可能更新數據庫中各種數據項的一個程序執(zhí)行單元(unit)

  • 四個屬性:ACID
    1. 原子性(atomicity)
    2. 一致性(consistency)
    3. 隔離性(isolation)
    4. 持久性(durability)/永久性(permanence)

4.8.2 本地事務

只需要操作單一的數據庫,ACID特性由數據庫支持
補充:spring @Transitional 使用注意

4.8.3 分布式事務典型場景

  • 跨庫事務
  • 分庫分表
  • 服務化(SOA)

4.8.4 X/Open DTP模型與XA規(guī)范

4.8.4.1 DTP模型(分布式事務處理 Distributed Transaction Processing)

5個基本元素:
- 應用程序(Application Program ,簡稱AP):用于定義事務邊界(即定義事務的開始和結束),并且在事務邊界內對資源進行操作。
- 資源管理器(Resource Manager,簡稱RM):如數據庫、文件系統(tǒng)等,并提供訪問資源的方式。
- 事務管理器(Transaction Manager ,簡稱TM):負責分配事務唯一標識,監(jiān)控事務的執(zhí)行進度,并負責事務的提交、回滾等。
- 通信資源管理器(Communication Resource Manager,簡稱CRM):控制一個TM域(TM domain)內或者跨TM域的分布式應用之間的通信。
- 通信協(xié)議(Communication Protocol,簡稱CP):提供CRM提供的分布式應用節(jié)點之間的底層通信服務。CRM底層采用OSI TP(Open Systems Interconnection — Distributed Transaction Processing)通信服務

4.8.4.2 XA規(guī)范

XA是DTP模型定義TM和RM之間通訊的接口規(guī)范。

4.8.4.2.1 兩階段提交協(xié)議(2PC)
4.8.4.2.1.1 XA規(guī)范對2PC的2點優(yōu)化
  • Read-only
  • One-phase Commit
4.8.4.2.1.2 存在的問題
  • 同步阻塞問題
  • 單點故障:協(xié)調者TM發(fā)生故障
  • 數據不一致
4.8.4.2.2 三階段提交協(xié)議(Three-phase commit)
4.8.4.2.2.1 3PC針對2PC改動點
  • 引入超時機制
  • 在第一階段和第二階段中插入一個準備階段
4.8.4.2.2.2 3PC和2PC區(qū)別

相對于2PC,3PC主要解決的單點故障問題,并減少阻塞
都無法徹底解決分布式的一致性問題

4.8.5 BASE理論與柔性事務

4.8.5.1 經典的分布式系統(tǒng)理論-CAP

  • 一致性
    強 / 最終 / 弱
  • 可用性
  • 分區(qū)容錯性

4.8.5.2 BASE理論

BASE理論是對CAP理論的延伸,核心思想是即使無法做到強一致性(Strong Consistency,CAP的一致性就是強一致性),但應用可以采用適合的方式達到最終一致性(Eventual Consitency)

  • 基本可用(Basically Available)
  • 軟狀態(tài)( Soft State)
  • 最終一致( Eventual Consistency)

4.8.5.3 典型的柔性事務方案

  • 最大努力通知(非可靠消息、定期校對)
  • 可靠消息最終一致性(異步確保型)
  • TCC(兩階段型、補償型)(Try-Confirm-Cancel)
4.8.5.3.1 最大努力通知
  • 不可靠消息
  • 定期校對
4.8.5.3.2 TCC兩階段補償型(maybe目前最火)
4.8.5.3.2.1 TCC兩階段提交 VS XA兩階段提交
  • XA是資源層面的分布式事務,強一致性,在兩階段提交的整個過程中,一直會持有資源的鎖。
  • TCC是業(yè)務層面的分布式事務,最終一致性,不會一直持有資源的鎖。
4.8.5.3.2.2 補償性事務(Compensation-Based Transactions)

補償是一個獨立的支持ACID特性的本地事務,用于在邏輯上取消服務提供者上一個ACID事務造成的影響,對于一個長事務(long-running transaction),與其實現一個巨大的分布式ACID事務,不如使用基于補償性的方案,把每一次服務調用當做一個較短的本地ACID事務來處理,執(zhí)行完就立即提交

4.8.5.3.2.3 TCC事務模型 VS DTP事務模型
4.8.5.3.2.4 TCC事務的優(yōu)缺點
  • 優(yōu)點
    解決提交占用資源鎖時間過長導致的性能問題
  • 缺點
    開發(fā)成本,主業(yè)務從業(yè)務都要改造
4.8.5.3.3 可靠消息最終一致性

兩種方案

  • 基于MQ的事務消息
  • 并不是所有的mq都支持事務消息。也就是消息一旦發(fā)送到消息隊列中,消費者立馬就可以消費到。此時可以使用獨立消息服務、或者本地事務表。

4.9 分庫分表常用方案

分庫分表方案中有常用的方案,hash取模和range范圍方案

4.9.1 hash取模

  • 優(yōu)點:數據均勻,不會有熱點
  • 缺點:數據遷移和擴容很難

4.9.2 range范圍方案

  • 優(yōu)點:利于將來的擴容
  • 缺點:有熱點問題

4.9.3 倆者結合

4.9.4 分庫分表能無限擴容么

  • 不能,數據庫連接過多
  • 解決辦法:不讓應用連接所有的數據庫 -> 異地多活

4.10 什么時候分庫分表?數據的量級?

5. 異地多活

tddl 配置

  • tddl-rule.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
    <bean id="vtabroot" class="com.taobao.tddl.interact.rule.VirtualTableRoot" init-method="init">
        <property name="dbType" value="MYSQL" />
        <property name="defaultDbIndex" value="XXX_0000_GROUP" />
        <property name="tableRules">
            <map>
                <entry key="xxx_user" value-ref="xxx_user" />
                <entry key="xxx_dept" value-ref="xxx_dept" />
            </map>
        </property>
    </bean>
    <bean id="xxx_user" class="com.taobao.tddl.interact.rule.TableRule">
        <property name="dbNamePattern" value="XXX_{0000}_GROUP" />
        <property name="tbNamePattern" value="xxx_user_{0000}" />
        <property name="dbRuleArray" value="(#corp_id,1,1024#.hashCode().abs().longValue() % 1024).intdiv(64)" />
        <property name="tbRuleArray" value="(#corp_id,1,1024#.hashCode().abs().longValue() % 1024)" />
        <property name="allowFullTableScan" value="false" />
    </bean>
    <bean id="xxx_dept" class="com.taobao.tddl.interact.rule.TableRule">
        <property name="dbNamePattern" value="XXX_{0000}_GROUP" />
        <property name="tbNamePattern" value="xxx_dept_{0000}" />
        <property name="dbRuleArray" value="(#corp_id,1,1024#.hashCode().abs().longValue() % 1024).intdiv(64)" />
        <property name="tbRuleArray" value="(#corp_id,1,1024#.hashCode().abs().longValue() % 1024)" />
        <property name="allowFullTableScan" value="false" />
    </bean>
</beans>
  • datasource.xml
<bean id="dataSource" class="com.taobao.tddl.client.jdbc.TDataSource" init-method="init">
        <!--<property name="appName" value="XXX_APP"/>-->
        <property name="appName" value="XXX_APP"/>
        <property name="appRuleFile" value="/xxx/tddl-rule.xml"/>
        <property name="dynamicRule" value="true"/>
</bean>

參考

DRDS 實例中的連接

分庫分表的基本思想

分庫分表?如何做到永不遷移數據和避免熱點?

MySQL binlog原來可以這樣用?各種場景和原理剖析!

leaf:美團開源的分布式ID生成系統(tǒng)剖析

UidGenerator:百度開源的分布式ID服務(解決了時鐘回撥問題)

數據庫中間件詳解

1.0 分布式事務概述

分布式事務

扎心一問:分庫分表就能無限擴容嗎

餓了么異地多活技術實現

數據庫異地多活解決方案

異地多活沒那么難

2017雙11技術揭秘—TDDL/DRDS 的類 KV 查詢優(yōu)化實踐

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容