扩展mysql

扩展mysql
  • mysql并不能完全利用高性能服务器的硬件,当cpu超过24个,内存超过128G时,mysql性能处于平缓,不在上升,所以在一个性能强大的服务器上运行多个实例,才更合理

  • mysql常见的扩展方式有:垂直扩展,水平扩展和向内扩展

  • 垂直扩展,也就是使用更好的机器

    • 单台服务器比多台服务器更容易维护和开发,扩展也更加简单
    • 但是入如果应用变得非常庞大,垂直扩展就会变得很困难
      • 首先是成本问题,高配置的机器比较昂贵,而且硬件是有上限的,不可能无限扩展
      • 另外如果使用了复制,主库升级配置后,一般不会配置一台和主库一样强大的从库,因为从库无法优先利用多核cpu和磁盘资源
  • 水平扩展,也就是将任务分配到多台计算机

    • 大概可以分为:复制、拆分和数据分片,最简单的方式就是通过复制把数据分发到多个服务器,读写分离,从库只做读操作;或者按照功能和职责对应用进行拆分,不同的节点执行不同的任务
    • 数据分片是将数据分割成多块,然后存储到不同的节点,如果是想扩展写容量,就必须进行分片,只有一台主库,无论有多少从库,写容量都是无法扩展的
    • 当然如果不是必要,尽量不要分片,先看能否通过调优和其他数据库来推迟分片
    • 分片应用会有一个数据库访问的抽象层,用以降低应用和分片数据之间通信的复杂度
    • 分片的最大问题,就是查找和获取数据,而且维护数据的一致性会很难,并且分片无法使用外键,对于重要且查询频繁的数据要减少分片,
    • 选择分区键的时候,尽可能选择那些能够避免跨分片查询的,保持分片足够小更容易管理,对数据的备份和恢复也更加容易,但是太小的分片也会导致产生很多的表,从而导致跨分片的查询增加
    • 跨分片的查询,需要对多个发片都执行一遍sql,最后在汇总,这类查询开销很大,最好能进行缓存
    • 如果可能,尽量让每个分片大小相同,这样可以在对分片进行分组的时候很容易平衡
  • 向内扩展,也就是定期对数据进行清理和归档,对冷热数据进行分离

    • 可以作为争取时间的短期策略,也可以作为处理大数据量的长期计划
    • 归档时需要在不影响事务处理的情况下进行,关键是要高效的找到要删除的行
分片
  • 分片有垂直和水平两种。
    • 垂直拆分比较简单,也就是本来一个数据库,因为表多所以数据多,这时候适合使用垂直切分,也就是把关系紧密(比如同一模块)的表切分出来放在一个库上
    • 如果表并不多,但每张表的数据非常多,这时候适合水平切分,把单表拆分为多个表
  • 垂直拆分为:垂直分库和垂直分表
    • 垂直分库:对象是整个表
      • 按业务对表进行分类,比如每个微服务单独使用一个数据库,如果有跨服务的关联查询,就必须通过数据冗余或程序二次加工来解决
    • 垂直分表:对象是列/字段
      • 基于数据库中的"列"进行,某个表字段较多,可以新建一张扩展表,将不经常用或字段长度较大的字段拆分出去到扩展表中,通过"大表拆小表",更便于开发与维护,而且一条记录如果占用空间过大会导致跨页问题,带来额外的开销
    • 优点:
      • 解决业务系统层面的耦合,业务清晰
      • 与微服务的治理类似,也能对不同业务的数据进行分级管理、维护、监控、扩展等
      • 高并发场景下,垂直切分一定程度的提升IO、数据库连接数、单机硬件资源的瓶颈
    • 缺点:
      • 部分表无法join,只能通过接口聚合方式解决,提升了开发的复杂度
      • 分布式事务处理复杂
      • 依然存在单表数据量过大的问题(需要水平切分)
  • 水平切分
    • 当一个应用难以再细粒度的垂直切分,或切分后数据量行数巨大,存在单库读写、存储性能瓶颈,就需要水平切分了
    • 水平切分分为库内分表和分库分表,根据表内某个字段的某种规则来将数据分散存储于不同的数据库或不同的表,水平切分后同一张表会出现在多个数据库/表中,每个库/表的内容不同
    • 水平切分的优点:
      • 不存在单库数据量过大、高并发的性能瓶颈,提升系统稳定性和负载能力
      • 应用端改造较小,不需要拆分业务模块
    • 缺点:
      • 跨分片的事务一致性难以保证
      • 跨库的join关联查询性能较差
      • 数据多次扩展难度和维护量极大

怎么划分分片:

  • 将数据分配到分片中的方法:固定分配和动态分配,两种方法都需要一个分区函数,输入分区键值获得行的分片

  • 固定分配也就是路由算法,分区函数只依赖于分区键的值:

    • 例如哈希和取模,实现简单开销低
      • 缺点是:
        • 如果分片不多,很难平衡分片间的负载
        • 不能自定义数据放在哪个分片上,有可能会使热点数据的竞争很激烈
        • 修改分片策略很困难,因为需要重新分配已有的数据
    • 或者以范围进行拆分数据,例如时间区间或ID区间
      • 优点:有利于将来的扩容,不需要做数据迁移。即时再增加表,之前的表的范围不需要改变
      • 缺点: 有热点问题,部分表的数据可能过热,而其他的表没有什么压力,例如以时间区间分片,存储的历史数据,很少会被查询
  • 动态分配:

    • 维护一个表作为分区的函数,分区键和分区号组成一条数据,通过分区键就可以获得分区号
    • 动态分配增加了分区函数的开销,但是可以对数据存储位置做细粒度的控制,
    • 而且可以生成不均衡的分片,对于服务器能力不同或者有特定目的时,很有帮助
  • 显示分配

    • 在插入的数据的时候,显示的选择分片,但是对于以有的历史数据会很难做到

部署分片的方法:

  • 每个节点的分片使用单一数据库,并且库名相同
  • 或者多个分片的表放在一个数据库,在表名上增加分片号
  • 每个分片使用一个数据库,库中包含应用所需要的全部表,在数据库名上增加分片号,表上就不需要增加分片号了,这样就不要专门编写查询了
  • 或者每个分片一个数据库,把分片号写到数据库名和表名

分库分表引入的问题:

  • 分库分表能有效的缓解单机和单库带来的性能瓶颈和压力,同时也带来了一些问题

  • 分布式事务(见seata)

  • 跨节点分页、排序、函数问题,将各个分片的结果集进行汇总和再次计算,最终将结果返回,对于分页查询,每次大量聚合后再分页,性能欠佳。

  • 跨节点 JOIN

    • 对于单库 JOIN,MySQL 原生就支持;对于多库,出于性能考虑,不建议使用 MySQL 自带的 JOIN,可以用以下方案避免跨节点 JOIN:
      • 全局表,也可看做是"数据字典表",对于这些稳定的共用数据表,可以在各个数据库中都保存一份;
      • 字段冗余: 一些常用的共用字段,在各个数据表中都保存一份;
      • 应用组装:应用获取数据后再组装。
      • 先确定表之间的关联关系,并将那些存在关联关系的表记录存放在同一个分片上,那么就能较好的避免跨分片join问题
  • 全局主键问题:在分库分表环境中,由于表中数据同时存在不同数据库中,因此需要单独设计全局主键,以避免跨库主键重复问题:

    • UUID 主键是最简单的方案,本地生成,性能高,没有网络耗时。但缺点也很明显,由于UUID非常长,会占用大量的存储空间;另外,作为主键建立索引和基于索引进行查询时都会存在性能问题,在InnoDB下,UUID的无序性会引起数据位置频繁变动,导致分页
    • 维护一个主键ID表:这个方案较为简单,缺点也明显:就是存在单点问题,强依赖主键ID表,当主键ID表异常时,整个系统都不可用,而且性能瓶颈限制在单台MySQL的读写性能
    • 或者维护多个主键ID表,不同表初始化一个不同的初始值,然后按指定的步长进行自增,可以解决单点故障,但是如果需要后续扩展比较麻烦
    • 数据库号段模式生成id:从主键ID表中取id时,一次取多个,每取一次把号段根据步长值进行递增,避免了频繁的访问数据库
    • 也可以使用 Redis 的自增原子性来生成唯一 id
    • Snowflake分布式自增ID算法(雪花算法)
  • 数据迁移、扩容问题

    • 一般面临性能和存储的瓶颈时,才会考虑分片设计,此时就不可避免的需要考虑历史数据迁移的问题。
    • 一般做法是先读出历史数据,然后按指定的分片规则再将数据写入到各个分片节点中。此外还需要根据当前的数据量和QPS,以及业务发展的速度,进行容量规划,推算出大概需要多少分片
    • 如果采用范围分片,只需要添加节点就可以进行扩容了,不需要对分片数据迁移。如果采用的是数值取模分片,扩容问题就相对比较麻烦。

分库分表的查询问题:

  • 查询精度要求很低
    • 如果对查询精度没有要求的话,当查询需要涉及到多个分表,每页的数量假设是20,那么第一页的数据,就是先查询每个分表的0-20条数据,然后把数据汇总排序后,返回前20条,以此类推
  • 查询精度一般-二次查询
    • 比如查询需要涉及到多分表,每页分页数量是20。
    • 那么可以根据 每页查询的数量(20) 整除 分表总数量,得到每个分表的查询数量。
    • 汇总所有分表的查询,排序得到最小的记录的标识符,并记录每个索引各自的最大的记录的标识符。
    • 在每个索引中,使用between 最小标识符 , 最大标识符 查询相应的结果后汇总排序,得到前十条记录返回。
  • mysql分库分表了,还要支持多种条件分页查询且精度要求很高,那么就需要把数据同步到其他更高效的数据库来查询,例如用ES来查
雪花算法
  • SnowFlake 中文意思为雪花,故称为雪花算法,是 Twitter(推特) 公司在其内部用于分布式环境下生成唯一 ID。在2014年开源 scala 语言版本。
  • 可以将雪花算法作为一个单独的服务进行部署,然后需要全局唯一 id 的系统,请求雪花算法服务获取 id 即可。
  • 对于每一个雪花算法服务,需要先指定 10 位的机器码,这个根据自身业务进行设定即可。例如机房号+机器号,机器号+服务号,或者是其他可区别标识的 10 位比特位的整数值都行。

雪花算法的原理就是生成一个的 64 位比特位的 long 类型的唯一 id。

  • 因为生成的 id 是正整数,所以最高 1 位固定值 0,如果是 1 就是负数了。
  • 接下来 41 位存储毫秒级时间戳,2^41/(1000606024365)=69,大概可以使用 69 年。
  • 再接下 10 位存储机器码,包括5位datacenterId 和5位 workerId,所以最多可以部署 2^10=1024 台机器。
  • 最后 12 位存储序列号。同一毫秒时间戳时,通过这个递增的序列号来区分。即对于同一台机器而言,同一毫秒时间戳下,可以生成 2^12=4096 个不重复 id。

使用注意事项:

  • 其实雪花算法每一部分占用的比特位数量并不是固定死的。例如你的业务可能达不到 69 年之久,那么可用减少时间戳占用的位数,雪花算法服务需要部署的节点超过1024 台,那么可将减少的位数补充给机器码用。
  • 雪花算法中 41 位比特位不是直接用来存储当前服务器毫秒时间戳的,而是需要当前服务器时间戳减去某一个初始时间戳值,一般可以使用服务上线时间作为初始时间戳值。
  • 对于机器码,可根据自身情况做调整,例如机房号,服务器号,业务号,机器 IP 等都是可使用的。对于部署的不同雪花算法服务中,最后计算出来的机器码能区分开来即可。

算法优缺点

  • 雪花算法有以下几个优点:
    • 高并发分布式环境下生成不重复 id,每秒可生成百万个不重复 id。
    • 基于时间戳,以及同一时间戳下序列号自增,基本保证 id 有序递增。
    • 不依赖第三方库或者中间件。
    • 算法简单,在内存中进行,效率高。
  • 雪花算法有如下缺点:
    • 依赖服务器时间,服务器时钟回拨时可能会生成重复 id。算法中可通过记录最后一个生成 id 时的时间戳来解决,每次生成 id 之前比较当前服务器时钟是否被回拨,避免生成重复 id。
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值