负载均衡的基本思路很简单:html
在一个服务器集群中尽量地的平均负载量。前端
基于这个思路,咱们一般的作法是在服务器前端设置一个负载均衡器。负载均衡器的做用是将请求的链接路由到最空闲的可用服务器上。如图 1,显示了一个大型网站负载均衡设置。其中一个负责 HTTP 流量,另外一个用于 MySQL 访问。
mysql
负载均衡有五个常见目的:算法
- 可扩展性。负载均衡对某些扩展颇有帮助,好比读写分离时从备库读数据。
- 高效性。负载均衡由于可以控制请求被路由到何处,所以有助于更有效的使用资源。
- 可用性。灵活的负载均衡方案可以大幅提升服务的可用性。
- 透明性。客户端无需知道是否存在负载均衡器,也不须要关系在负载均衡器的背后有多少机器。呈现给客户端看到的就是一个透明的服务器。
- 一致性。若是应用是有状态的(数据库事务、网站会话等),那么负载均衡器就能够将相关的查询指向同一个服务器,以防止状态丢失。
而对于负载均衡的实现,通常有两种方式:直接链接和引入中间件。sql
1 直接链接
有些人认为负载均衡就是配置在应用和 MySQL 服务器直接东西,但实际上这并非惟一的负载均衡方法。接下来咱们就讨论一下常见的应用直连的方法,及其相关注意事项。数据库
1.1 复制的读写分离
此种方式下,容易出现一个最大的问题:脏数据。一个典型的例子是,当用户评论了一篇博文,而后从新加载页面,却没有看到新增的评论。缓存
固然,咱们也不能由于脏数据的问题,就将读写分离弃之不用。实际上,对于不少应用,可能对脏数据的容忍度比较高,此时就能够大胆的引入此种方式。服务器
那么对于脏数据的容忍度比较低的应用,如何进行读写分离呢?接下来,咱们对读写分离再进一步区分,相信你总能找到适合本身的一款策略。网络
1) 基于查询分离架构
若是应用只有少数数据不能容忍脏数据,咱们能够将全部不能容忍脏数据的读和写都分配到 master 上。其它的读查询分配的 slave 上。该策略很容易实现,但若是容忍脏数据的查询比较少,极可能会出现不能有效使用备库的状况。
2) 基于脏数据分离
这是对基于查询分离策略的小改进。须要作一些额外的工做,好比让应用检查复制延迟,以肯定备库数据是否最新。许多报表类应用均可以使用这个策略:只须要晚上加载的数据复制到备库接口,并不关心是否是彻底跟上了主库。
3) 基于会话分离
这个策略比脏数据分离策略更深刻 一些。它是判断用户是否修改了数据,用户不须要看到其余用户的最新数据,只须要看到本身的更新。
具体能够在会话层设置一个标记位,代表用户是否作了更新,用户一旦作了更新,就将该用户的查询在一段时间内指向主库。
这种策略在简单和有效性之间作了很好的妥协,是一种较为推荐的策略。
固然,若是你的想法够多,能够把基于会话的分离策略和复制延迟监控策略结合起来。若是用户在 10 秒前更新了数据,而全部备库延迟在 5 秒内,就能够大胆的从备库中读取数据。要注意的是,记得为整个会话选择同个备库,不然一旦多个备库的延迟不一致,就会给用户形成困扰。
4) 基于全局版本 / 会话分离
经过记录主库日志坐标和备库已复制的坐标对比,确认备库是否更新数据。当应用指向写操做时,在提交事务后,执行一次 SHOW MASTER STATUS 操做,而后将主库日志坐标存储在缓存中,做为被修改对象或者会话的版本号。当应用链接到备库时,执行 SHOW SLAVE STATUS,并将备库上的坐标和缓存中的版本号对比。若是备库比主库记录点更新,就代表备库已更新对应数据,可放心的使用。
实际上,不少读写分离策略都须要监控复制延迟来决定读查询的分配。不过要注意的是,SHOW SLAVE STATUS 获得的 Seconds_behind_master 列的值并不能精确的表示延迟。咱们可使用 Percona Toolkit 中的 pt-heartbeat 工具更好的监控延迟。
1.2 修改 DNS 名
对于一些比较简单的应用,能够为不一样目的建立 DNS。最简单的方法是只读服务器拥有一个 DNS 名(read.mysql-db.com),给负责写操做的服务器起另一个 DNS 名(write.mysql-db.com)。若是备库可以跟得上主库,就把只读 DNS 名指向到备库,不然,就指向到主库。
这种策略很是容易实现,但有个很大的问题是:没法彻底控制 DNS。
- 修改 DNS 并非马上生效的,也不是原子性的。将 DNS 的变化传递到整个网络或者网络间传播都须要比较长的时间。
- DNS 数据会在各个地方缓存下,它的过时时间是建议性质,而非强制的。
- 可能须要应用或服务器重启才能使修改后的 DNS 彻底生效。
这种策略较为危险,即便能够经过修改 /etc/hosts 文件来避免 DNS 没法彻底控制的问题,但仍不失理想策略。
1.3 转移 IP 地址
经过在服务器间转移虚拟地址,来实现负载均衡。是否是感受和修改 DNS 很像?但实际上彻底是两码事。转移 IP 地址容许 DNS 名保持不变,咱们能够经过 ARP 命令(不了解 ARP,看这里)强制使 IP 地址的更改快速并且原子性的通知到局域网络上。
一个比较方便的技术是为每一个物理服务器分配一个固定的 IP 地址。该 IP 地址固定在服务器上,再也不改变。而后能够为每一个逻辑上的 “服务”(能够理解为容器)使用一个虚拟 IP 地址。
这样,IP 就可以很方便的在服务器间转移,无需从新配置应用,实现也更加容易。
2 引入中间件
上面的策略都是假定应用是和 MySQL 服务器之间链接的,可是许多负载均衡都会引入一个中间件,做为网络通讯的代理。它一边接受全部的通讯,另外一边将这些请求分发的指定服务器上,并将执行结果发送回请求机器。图 2 展现了此种架构。
2.1 负载均衡器
如今有许多负载均衡硬件和软件,但不多有专门为 MySQL 服务器设计的。Web 服务器一般更须要负载均衡,所以许多多用途的负载均衡设备都会支持 HTTP,而对其余用途则只有一些不多的基本特性。
MySQL 链接只是正常的 TCP/IP 链接,因此能够在 MySQL 上使用多用途负载均衡器。但因为缺乏 MySQL 专有的特性,所以会多一些限制:
- 分发请求是可能没法作到很好的负载均衡。
- 对 MySQL 会话支持不足,可能不知道如何把全部从单个 HTTP 会话发送的链接请求 “固定” 到一个 MySQL 服务器上。
- 链接池和长链接可能会阻碍负载均衡器分发链接请求。
- 不能很好的对 MySQL 服务器作健康和负载检查。
2.2 负载均衡算法
有不少算法用来决定哪一个服务器接受下一个链接。每一个厂商都有各自不一样的算法,有如下经常使用方法:
- 随机分配。从可用的服务器池中随机选择一个服务器来处理请求。
- 轮询。以循环顺序发送请求到服务器,例如:A、B、C、A、B、C。
- 哈希。经过链接的源 IP 地址进行哈希,将其映射到池中的同一个服务器上。
- 最快响应。将链接分配给可以最快处理请求的服务器上。
- 最少链接数。将链接分配给拥有最少活跃链接的服务器上。
- 权重。根据机器的性能等条件,给不一样机器配置不一样的权重,以便让高性能的机器能处理更多的链接。
上述各类方法没有最好,只有最适合的,这取决于具体的工做负载。
另外,咱们只描述了即时处理的算法。但有时候使用排队算法可能会更有效。例如,一个算法可能只维护给定的数据库服务器并发数量,同一时刻只容许不超过 N 个活跃事务。若是有太多的活跃事务,就将新的请求放到一个队列里,而后让可用服务器列表来处理。
2.3 一主多备间的负载均衡
最多见的复制结构就是一个主库加多个备库。这种架构的扩展性较差,但咱们能够经过一些方法结合负载均衡来得到更好的效果。
- 功能分区。对于厂家的功能包括报表、分析、数据仓库以及全文索引,配置一个或一组备库来扩展单个功能的容量。
- 保证备库跟上主库。备库存在的问题就是脏数据。对于此,咱们可使用函数 MASTER_POS_WAIT() 阻塞主库的操做,直到备库遇上了设置的主库同步点。另外,咱们还可使用复制心跳来检查延迟状况。
咱们不能也不该该在应用的开始就就想着把架构作成阿里那样的架构。最好的方式是实现应用当前所明确须要的,并为可能的快速增加作好预先规划。
另外,为可扩展性制定一个数字目标是颇有意义的,就像咱们为性能制定了一个精确目标,知足 10K 或 100K 并发同样。这样能够经过相关理论避免诸如序列化或交互操做的开销问题带入到咱们的应用中。
在 MySQL 扩展策略方面,典型的的应用在增加到很是庞大时,一般先从单个服务器转移到向外扩展的拥有备库的架构,再到数据分片或按功能分区。这里要注意的是,咱们不提倡诸如 “尽早分片,尽可能分片” 的建议。实际上,分片很复杂,并且成本很高,最主要的是不少应用可能根本不须要。与其花大成本去分片,还不如先去看看新的硬件和新版本的 MySQL 有哪些变化,也许这些新变化会给你带来惊喜。
总结
- 直接链接重 "分离",均衡器和算法有局限。
- 为扩展性量化指标。