高性能MySQL(第三版)第十一章:可扩展的MySQL

第十一章 可扩展的MySQL

  • 11.1 什么是可扩展性
  • 11.2 扩展MySQL
    • 11.2.1 向上扩展
    • 11.2.2 向外扩展
    • 11.2.3 多实例扩展
    • 11.2.4 集群扩展
    • 11.2.5 向内扩展
  • 11.3 负载均衡
    • 11.3.1 直接连接
    • 11.3.2 引入中间件
    • 11.3.3 一主多备间的负载均衡
  • 11.4 总结

11.1 什么是可扩展性

可扩展性。 即通过增加资源提升整个系统吞吐量的能力

一般会有如下的角度影响负载:

  • 数据量
  • 用户量 更多的用户,意味着更多的数据,更复杂的查询,更多的事务
  • 用户活跃度 容易造成热点
  • 相关数据集的大小 即关联数据,比如好友

可扩展性的数学表现:

  • 最简单的是线性的,资源翻倍,吞吐量翻倍
  • 但是由于有些工作是线性的,无法通过并发来提升,这样曲线就会趋于平缓
  • 再引入扩展带来的内部节点或者是线程间的通信,会造成曲线的不降反升
  • 考虑到有一些I/O密集型的应用,扩展只会可能变成全都读取内存,还有可能造成曲线上扬

11.2 扩展MySQL

通常系统初建时要考虑一点可扩展性。在扩展之前,要先压榨单机性能,比如算法调优等等。

11.2.1 向上扩展

向上扩展就是换CPU,磁盘等等。对部分应用来说这是唯一需要做的。

优点:

  • 单台服务器比多台服务器更加容易开发和维护,能显著节省开销
  • 在单台服务器上备份和恢复应用同样简单;
  • 无需关心一致性;

为了能够更好的在大型服务器上运行MySQL,一定要尽量使用最新的版本。
如果应用变得非常庞大,向上扩展可能就没有办法。

11.2.2 向外扩展

向外扩展有时也称为横向扩展或者水平扩展,策略划分为三个部分:复制、拆分,以及数据分片(sharding)。

最简单的扩展方法是通过复制将数据分发到多个服务器上,然后将备库用于读查询,即读写分离。

另外一个比较常见的向外扩展方法是将工作负载分布到多个“节点”。许多大型的MySQL应用不能自动分布负载,就算有也没有做到完全的自动化。

一个节点可能就是一台服务器,如果设计冗余,那么一个节点通常是下面的某一种:主主复制,一主多备复制,一主多备DRBD复制,共享存储。大多数情况下,一个节点内的所有服务器应该拥有相同的数据。我们倾向于把主主复制架构作为两台服务器的主动被动节点。

安功能拆分
按功能拆分,或者说按业务拆分,意味着不同的节点执行不同的任务。将独立的服务节节点分配给不同的应用,这样每个节点只包含特定应用的数据,即按库划分。

另一个可能的按功能划分方法是对单个服务器的数据进行划分,确保划分的表集合之间不会执行关联操作,即按表划分。

但是功能划分不能无限地进行扩展,因为如果一个功能区哉被捆绑到单个MySQL节点,就只能进行垂直扩展。如果进行了太多的功能划分,以后就很难采用更具扩展性的设计了。

数据分片
在目前用于扩展大型MySQL应用的方案中,数据分片是最通用且最成功的方法。它把数据分割成一小片,或者说一块,然后存储到不同的节点中。

数据分片和某些类型的按功能划分联合使用时非常有用。大多数分片系统也有一些“全局”的数据不会被分片(例如城市列表或者登录数据)。全局数据一般存储在单个节点上,并且通常保存在类似 memcached 这样的缓存里。

实际上,大多数应用只会对需要的数据做分片,通常是那些将会增长得非常庞大的数据。

如果事先知道应用会扩大到很大的规模,并且清楚按功能划分的局限性,就可以跳过中间步骤,直接从单个节点升级为分片数据存储。事实上,这种前瞻性可以帮你避免由于粗糙分片方案带来的挑战。

采用分片的应用常用一个数据库访问抽象层,用以降低应用和分片数据存储之间通信的复杂度,但无法完全隐藏分片。因为相比数据存储,应用通常更了解跟查询相关的一些信息。

  • 用的最多
  • 扩展写容量必须分片
  • 要有足够大的数据量以及业务可分的时候才分。
  • 一般可以按照用户ID,时间等进行分片

分片?还是不分片?
答案很简单:如非必要,尽量不分片。首先看是否能通过性能调优或者更好的应用或数据库设计来推迟分片。如果能足够长时间地推迟分片,也许可以直接购买更大的服务器,升级MySQL到性能更优的版本,然后继续使用单台服务器,也可以增加或减少复制。
简单的说,对单台服务器而言,数据大小或负载变得太大时,分片将是不避免的,如果不分片,而是尽可能地优化应用,系统能扩展到什么程度呢?答案可能会让你很惊讶。有些非常受欢迎的应用,你可能以为从一开始就分片了,但实际上直到已经值数十亿美元并且流量极其巨大也还没有采用分片的设计。在没有必要的情况下采用分片的架构来构建应用会步履维艰。

选择分区键
数据分片最大的挑战就是查找和获取数据:如何查找数据又取决于如何分片。我们的目标就是对重要并且频繁查询的数据减少分片(可扩展性法则的其中一个条件就是避免不同节点间的交互)

  • 分区键 , 决定哪一行存储在哪个位置。
  • 常常是分厂重要的实体主键,会尽量避免跨库的查询和通讯。 特别是不能定位- 在哪个节点上,需要所有节点扫描。
  • 可以使用ER图找到处于中间的点

多个分区键
这种情况可以把要分区的键的表的关键字段在其中另外一个键的表中做冗余。来做关联查询

问题1: 跨片查询和聚合。 可以使用汇总表,搜索引擎
问题2:一致性。外键失效,需要应用保证

分配数据、分片和节点

  • 尽可能地让分片的大小比节点容量小很多,这样就可以在单个节点上存储多个分片。
  • 保持分片足够小更容易管理。
  • 小一点的分片也便于转移。有助于重新分配容量,平衡各个节点的分片。

在节点上部署分片
常用方法:

  • 每个分片使用单一数据库,并且数据库名要相同。
  • 将多个分片表放到一个数据库中,在每个表名上包含分片号。
  • 为每个分片使用一个数据库,并在数据库中包含所有应用需要的表。
  • 每个分片使用一个数据库,并在数据库名个表名中包含分片号。
  • 在每个节点上运行多个MySQL实例,每个实例上有一个或者多个分片。

数据分配策略
都会有分区方法,传入分区键, 输出分区号

固定分配
分区方法只依赖分区键。
比如哈希函数和取模运算。 CRC32();

特性:

  • 简单开销低
  • 如果分片大但数量少,则不好分配负载
  • 无法自定义数据放到哪个分片上。 比如活跃度。 分片切分的小一点可以缓解这个问题
  • 修改策略困难

动态分配
利用外部资源,可以是表或者是目录服务器等等。来记录分区键和分区iD之间的关系。 这种可以很灵活。

通常都是两种结合使用。 比如先用静态的方式处理一下分区键,再用动态的方式把处理后的结果映射到分区Id上

显示分配
就是分配策略本身已经显示成为了分区键的一部分。能直接看出来。

重新均衡分片数据
可以使用动态分配策略。相对随机的分配。
并且还能够根据每个服务器的负载情况选择关闭 。
还可以为想均衡的表简历备库,然后修改访问机制,各负责一般的数据,然后删除不用的数据。

唯一ID
分片了,自增主键就不好用了。
可以有如下的方案搞:

  • auto_increment_increment和auto_increment_offset. 设置步长和偏移量来解决,比如第一个表是1,3,5. 第二个表是2,4,6
  • 全局表自增来生成唯一
  • 使用memcached的incr(),也可以用redis
  • 使用复合值,分片id_自增
  • 使用guid

分片工具
基于分片的系统,如果应用创建多个数据源分别访问分片就有点数不过去了,应该有抽象层。其应该具有如下的功能:

  • 连接到正确的分片并执行查询
  • 分布性一致性校验
  • 跨分片关联操作
  • 跨分片结果集聚合
  • 锁和实物管理
  • 对新分片的处理能力。

有很多不错的工具可用:

  • Hibernate Shards
  • HiveDB
  • Sphinx 全文检索引擎,在分片中的聚合关联查询等有用。

11.2.3 多实例扩展

为了更大的压榨CPU的性能,可以单机多实例多分片的部署 。
还可以通过虚拟化技术 。
这种扩展可能会带来I/O的瓶颈,可以使用多网卡的方式。

11.2.4 集群扩展

云,集群。这个是理想的状态,数据库能够弹性扩展,自动分片等等。
Mysql收到了No SQL的挑战,其中一点就是Nosql可以更好地集群,但是Nosql存在很多其他的问题,比如事务,查询上的弱点,其为了解决这些弱点,也越来越像关系型数据库。

NDB Cluster是一个可扩展的数据库,既可以使用NoSQL,又可以使用Mysql存储引擎,我们经常可以选用的类似的组件有:

  • Mysql Cluster
  • Clustrix
  • ScaleBase
  • Akiban 查询加速器,可以加在备库上,目前没有生产环境的使用

11.2.5 向内扩展

对不需要的数据进行归档和清理

需要考虑如下的问题:

  • 对应用的影响 不影响业务,高效的找到行,并小块小块的删除,以平衡一次归档的行数锁,事务负载间的平衡
  • 数据一致性
  • 避免数据丢失
  • 接触归档, 要有一个补充方案,如当前找不到了,应该设计高效的去归档数据部分检查的策略

保持活跃数据独立

  • 分表 分成热表和不热表有利于高效的利用缓存。缓存每次缓存一页,一页中有10%热的可能就会整页缓存,造成了90浪费,分表之后,热度数据可能占据整个页的80%,效率更高。
  • 分区
  • 基于时间数据分区 把最近的时间的数据放到高速硬盘中。可以使用动态分片来实现这种策略。使用如下的分片目录表:users(user_id, shard_new, shard_archive, archive_timestamp)。定时数据转移。记录新分片和旧分片以及切换分片的时间。

11.3 负载均衡

前端负载均衡器,根据服务器性能情况分发请求。
目的: 更有效的使用资源。 可用性提高(保证有服务有用), 透明。
跟分片和复制关系密切,可以部署在任何一个环节,比如应用前端,数据库前端等
可选的方案: DNS, LVS, TCP代理等等。普遍使用F5, HAProxy

11.3.1 直接连接

应用直连。不使用中间件完全用业务来判断负载,如选择不同的备库做不同的逻辑。

  1. 读写分离
    写用主库,读用主备分担,实时性的用主库,其他用备库
    让应用检查复制延迟,提高容忍脏数据的能力
    基于会话,自己修改的数据查看时查主库。
    基于版本,查看下备库的时间戳版本类型的字段查看下如果太旧就查主库
  2. 修改DNS
    比较粗的方式,把主库和备库绑定在不同的DNS中,然后切换。但是因为不是原子的,会被缓存等等原因并不是很好用。

11.3.2 引入中间件

  1. 负载均衡器
    1.一般的负载均衡器都是HTTP协议的,但是Mysql需要TCP协议的,因此要使用能支持TCP协议的,但是这不是专门为Mysql设计的,还是会有一些限制。
    不能很好的均衡,因为无法知道负载权重
    2.均衡器并不能很好的分辨Mysql连接的状态,保证他能尽量练到固定的服务器,提高缓存效率
    3.线程池可能用不到负载分发
    4.要求均衡器支持TCP分发及TCP端口监测等等。

  2. 负载均衡算法
    1.随机
    2.轮询 依次发送请求
    3.最少连接数 适合有新服务器加入的时候,因为加入了新的服务器,其响应速度没有缓存会比较慢,因此先把最少连接数
    4.最快响应
    5.哈希 对源IP进行hash
    6.权重
    7.排队,设置最大连接数。排队处理

11.3.3 一主多备间的负载均衡

  1. 功能分区
    报表,分析,数据仓库,全文索引等
  2. 过滤和数据分区
    通过复制的过滤功能,将不同的数据分配在不同的备库上
  3. 保证备库跟上主库 MASTER_POS_WAIT()可以保证主库等待备库同步
  4. 同步写操作, 有半同步机制

11.4 总结

正确地扩展MySQL并没有看起来那么美好。从第一天就建立一个Facebook架构,这并不是正确的方式。最好的策略是实现应用所明确需要的,并为可能的快速增长做好预先规划,成功的规划是可以为任何必要的措施筹集资金以满足需求。

在MySQL扩展策略方面,典型的应用在增长到非常庞大时,通常先从单个服务器转移到向外扩展的拥有读备库的架构,再到数据分片和按功能分区。我们并不同意那些提倡为每个应用“尽早分片,尽量分片”(shardearly, shard often)的建议。这很复杂且代价昂贵,并且许多应用可能根本不需要。可以花一些时间去看看新的硬件和新版本的MySQL有哪些变化。

当存在多个服务器时,可能出现跟一致性或原子性相关的问题。我们看到的最普遍的问题是缺少会话一致性。负载均衡器可以解决这个问题,但它本身也有一些问题。

你可能感兴趣的:(数据库)