0%

mysql08_扩展&高可用

扩展mysql

什么时候可扩展性?

简要地说,可扩展性表明了当需要增加资源以执行更多工作时系统能够获得划算的等同提升( equal bang for the buck)的能力。

缺乏扩展能力的系统在达到收益递减的转折点后,将无法进一步增长。

向上扩展

向上扩展(有时也称为垂直扩展)意味着购买更多性能强悍的硬件,对很多应用来说这是唯一需要做的事情。

这种策略有很多好处。例如,单台服务器比多台服务器更加容易维护和开发,能显著节约开销。

在单台服务器上备份和恢复应用同样很简单,因为无须关心一致性或者哪个数据集是权威的。

从复杂性的成本来说,向上扩展比向外扩展更简单。

向外扩展

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

主从读写分离

主库写入数据,从库提供读服务或者跑大量统计任务。

拆分

按功能拆分(垂直分库)

按系统的不同功能,进行数据库拆分,微服务化每个应用用自己单独的数据库。

垂直拆分表

一般是表中的字段较多,将不常用的, 数据较大,长度较长(比如text类型字段)的拆分到“扩展表“。

数据分片

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

大多数分片系统也有一些“全局的”数据不会被分片(例如城市列表或者登录数据)。全局数据一般存储在单个节点上并且通常保存在类似redis这样的缓存里。

大多数应用只会对需要的数据做分片——通常是那些将会增长得非常庞大的数据。用户数达到5亿,那么就可能需要对用户数据分片。用户的定单数据,非常庞大,并且还会越来越多也需要做数据分片。

切分策略

动态映射分配

将ID和库的Mapping关系记录在一个单独的库中。

优点:ID和库的Mapping算法可以随意更改。
缺点:引入额外的单点。

范围切分

range分片 : 比如按照时间区间或ID区间来切分。

优点:单表大小可控,天然水平扩展。
缺点:无法解决集中写入瓶颈的问题,存在的数据热点问题,热点会出现在最新的几台机器上。

hash分片

hash分片一定要做好容量规划,如果需要扩容,重新计算hash值代价非常大。可以先规划足够大的容量,比如一次性份1024个表,尽量避免再次扩容

刚开始可以一个数据库多个数据分片,随着业务量的上升,可以逐渐过渡到一个数据库一个分片。

唯一键方案

这个方案也很多,主流的有那么几种:

利用数据库自增ID

优点:最简单。
缺点:单点风险、单机性能瓶颈。

利用数据库集群并设置相应的步长

优点:高可用、ID较简洁。
缺点:需要单独的数据库集群。

Twitter Snowflake

优点:高性能高可用、易拓展。
缺点:需要独立的集群以及ZK。

UUID/Random算法

优点:简单。
缺点:生成ID较长,有重复几率。

根据业务 时间戳+业务编号

结合自身业务,实现唯一键 如 时间戳+用户标识码+随机数

优点:简单,基本不会重复
缺点:长度稍长,性能要比int/bigint的稍差等。

负载均衡

读写分离

主库写入数据,从库提供读服务或者跑大量统计任务。

DNS负载均衡

这是一个比较粗糙的负载均衡技术。

最简单的方法是只读服务器拥有一个DNS名,而给负责写操作的服务器起另外一个DNS名。如果备库能够跟上主库,那就把只读DNS名指定给备库,当出现延迟时,再将该DNS名指定给主库。

这种DNS技术非常容易实现,但也有很多缺点。最大的问题是无法完全控制DNS。

  • 修改DNS并不是立刻生效的,也不是原子的。将DNS的变化传递到整个网络或在网络间传播都需要比较长的时间。
  • DNS数据会在各个地方缓存下来,它的过期时间是建议性质的,而非强制的。
  • 可能需要应用或服务器重启才能使修改后的DNS完全生效
  • 多个IP地址共用一个DNS名并依赖于轮询行为来均衡请求,这并不是一个好主意。因为轮询行为并不总是可预知的。
  • DBA可能没有权限直接访问DNS。

转移IP地址(虚拟ip、LVS)

些负载均衡解决方案依赖于在服务器间转移虚拟地址,一般能够很好地工作。

这听起来和修改DNS很像,但完全是两码事。

服务器不会根据DNS名去监听网络流量,而是根据指定的IP地址去监听流量,所以转移IP地址允许DNS名保持不变。

你可以通过ARP(地址解析协议)命令强制使IP地址的更改快速而且原子性地通知到网络上。

**一个比较方便的技术是为每个物理服务器分配一个固定的IP地址。该IP地址固定在服务器上,不再改变。然后可以为每个逻辑上的“服务”使用一个虚拟IP地址。**它们能够很方便地在服务器间转移,这使得转移服务和应用实例无须再重新配置应用,因此更加容易。

中间件负载均衡

负载均衡器

在市场上有许多负载均衡硬件和软件,但很少有专门为 MySQL服务器设计的。web服务器通常更需要负载均衡,因此许多多用途的负载均衡设备都会支持HTTP,而对其他用途则只有一些很少的基本特性。

MySQL连接都只是正常的TCP/IP连接,所以可以在 MySQL上使用多用途负载均衡器。但由于缺少 MySQL专有的特性,因此会多一些限制。(HAProxy)

常见负载均衡算法

  1. 随机 负载均衡器随机地从可用的服务器池中选择一个服务器来处理请求。
  2. 轮询 负载均衡器以循环顺序发送请求到服务器,例如:A,B,C,A,B,C。
  3. 最少连接数 下一个连接请求分配给拥有最少活跃连接的服务器。
  4. 最快响应 能够最快处理请求的服务器接受下一个连接。
  5. 哈希 负载均衡器通过连接的源IP地址进行哈希,将其映射到池中的同一个服务器上。每次从同一个IP地址发起请求,负载均衡器都会将请求发送给同样的服务器。只有当池中服务器数目改变时这种绑定才会发生变化。
  6. 权重 负载均衡器能够结合使用上述几种算法。

MySql高可用(复制原理)

复制基本原理

在详细介绍如何设置复制之前,让我们先看看 MySQL实际上是如何复制数据的。总的来说,复制有三个步骤:

  1. 在主库上把数据更改记录到二进制日志( Binary Log)中(这些记录被称为二进制日志事件)。
  2. 备库将主库上的日志复制到自己的中继日志( Relay Log)中。
  3. 备库读取中继日志中的事件,将其重放到备库数据之上。

IO线程是单线程的,SQL线程是可以多线程的

binlog的三种格式

statement 基于语句的复制

row基于行的复制

mixed混合复制

为什么会有mixed格式的binlog?

因为有些statement格式的binlog可能会导致主备不一致,所以要使用row格式。

但row格式的缺点是,很占空间。比如你用一个delete语句删掉10万行数据,用statement的话就是一个SQL语句被记录到binlog中,占用几十个字节的空间。但如果用row格式的binlog,就要把这10万条记录都写到binlog中。这样做,不仅会占用更大的空间,同时写binlog也要耗费IO资源,影响执行速度。

所以,MySQL就取了个折中方案,也就是有了mixed格式的binlog。mixed格式的意思是,MySQL自己会判断这条SQL语句是否可能引起主备不一致,如果有可能,就用row格式,否则就用statement格式。

复制过滤器

使用选项 binlog_do_db和 binlog_ ignore_db来控制过滤被复制端的输出。一般不启用这两个参数,只控制从库过滤。

常见的部署架构

主从

最简单的

主主

自增id设定步长和起始位置,来保证不冲突,实现主主复制

循环复制问题

业务逻辑在节点A上更新了一条语句,然后再把生成的binlog 发给节点B,节点B执行完这条更新语句后也会生成binlog。(我建议你把参数log_slave_updates设置为on,表示备库执行relay log后生成binlog)。

那么,如果节点A同时是节点B的备库,相当于又把节点B新生成的binlog拿过来执行了一次,然后节点A和B间,会不断地循环执行这个更新语句,也就是循环复制了。这个要怎么解决呢?

**当复制SQL线程读中继日志时,会丢弃事件中记录的服务器ID和该服务
器本身ID相同的事件,从而打破了复制过程中的无限循环。**在某些复制拓扑结构下打破无限循环非常重要,例如主-主复制。

主从延迟来源

  1. 从库性能比较差
  2. 备库的压力大 一般可以这么处理:一主多从。除了备库外,可以多接几个从库,让这些从库来分担读的压力。
  3. 大事务 一次删除大量数据或者大表DDL

复制的方式

异步复制

默认的复制方式,存在数据丢失的可能性

半同步复制(防止脑裂)

为了解决默认复制方式,存在数据丢失的问题,引入半同步复制,也就是semi-sync replication

semi-sync做了这样的设计:

  1. 事务提交的时候,主库把binlog发给从库;
  2. 从库收到binlog以后,发回给主库一个ack,表示收到了;
  3. 主库收到这个ack以后,才能给客户端返回“事务完成”的确认。

也就是说,如果启用了semi-sync,就表示所有给客户端发送过确认的事务,都确保了备库已经收到了这个日志。