数据库专题——分库分表

news2024/12/22 22:25:03
  • 一. 分库分表介绍
  • 二. 分库分表实践

一. 分库分表介绍

1.1 分库分表解决了什么问题

  • 先说分库:
    • 《高性能MySQL》中提到了两种数据库扩展方式:垂直扩展和水平扩展。前者意味着买更多性能强悍的硬件,但是总会达到扩展的天花板,且成本较高。分库则是后者的一种实现方式。
    • 流量瓶颈:主要是写多的场景(读多可以通过读写分离,缓存等方式解决问题),而单集群写在大流量下是易达到瓶颈的。
    • 容量瓶颈:数据量大的情况下,单集群磁盘不够存储(尤其对于订单类的业务,即使有归档等手段,也难以支撑一定时间范围内的数据存储)。
  • 再说分表
    • 分表主要解决单表过大问题(DBA推荐单表容量在1000万行左右):随着表增大,从经验上看会引起慢查询(即使SQL语句很简单且走了索引),分表有利于提高读写效率

1.2 分库分表的方式

分表通常可分为水平分表和垂直分表

  • 垂直分表:把大表的字段拆分,拆成小表。如把order表拆成order_major(包含热点字段)和order_extra(包含冷门字段)
    • 优点:热点数据分离,热点表走主库,冷门表走从库
  • 水平分表:水平分表就是指以行为单位对数据进行拆分,一般分库分表指的就是水平分表
    • 优点:优化单表行数过大,提高性能

1.3 分库分表的基本原理

选择一个或多个路由键(routeKey,也可称分片),根据该路由键及路由规则,将SQL路由至不同的分库及分表。

  • 如分10库,每库100表,路由键为userId
    • 库路由规则:#userId#%10
    • 表路由规则:(#userId#).intdiv(10)%100
  • 代表含义:uid=100001会路由到1库0表中;uid=100329会路由到9库32表中

1.4 分库分表需要注意的问题

  • (1)自增主键无法标识唯一id,需要依赖分布式ID生成服务
  • (2)路由键的选择(拆分的维度):如订单表,假如又要根据订单id查询,又要根据用户id查询,该怎么解决
    • 思路一:系统拆分(实现成本高)
    • 思路二:建路由表(订单表以订单id为路由键;新建一张用户id与订单id的路由表,以用户id作为路由键)——> 注意分布式事务问题
  • (3)分布式事务问题:跨库就会涉及到分布式事务问题,除非所有操作的表都基于相同的路由键与路由规则
  • (4)路由键的选择:数据倾斜
  • (5)可扩展性:如果当前已经是分库分表,未来再扩容,建议以倍数扩(如2—>4,4—>8)。不然会复杂
  • (6)数据迁移过程中的平滑稳定

1.5 分库分表的实现方案

业界主要两种:服务端代理 和 客户端代理

  • 服务端代理:通过部署代理服务,背后管理多个数据库实例。应用层通过一个普通的数据源(c3p0、druid、dbcp等)与代理服务器建立连接,所有的SQL语句都是发送给这个代理,由这个代理去路由底层数据库,开发人员无需关注底层逻辑
  • 客户端代理:应用层内部管理了多个普通的数据源(c3p0、druid、dbcp等),每个普通数据源各自与不同的库建立连接。应用层通过路由规则路由给各个普通的数据源去执行,并返回结果。数据源代理通常也实现了JDBC规范定义的API,因此能够直接与orm框架整合。这种方案下开发人员需要修改代码

主流的实现方案对比

  • 数据库代理
    • 目前的实现方案有:阿里巴巴开源的cobar,mycat团队在cobar基础上开发的mycat,mysql官方提供的mysql-proxy,奇虎360在mysql-proxy基础开发的atlas。目前除了mycat,其他几个项目基本已经没有维护。
    • 优点:多语言支持。也就是说,不论你用的php、java或是其他语言,都可以支持。原因在于数据库代理本身就实现了mysql的通信协议,你可以就将其看成一个mysql 服务器。mysql官方团队为不同语言提供了不同的客户端驱动,如java语言的mysql-connector-java,python语言的mysql-connector-python等等。因此不同语言的开发者都可以使用mysql官方提供的对应的驱动来与这个代理服务器建通信。
    • 缺点:实现复杂。因为代理服务器需要实现mysql服务端的通信协议,因此实现难度较大。
  • 数据源代理
    • 目前的实现方案有:阿里巴巴开源的tddl,大众点评开源的zebra,当当网开源的sharding-jdbc。需要注意的是tddl的开源版本只有读写分离功能,没有分库分表,且开源版本已经不再维护。大众点评的zebra开源版本代码已经很久更新,基本上处于停滞的状态。当当网的sharding-jdbc目前算是做的比较好的,代码时有更新,文档资料比较全。
    • 优点:更加轻量,可以与任何orm框架整合。这种方案不需要实现mysql的通信协议,因为底层管理的普通数据源,可以直接通过mysql-connector-java驱动与mysql服务器进行通信,因此实现相对简单。
    • 缺点:仅支持某一种语言。例如tddl、zebra、sharding-jdbc都是使用java语言开发,因此对于使用其他语言的用户,就无法使用这些中间件。版本升级困难,因为应用使用数据源代理就是引入一个jar包的依赖,在有多个应用都对某个版本的jar包产生依赖时,一旦这个版本有bug,所有的应用都需要升级。而数据库代理升级则相对容易,因为服务是单独部署的,只要升级这个代理服务器,所有连接到这个代理的应用自然也就相当于都升级了。
  • ORM框架代理
    • 目前有hibernate提供的hibernate-shards,也可以通过mybatis插件的方式编写。相对于前面两种方案,这种方案可以说是只有缺点,没有优点。

二. 分库分表实践

2.1 路由键的选择

  • 确定业务逻辑上的主体,并确认大部分数据库操作都基于这个主体进行(如用户ID)。
  • 路由键在业务上不应被update,应是一个稳定的数据。且不应该为Null
  • 数据倾斜问题,确保散列均匀

2.2 分库分表数决策

  • 分表数量决策:
    • 单表建议:不超过1000万行数据
    • 通常可以预估2到5年的数据增长量,用估算出的总数据量除以总的物理分库数,再除以建议的最大数据量1000万,即可得出每个物理分库上需要创建的物理分表数
      • (未来3到5年内总共的记录行数) / 单张表建议记录行数
  • 分库数量决策:
    • 提前规划好未来2到5年的峰值流量+容量

2.3 路由规则

  • 路由键自身散列均匀:可通过取模的形式
    • 例如:库路由规则:#user_id#%10;表路由规则:(#user_id#).intdiv(10)%100
  • 路由键自身不散列均匀:对路由键作hash
    • 例如:crc32(#user_id#)%8

2.4 其他挑战

  • 自增主键:分布式自增id
  • 分库分表数据迁移过程的双写:
    • 思路一:mq事务消息,对于老表的事务,通过mq异步对新表重新执行,失败则补偿
      • 缺点:异步极端情况下非实时(mq消息延迟),代码改动大
      • 优点:老表 与 新表的最终数据一致性可保证
    • 思路二:监听老表binlog,异步对新表执行。与思路一差不多
    • 思路三:代码内部双写事务(设置两个事务管理器来处理)
      • 优点:可通过切面形式实现,代码嵌入改造量小
      • 缺点:①极端情况下无法保证两个事务的一致性(已提交事务A,准备提交B时宕机);②双写流程中接口性能下降
  • 迁移过程整体思路:建分库分表—>双写(增量)—>刷存量—>数据核验—>切读流量—>切写流量—>下线双写—>收尾
  • 小部分业务场景下没有路由键:
    • 思路:空间换时间,建路由表(订单表以订单id为路由键;新建一张用户id与订单id的路由表,以用户id作为路由键)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1461216.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

​LeetCode解法汇总105. 从前序与中序遍历序列构造二叉树

目录链接: 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目: https://github.com/September26/java-algorithms 原题链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 描述: 给定两个整…

js 多对象去重(多属性去重)

需求中发现后端可能没有处理重复数据,这个时候前段可以直接解决。 在 JavaScript 中,可以使用 Set 数据结构来进行多对象的去重。Set 是 ES6 新引入的集合类型,其特点是元素不会重复且无序。 下面是一个示例代码,展示如何通过 S…

python基础教程—总结篇

这篇是Python基础教程系列的总结篇,这里这个专栏的地址:《Python教程》 首先必须声明一点,这是基础教程,所以面向的是新人,没有学过Python的同学,所以这套教程并没有涉及到比较难的并发编程模块&#xff0…

【Git教程】(二)入门 ——关于工作区与版本库、版本提交、查看信息、克隆、推送与拉回的简单介绍 ~

Git教程 入门 1️⃣ 准备Git 环境1.1 创建版本库1.2 首次提交1.3 显示历史 2️⃣ Git 的协作功能2.1 克隆版本库2.2 从另一版本库中获取修改2.3 从任意版本库中取回修改2.4 创建共享版本库2.5 用 push 命令上载修改2.6 Pull 命令:取回修改 🌾 总结 如果…

GitHub使用记录

1.创建仓库 2.删除仓库 翻到最下面 3.将本地文件同步到云端库上 Github——git本地仓库建立与远程连接(最详细清晰版本!附简化步骤与常见错误)_将本地仓库与远程仓库关联-CSDN博客 第三步参考:Github——git本地仓库建立与远程连…

聚道云软件连接器:高科技企业财务自动化,提升效率准确性!

客户介绍: 某互联信息技术有限公司是一家专业从事信息技术服务的高科技企业,在业内享有较高的知名度和影响力。近年来,公司业务快速发展,对信息化建设提出了更高的要求。 客户痛点: 在传统情况下,该公司的…

XML Map 端口进阶篇——常用关键字和格式化器详解

XML Map 端口是用于在不同XML之间建立关系映射的工具,允许通过拖拽操作实现源XML和目标 XML之间的数据字段映射,除此之外,XML Map 端口还提供了其它丰富多彩的功能,使用户能够更加灵活和高效的处理XML 数据映射任务,让…

Ubuntu20.04安装Carla0.9.15

文章目录 环境要求下载Carla解压Carla运行Carla测试官方用例创建python环境安装依赖包案例:生成车辆案例:测试自动驾驶 参考链接 环境要求 系统配置要求: 至少3G显存的GPU,推荐3060及以上的显卡进行Carla拟真。预留足够的硬盘空…

Maxwell - 增量数据同步工具

前言 今天来学习一个新的大数据小工具 Maxwell ,它和 Sqoop 很像。Sqoop主要用于在 Hadoop (比如 HDFS、Hive、HBase 等)和关系型数据库之间进行数据的批量导入和导出,而 Maxwell 则主要用于监控数据库的变化(通过监控…

Linux内核解读

来自鹅厂架构师 作者:aurelianliu 工作过程中遇到的调度、内存、文件、网络等可以参考。 1.os运行态 X86架构,用户态运行在ring3,内核态运行在ring0,两个特权等级。 (1)内核、一些特权指令,例…

【实战 JS逆向+python模拟获取+Redis token会话更新】实战模拟测试 某巴批发网 仅供学习

逆向日期:2024.02.20 使用工具:Node.js、python、Redis 加密方法:md5标准库 文章全程已做去敏处理!!! 【需要做的可联系我】 AES解密处理(直接解密即可)(crypto-js.js 标…

旧物回收小程序开发,开启绿色生活新篇章

随着科技的发展和人们生活水平的提高,物质生活的丰富带来了大量的废弃物。如何合理处理这些废弃物,实现资源的再利用,已成为社会关注的焦点。旧物回收小程序的开发与应用,为这一问题提供了有效的解决方案。本文将探讨旧物回收小程…

Python学习笔记——自定义函数(基础知识)

自定义函数非常简洁有效地实现了代码的复用,让程序编写、阅读、测试和修改变得更加容易。 下面记录Python自定义函数的使用。 1、定义函数: def describe_pet(pet_name,animal_typedog):显示宠物的信息print(f"\nI have a {animal_type}.")…

备战蓝桥杯---数学之矩阵快速幂基础

我们先不妨看一道题&#xff1a; 看见n的数据范围就知道直接按以前的递归写肯定狗带&#xff0c;那我们有什么其他的方法吗&#xff1f; 下面是分析&#xff1a; 我们就拿斐波那契数列试试手吧&#xff1a; 下面是AC代码&#xff0c;可以当作模板记&#xff1a; #include<b…

Android 基础技术——Framework

笔者希望做一个系列&#xff0c;整理 Android 基础技术&#xff0c;本章是关于 Framework 简述 Android 系统启动流程 当按电源键触发开机&#xff0c;首先会从 ROM 中预定义的地方加载引导程序 BootLoader 到 RAM 中&#xff0c;并执行 BootLoader 程序启动 Linux Kernel&…

2.20 Qt day1

一. 思维导图 二. 消化常用类的使用&#xff0c;以及常用成员函数对应的功能 按钮类QPushButton&#xff1a; mywidget.h&#xff1a; #ifndef MYWIDGET_H #define MYWIDGET_H#include <QWidget> #include<QPushButton>//按钮类 #include<QIcon>class MyW…

vscode 插件 Marp for VS Code 制作 ppt

话不多说&#xff0c;直接上图 用它来写幻灯片&#xff0c;简直不要太好用&#xff0c;如果你一直使用 markdown 语法写笔记的话&#xff0c;那么做 ppt 对你来说简直就是喝水&#xff1b; 在vscode 上面直接装一个Marp for VS Code插件就可以了 基本使用方法步骤 crtl win …

Flutter自定义tabbar任意样式

场景描述 最近在使用遇到几组需要自定义的tabbar或者类似组件&#xff0c;在百度查询资料中通常&#xff0c;需要自定义 TabIndicator extends Decoration 比如上图中的带圆角的指示器这样实现 就很麻烦&#xff0c; 搜出来的相关也是在此之处上自己画&#xff0c;主要再遇…

OpenLDAP接入NineData SSO

本文面向使用 OpenLDAP 管理人员账户信息的企业&#xff0c;提供将 OpenLDAP 接入单点登录&#xff08;SSO&#xff09;的最佳实践指南&#xff0c;以实现统一认证和授权管理。通过集成 OpenLDAP、phpLDAPadmin、Keycloak&#xff0c;您可以轻松通过 SSO 功能登录 NineData。 …

Android13 编译ninja failed with: exit status 137

描述 现象很奇怪&#xff0c;主机是ubuntu 18.04&#xff0c; 内存有32G&#xff0c;并且系统中有两份Android13代码&#xff0c; 有一份编译正常&#xff0c;另外一份编译不正常&#xff0c;一度以为是因为下载源码不齐全导致&#xff0c;后面仔细看日志&#xff0c;原来是内…