高性能MySQL.读书笔记(六)高可用性

什么是高可用性

每个应用对可用性的需求各不相同。在设定一个可用时间的目标之前,先问问自己,是不是确实需要达到这个目标。可用性每提高一点,所花费的成本都会远超之前;可用性的效果和开销的比例并不是线性的。需要保证多少可用时间,取决于能够承担多少成本。高可用性实际上是在宕机造成的损失与降低宕机时间所花费的成本之间取一个平衡。换句话说,如果需要花大量金钱去获得更好的可用时间,但所带来的收益却很低,可能就不值得去做。总的来说,应用在超过一定的点以后追求更高的可用性是非常困难的,成本也会很高,因此我们建议设定一个更现实的目标并且避免过度设计。幸运的是,建立2个9或3个9的可用时间的目标可能并不困难,具体情况取决于应用。

有时人们将可用性定义成服务器正在运行的时间段。我们认为可用性的定义还应该包括应用是否能以足够好的性能处理请求。有许多方法可以让一个服务器保持运行,但服务并不是真正可用。对一个很大服务器而言,重启MySQL之后,可能需要几个小时才能充分预热以保证查询请求的响应时间是可以接受的,即使服务器只接收了正常流量的一小部分也是如此。

如果服务器遭遇灾难性故障,可能多少都会丢失一此数据,例如最近已经写入二进制日志但尚未传递到备库中的中继日志中的事务。你能够容忍吗?大多数应用能够容忍;因为替代方案大多非常昂贵且复杂,或者有一些性能开销。例如,可以使用同步复制,或是将二进制日志放到一个通过DRBD进行复制的设备上,这样就算服务器完全失效也不用担心丢失数据。(但整个数据中心也有可能会掉电。)

一个良好的应用架构通常可以降低可用性方面的需求,至少对部分系统而言是这样的,良好的架构也更容易做到高可用。将应用中重要和不重要的部分进行分离可以节约不少工作量和金钱,因为对于一个更小的系统改进可用性会更容易。

 

如何实现高可用

提升平均失效时间(MTBF)

在分类整理宕机事件并追查导致宕机的根源时,我们发现,很多宕机本来是有一些方法可以避免的。我们发现大部分宕机事件都可以通过全面的常识性系统管理办法来避免。

l      测试恢复工具和流程,包括从备份中恢复数据。

l      遵循最小权限原则。

l      谨慎安排升级数据库服务器。

l      在升级前,使用诸如Percona Toolkit中的pt_uptrade之类的工具仔细检查系统

l      除非能证明有效,否则禁用查询缓存。

l      避免使用复杂的特性,例如复制过滤和触发器,除非确实需要。

l      定期检查复制完整性。

l      归档并清理不需要的数据。

l      养成习惯,评估和管理系统的改变、状态以及性能信息。

降低平均恢复时间(MTTR)

可以通过减少恢复时间来获得高可用性。事实上,一些人走得更远,只专注于减少恢复时间的某个方面:通过在系统中建立冗余来避免系统完全失效,并避免单点失效问题。

在降低恢复时间上进行投资是非常重要的,一个能提供冗余和故障转移能力的系统架构,则是降低恢复时间的关键环节。但实现高可用性不单单是一个技术问题,还有许多个人和组织的因素。组织和个人在避免宕机和从宕机事件中恢复的成熟度和能力层次各不相同。

团队成员是最重要的高可用性资产,所以为恢复制定一个好的流程非常重要。拥有熟练技能、应变能力、训练有素的员工,以及处理紧急事件的详细文档和经过仔细测试的流程,对从宕机中恢复有巨大的作用。但也不能完全依赖工具和系统,因为它们并不能理解实际情况的细微差别,有时候它们的行为在一般情况下是正确的,但在某些场景下去是个灾难。

避免单点失效

找到并消除的可能失效的单点,并结合切换到备用组件的机制,这是一种通过减少恢复时间(MTTR)来改善可用性的方法。如果你够聪明,有时候甚至能将实际的恢复时间降低至0,但总的来说这很困难。(即使一些非常引人注目的技术,例如昂贵的负载均衡器,在发现问题并进行反馈时也会导致一定的延迟。)

共享存储或磁盘复制

共享存储通常使用的是SAN。如果主服务器挂了,备用服务器可以挂载相同的文件系统,执行需要的恢复操作,并在失效服务器上的数据上启动MySQL。这个过程会更快,因为备用服务器已经启动,MySQL随时可以运行。当开始做故障转移时,检查文件系统、恢复InnoDB以及预热(Percona Server提供了一个新特性,能够把buffer pool保存下来并在重启后还原,在使用共享存储时能够很好地工作。MySQL5.6也有相似的特性)是最有可能遇到延迟的地方,但检测失效本身在许多设置中也会花费很长时间。

共享存储可以避免除存储外的其他任何组件失效所引起的数据丢失,并为非存储组件建立冗余提供可能。不过,共享存储本身仍是可能失效的单点。如果MySQL崩溃等故障导致数据文件损坏,可能会导致备用服务器也无法恢复。

主动-主动访问模式的共享存储怎么样?

在一个SAN、NAS或者集群文件系统上以主动-主动模式运行多个实例怎么样?MySQL不能这么做。因为MySQL并没有被设计成和其他MySQL实例同步对数据的访问,所以无法在同一份数据上开启多个MySQL实例。

MySQL中最普遍使用的磁盘复制技术是DRBD,并结合Linux-HA项目中的工具使用。

由于在备用DRBD设备上的写入必须要在主设备上的写入完成之前,因此备用设备的性能至少要和主设备一样,否则就会限制主设备的写入性能。带电池写缓存的RAID控制器对DRBD而言几乎是必需的,因为在没有这样的控制器时性能可能会很差。

DRBD和SAN很相似,DRBD是获得一份复制的数据,而SAN则是使用同一份数据副本,所以DRBD没有单点问题,但这两种情况下,当启动备用机器时,MySQL服务器的缓存都是空的。

DRBD有一些很好的特性和功能,但也有缺点:

l      DRBD故障转移无法做到秒以内。它通常至少需要几秒时间来将备用设备提升成主设备,这还不包括任何必须的文件系统恢复和MySQL恢复。

l      它很昂贵,因为必须在主动-被动模式下运行。热备服务器的复制设备因为处于被动模式,无法用于其他任务。连MySQL服务都是停用的。

l      对MyISAM表用处不大,因为MyISAM表崩溃后需要花费很长时间来检查和修复。

l      DRBD无法代替备份。如果磁盘由于蓄意的破坏、误操作、BUG或者其他硬件故障导致数据损坏,DRBD将无济于事。此时复制的数据只是被损坏数据的完美副本。你需要使用备份(或MySQL延时复制)来避免这些问题。

l      对写操作而言增加了负担。网络往返开销增加了写入延迟。使用DRBD导致服务器变慢最常见的原因是MySQL使用InnoDB并采取了完全持久化模式(innodb_flush_log_at_trx_commit=1),这会导致许多小的写入和fsync()调用,通过DRBD同步时会非常慢。

 

MySQL同步复制

当使用同步复制时,主库上的事务只有在至少一个备库上提交后才能认为其执行完成。

MySQL本身并不支持同步提制(MySQL5.5只支持半同步复制。)

这里可以在应用中加一个模拟方式,应用的业务在主库上提交后,马上连接到备库,调用函数MASTER_POS_WAIT检查备库是否同主库同步,但是这样会极大增加主库上业务提交返回的延迟。

基于复制的冗余

复制管理器是使用标准MySQL复制来创建冗余的工具。尽管可以通过复制来改善可用性,但也有一些“玻璃天花板”会阻止MySQL当前版本的异步复制和半同步复制获得和真正的同步复制相同的结果。复制无法保证实时的故障转移和数据零丢失,也无法将所有节点等同对待。

复制管理器通常监控管理三件事:应用和MySQL间的通信、MySQL服务器的健康度,以及MySQL服务器间的复制关系。它们即可以修改负载均衡的配置,也可以在必要的时候转移虚拟IP地址以使应用连接到合适的服务器上。大体上操作并不复杂:只需要确定写入不会发送到一个还没有准备好提供写服务的服务器上,并保证当需要提升一台备库为主库时记录下正确的复制坐标。

这听起来在理论上是可行的,但实际经验表明实际上并不总是能有效工作。事实上还很糟糕,有些时候最好有一些轻量级的工具集来帮助从觉的故障中恢复并以很低的开销获得较高的可用性。但很遗憾,到现在为止还没有一个好的工具集可以可靠地完成这一点。

最好不要尝试自己写复制管理器。异步组件有大量的故障形式,很多你从未亲身经历过,其中一些甚至无法理解,并且程序也无法适当处理,因此从这些异步组件中得到正确的行为相当困难,并且可能遭遇数据丢失的危险。事实上,机器刚开始出现问题时,由一个经验丰富的人来解决是很快的,但如果其他人做了一些错误的修复操作则可能导致问题更严重。

第一个复制管理器是MMM(http://mysql-mmm.org),但该工具集是否适用于生产环境部署的意见并不一致(尽管该工具的原作者也承认它并不可靠)。我们的许多客户在自动故障转移模式下使用该工具时确实遇到了许多严重的问题。它会导致健康的服务器离线,也可能将写入发送到错误的地点,并将备库移动到错误的坐标。

另一个是比较新的工具是MHA工具集(http://code.google.com/p/mysql-master-ha/),MHA是很好的测试集,可以防止一些MMM遇到的问题,但是我们对该工具集还没有更多的认识。

基于复制的冗余最终来说好坏参半。只有在可用性的重要性远比一致性或数据零丢失保证更重要时才推荐使用。例如,一些人并不会真正的从他们的网站功能中获得,而是从它的可用性中赚钱。谁会在乎是否出现了故障导致一张照片丢失了几条评论或其他什么东西呢?只要广告收益继续滚滚而来,可能并不值得花更多成本去实现真正的高可用性。但是还是可以通过复制来建立“尽可能的”高可用性。,当遇到一些很难处理的严重宕机时可能会有所帮助。这是一个大赌注,并且可能对大多数人而言太过于冒险,除非是那些老成的用户。

问题是许多用户不知道如何去证明自己有资格并评估复制“轮盘赌”是否适合他们。这有两个方面的原因。第一,他们并没有看到“玻璃天花板”,错误地认为一组虚拟IP地址、复制以及管理脚本能够实现真正的高可用性。第二,他们低估了技术的复杂度,因此也低估了严重故障发生后从中恢复的难度。一些人认为他们能够使用基于复制的冗余技术,但随后他们可能会更希望选择一个有更强保障的简单系统。

请不要认为我们将这些技术说得无所不能而把MySQL自身的复制贬得一团糟,那不是我们的本意。你可以为DRBD写出低质量的故障转移脚本,这很简单,就像为MySQL复制编写脚本一样。主要的区别是MySQL复制非常复杂,有很非常细小的差别,并且不会阻止你干坏事。

 

故障转移和故障恢复

提升备库或切换角色

虚拟IP地址或IP接管

中间件解决方案

可以使用代理、端口转发、网络地址转换(NAT)或者硬件负载均衡来实现故障转移和故障恢复。这些都是很好的解决方案,不像其它方法可能会引入一些不确定性(所有系统组件认同哪一个是主库吗?它能够及时并原子地更改吗?),它们是控制应用和服务器间连接的中枢。但是,它们自身也引入了单点失效,需要准备冗余来避免这个问题。

使用这样的解决方案,你可以将一个远程数据中心设置成看起来好像和应用在同一个网络里。这样就可以使用诸如浮动IP地址技术让应用和一个完全不同的数据中心开始通信。你可以配置每个数据中心的每台应用服务器,通过它自己的中间件连接,将流量路由到活跃数据中心的机器上。如果活跃数据中心的MySQL崩溃了,中间件可以路由流量到另外一个数据中心的服务器池中,应用无须知道这个变化。

MySQL代理,我推荐国内淘宝的Cobar,文档齐全,挺好用的。

在应用中处理故障转移

有时候让应用来处理故障转移会更简单或者更加灵活。例如,如果应用遇到一个错误,这个错误外部观察者正常情况下是无法察觉的,例如关于数据库损坏的错误日志信息,那么应用可以自己来处理故障转移过程。

虽然把故障转移处理过程整合到应用中看起来比较吸引人,但可能没有想象中那么有效。大多数应用有许多组件,例如cron任务、配置文件,以及用不同语言编写的脚本。将故障转移整合到应用中可能导致应用变得太过笨拙,尤其是当应用增大并变得更加复杂时。

但是将监控构建到应用中是一个好主意,当需要时,能够立刻开始故障转移过程。应用应该也能够管理用户体验,例如提供降级功能,并显示给用户合适的信息。

总结

增加运行时间,就要尝试去防止故障发生。悲剧的是,在预防故障发生时,它仍然会觉得你做的不够多,所以预防故障的努力经常会被忽视掉。

缩短恢复时间可能更复杂并且代价很高。从简单和容易的方面来说,可以通过监控来更快地发现问题,并记录大量的度量值以帮助诊断问题。

 

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页