数据库中间件/分库分表相关知识点整理

来源

来自对大佬们文章的总结,参考的文章都列在最后啦

1 数据库拆分

垂直拆分 -> 读写分离 -> 分库分表(水平拆分)

1.1 垂直拆分

  • 多张表的数据库 -> 多个小的数据库
  • 大表 -> 小表(实际开发比较少用)
  • 服务化(SOA Service-Oriented Architecture)改造

1.2 读写分离

  • 一个 Master 节点(主库)对应多个 Salve 节点(从库)
    补充知识点:集群、mysql主从切换、主从复制、binlog

1.2.1 优点

  • 减轻单个库访问压力

1.2.1 挑战

  • DBA(Database Administrator):
    多了很多集群运维工作
  • 开发人员:
    1. 基本读写分离功能:读请求 写请求
    2. 主从数据同步延迟问题:强一致性场景,写/读都走主库
    3. 事务问题:跨多个库事务,写/读都走主库
    4. 感知集群信息变更:主从切换、增加新节点

1.3 分库分表

垂直分库 + Master/Salve 模式 -> 高并发访问操作;但是业务表中的数据还是会很大 -> 维护和性能

  • 只分表
  • 只分库
  • 分库分表

1.3.1 优点

  • 存储能力的水平扩展:多个mysql主从复制集群
  • 写能力的水平扩展:每个分片都有一个master写入、索引开销等

1.3.2 挑战

希望像操作单库单表一样操作分库分表

  • 基本的数据库增删改功能
    希望像操作单库单表一样操作分库分表

    1. sql解析
    2. sql路由:库路由和表路由
    3. sql改写
    4. sql执行:并发带不同的库
    5. 结果集合并
  • 分布式id
    单库的自增主键id会冲突,需要一个全局的id生成器

  • 分布式事务

    1. XA事务
    2. 柔性事务
  • 动态扩容
    增加分库分表的数量

2 主流数据库中间件设计方案

单库单表,通过连接池与数据库建立连接,进行读写操作
读写分离和分库分表,应用都要操作多个数据库实例,需要使用数据库中间件

2.1 设计方案

典型:proxy、smart-client

2.1.1 proxy模式

2.1.1.1 优点

  • 多语言支持:以mysql为例,如果proxy本身实现了mysql的通信协议,可以就将其看成一个mysql服务器
  • 对业务开发同学透明:可以把proxy当成mysql服务器

2.1.1.2 缺点

  • 实现复杂:需要实现被代理的数据库server端的通信协议,也许只能代理某一种数据库,如mysql
  • proxy本身需要保证高可用:不能挂
  • 租户隔离:多个应用都访问proxy代理的底层数据库时
    补充知识点:怎么隔离

2.1.2 smart-client模式

通常smart-client是在连接池或者driver的基础上进行了一层封装,smart-client内部与不同的库建立连接,sql交给smart-client

  • 读写分离 -> 选择走从库还是主库
  • 分库分表 -> 进行sql解析、sql改写等操作,然后路由到不同的分库,将结果合并,返回给应用

2.1.2.1 优点

  • 实现简单:proxy需要实现数据库的服务端协议,而smart-client不需要实现客户端通信协议,有厂商提供的Driver
  • 天然去中心化:以sdk方式,被应用引用,部署到不同节点,且直连数据库;相对proxy高可用

2.1.2.2 缺点

  • 通常仅支持某一种语言:例如tddl需使用java语言开发
  • 版本升级困难:多个应用都依赖某版本jar包,有bug都要升级;而proxy只要升级代理服务器

2.2 业界产品

各有优缺点

proxy实现

目前的实现方案有:

  • 阿里巴巴开源的cobar
  • 阿里云上的drds
  • mycat团队在cobar基础上开发的mycat
  • mysql官方提供的mysql-proxy
  • 奇虎360在mysql-proxy基础开发的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 配置中心

事实上:主从变更,增加从库 -> 配置信息变更 -> 监听配置中心
配置中心的选择:

  • 阿里的diamond
  • 百度的disconf
  • 点评开源的lion
  • 携程开源的apollo
  • 等等

3.3.1.1 问题

  • 延迟:监控服务监控到集群信息变更 -> 配置中心 -> 数据库中间件,必然存在一些延迟
    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路由

分库分表的字段称为路由字段,或者分区字段。
注意点:SQL中应该包含这个路由字段- INSERT- SELECT- UPDATE、DELETE。
路由规则有:

  • 库规则:用于确定到哪一个分库
  • 表规则:用于确定到哪一个分表

4.3 SQL改写

很复杂,支持简单的OLTP场景,迈向OLAP
补充知识点:OLTP(On-Line Transaction Processing,联机事务处理),OLAP(On-Line Analytical Processing,联机分析处理),HTAP

4.4 SQL执行

拆出来的多个SQL,并发执行

4.5 结果集合并

权衡实现复杂度、执行效率,case by case分析

  • 对于查询条件:
    分区字段 =、IN
    普通字段 NOT IN、BETWEEN…AND、LIKE、NOT LIKE等

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

  • 子查询:
    支持非常有限
    分为FROM部分的子查询和WHERE部分的子查询
    语法上兼容,但是无法识别子查询中的分区字段,或者要求子查询的表名必须与外部查询表名相同,又或者只能支持一级嵌套子查询

  • JOIN:
    很复杂
    不可能把两个表的所有分表,全部拿到内存中来进行JOIN
    取巧的办法,一个是Binding Table,另外一个是小表广播

  • 分页排序:
    分页的效率较低
    ORDER BY和LIMIT

  • 关于JOIN的特属说明:

    1. Binding Table:
      强关联的表的路由规则设置为完全一样,在同一个分库中join

    2. 小表广播:
      每个分库内都实时同步一份完整的数据,在同一个分库中join
      补充知识点:同步组件,canal、puma

4.6 二级索引(辅维度同步)

user_id分库分表,同步到另一个集群,按phone_id分库分表

4.7 分布式id生成器

  • 基于zk
  • 基于mysql
  • 基于缓存
  • 基于算法
    1. twitter的snowflake算法
    2. 美团开源的分布式ID生成系统Leaf
    3. 百度开源的分布式唯一ID生成器UidGenerator
    4. 等等

4.8 分布式事务

4.8.1 事务简介

事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(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规范

4.8.4.1 DTP模型(分布式事务处理 Distributed Transaction Processing)

5个基本元素:
- 应用程序(Application Program ,简称AP):用于定义事务边界(即定义事务的开始和结束),并且在事务边界内对资源进行操作。
- 资源管理器(Resource Manager,简称RM):如数据库、文件系统等,并提供访问资源的方式。
- 事务管理器(Transaction Manager ,简称TM):负责分配事务唯一标识,监控事务的执行进度,并负责事务的提交、回滚等。
- 通信资源管理器(Communication Resource Manager,简称CRM):控制一个TM域(TM domain)内或者跨TM域的分布式应用之间的通信。
- 通信协议(Communication Protocol,简称CP):提供CRM提供的分布式应用节点之间的底层通信服务。CRM底层采用OSI TP(Open Systems Interconnection — Distributed Transaction Processing)通信服务

4.8.4.2 XA规范

XA是DTP模型定义TM和RM之间通讯的接口规范。

4.8.4.2.1 两阶段提交协议(2PC)
4.8.4.2.1.1 XA规范对2PC的2点优化
  • Read-only
  • One-phase Commit
4.8.4.2.1.2 存在的问题
  • 同步阻塞问题
  • 单点故障:协调者TM发生故障
  • 数据不一致
4.8.4.2.2 三阶段提交协议(Three-phase commit)
4.8.4.2.2.1 3PC针对2PC改动点
  • 引入超时机制
  • 在第一阶段和第二阶段中插入一个准备阶段
4.8.4.2.2.2 3PC和2PC区别

相对于2PC,3PC主要解决的单点故障问题,并减少阻塞
都无法彻底解决分布式的一致性问题

4.8.5 BASE理论与柔性事务

4.8.5.1 经典的分布式系统理论-CAP

  • 一致性
    强 / 最终 / 弱
  • 可用性
  • 分区容错性

4.8.5.2 BASE理论

BASE理论是对CAP理论的延伸,核心思想是即使无法做到强一致性(Strong Consistency,CAP的一致性就是强一致性),但应用可以采用适合的方式达到最终一致性(Eventual Consitency)

  • 基本可用(Basically Available)
  • 软状态( 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是业务层面的分布式事务,最终一致性,不会一直持有资源的锁。
4.8.5.3.2.2 补偿性事务(Compensation-Based Transactions)

补偿是一个独立的支持ACID特性的本地事务,用于在逻辑上取消服务提供者上一个ACID事务造成的影响,对于一个长事务(long-running transaction),与其实现一个巨大的分布式ACID事务,不如使用基于补偿性的方案,把每一次服务调用当做一个较短的本地ACID事务来处理,执行完就立即提交

4.8.5.3.2.3 TCC事务模型 VS DTP事务模型
4.8.5.3.2.4 TCC事务的优缺点
  • 优点
    解决提交占用资源锁时间过长导致的性能问题
  • 缺点
    开发成本,主业务从业务都要改造
4.8.5.3.3 可靠消息最终一致性

两种方案

  • 基于MQ的事务消息
  • 并不是所有的mq都支持事务消息。也就是消息一旦发送到消息队列中,消费者立马就可以消费到。此时可以使用独立消息服务、或者本地事务表。

4.9 分库分表常用方案

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

4.9.1 hash取模

  • 优点:数据均匀,不会有热点
  • 缺点:数据迁移和扩容很难

4.9.2 range范围方案

  • 优点:利于将来的扩容
  • 缺点:有热点问题

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生成系统剖析

UidGenerator:百度开源的分布式ID服务(解决了时钟回拨问题)

数据库中间件详解

1.0 分布式事务概述

分布式事务

扎心一问:分库分表就能无限扩容吗

饿了么异地多活技术实现

数据库异地多活解决方案

异地多活没那么难

2017双11技术揭秘—TDDL/DRDS 的类 KV 查询优化实践

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容