#高可用与高性能mysql
首先要明晰两个概念:高可用和高性能,高可用和高性能在某些“方法论”或者实现上有相似的地方,可是其解决的问题和侧重点有所不一样:linux
高可用关注的是“持续可用问题”,我知道这是废话,那么何为“可用”,简单的的说“部分服务器挂了依然还能为用户提供服务”。衡量可用度有一个简单的指标:可用性,他是一个百分百比,具体为:在一段时间内服务器(组)正常提供服务的时间/总的时间100。若是你的服务器(组)在93%的状况下是正常的,咱们能够认为系统可用性为93%,固然对于单台服务器或者组还有其余指标参数,好比宕机时间(平均故障间隔时间),故障率等。 如下是github的状态页面:https://status.github.com 上面显示了系统可用性和网站的其余指标,能够做为用户的参考。nginx
高性能侧重于“规模”问题,当你的计算量很是大的时候,好比须要处理的数据量(请求量)很是大,或者解题步骤很是多或者繁杂的时候的时候咱们为了节省时间,提供更优质的服务须要考虑高性能问题;git
咱们假设程序和系统已经到最大优化,此时高性能依赖于服务器或者CPU的“堆叠(集群)”,一台服务器能够服务100人,两台服务器能够200人,固然这是理想状况。github
而高可用依赖于容错机制,好比失败以后采起什么措施,部分服务不可用以后的熔断措施等,固然备份也是高可用的一个具体措施(包括数据备份),哪怕是冷备:有的银行在采购的时候一样的设备会买两套,一套放在仓库里晾着,生怕天灾人祸而供货商货或者生产商不在继续生产该型号的设备,都是保证系统高可用的一周手段。web
##高性能和高可用的交叉点: 1,增长或者加强设备是相同的手段 咱们须要增长设备来实现其中一套设备挂了还能使用另外一套的方式来实现高可用(我的以为备机,不管是热备仍是冷备,是高可用的必要条件);一样增长设备,若是你能保证两套设备同时工做分担任务,他便能增长系统的性能(我以为吞吐量或者处理能力这些词更适合这个场景) 2,机制或者方法的交叉点 综合而言高可用通常有两种机制 a,保险丝熔断机制,这种机制在系统出现问题的时候将问题系统切出去,一面问题扩大化,航天飞机电路设计的时候大概会采用这种机制,当某一电路出现问题,为了不问题蔓延须要断开问题系统;软件种也须要这种机制,1,避免数据污染,2.避免请求堆积;这些问题之后能够讨论 b,线路(备份)切换机制 当系统出现异常,将备机自动或者手动切换过来的机制保证高可用的一种手段,切换的速度和精确度是系统可用性的一个标准。一样,在高性能集群,尤为是负载均衡集群种,将不一样请求“路由”到不一样的服务器也是一个必要的手段。redis
#高性能集群 高性能集群的方法取决于解决问题的性质,第一,问题(数据规模)是否是能够分解;第二,问题是否是能够分步 第一点关注数据或者规模的水平切分,就是将一块大数据或者一个大问题分解成不一样的小问题而后分布到不一样的节点处理,以后或许要汇总(这是mapReduce的核心思想),第二点倾向于将问题分红不一样的步骤,好比我本来须要先洗菜,而后再炒菜的,可是我得想想我能不能将洗菜和炒菜一块儿放在不一样的地方作(固然这个例子必然是不行,对吧),这是分布式计算的核心。算法
高性能集群分负载均衡集群和分布式计算集群;负载均衡集群为了解决规模分解问题,也就是水平切分; 分布式计算主要解决问题分步解决问题(从业务层面上讲);sql
举个例子:咱们假设完成一笔交易须要作一下几件事情:1,收到,并记录用户请求 2,将请求抽象成一个“交易订单”记录到数据库3,交易系统调用外部系统(能够是一个抽象了的金融基础服务,也能够是一个第三方,好比银行的外部服务)完成交易。3,银行或者外部系统通知交易系统,交易系统更新交易状态。4,交易系统同步返回用户,告知交易结果。5,交易系统调用短信服务,通知用户交易结果。数据库
作这些事情的服务器能够是不一样的,他们各自完成交易环节的一小部分,组合在一块儿完成了整个交易的流程。这些服务器实现不一样的功能,组合在一块儿是一个简单的分布式计算系统。分布式计算侧重于业务的垂直切分,侧重于业务层面的抽象和复用。
假设咱们发现交易系统单机没法应付目前的交易量,咱们须要对相同的交易系统部署两份(或者多份),让这个两份系统协同完成规模庞大的交易请求,此时他们将组成一组功能或者业务相同的交易负载均衡系统集群。
#正文 以上是准备工做,本文主要讨论“高性能集群”中的“负载均衡集群”,以及常规场景
#何为负载均衡以及为什么须要负载均衡 若是看了上面的准备概述,我以为就没有必要概念性的解释负载均衡了,咱们举个例子; 一家网站,为用户提供新闻资讯服务,刚起步的时候只有几百用户,咱们从成本出发准备一台虚拟机就能解决问题;可是随着网站访问量的增长,服务器资源耗今,用户反馈访问缓慢;须要两台或者更多的机器才能提供相同质量的服务,此时最节省成本的作法是再买2台机器(这相比于优化程序优化系统的成本要小的多,获得的收益也可能会好得多);3台服务器分担请求,理论上速度能够比原来快2倍。 那么问题来了:如何作?如何让一部分用户使用服务器A,另外一部分用户使用服务器B或者
##负载均衡集群的难题(如下其实都是一个问题): ###均衡问题 咱们有两台如出一辙的服务器,咱们更多的是但愿于两台服务器分担相同量的工做,而不是一台服务器很忙,而另两台台服务器很空闲。这每每很难,均衡问题不只仅取决于使用的方法或者策略,更取决于你对问题的预判,还有对现实问题的妥协。惟一的作法是不断的调整,积累经验逐步调优。 最基本也是最简单的均衡策略是:随机,固然还有轮询,基于后端最少使用或者人为权重; a.随机(Random): 不考虑实际状况,将问题或者请求随机的抛给两台服务器,就像跑硬币实验同样,访问量越高,就越均衡。 b.轮询(Round Robin): 不考虑后端服务器的实际状况,ABCABCABCABCABC。。。的方式依次给A,B,C三台服务器。 c.最少使用(LeastUse/LeastActive) 服务器选择相对空闲的机器最为下一个请求的处理者。这相对要复杂一些,由于实现这个策略须要负载设备和ABC三台台服务器通讯,获得AB和C的资源使用状况,固然对每一个后端的服务维护一个简单的计数器,调度最小活跃的机器也是一个很好的办法。 d.人为权重 本质上和随机没什么区别只是加入了人为因子(咱们能够理解随机策略每每得不到理想中均衡,须要人为设置一些因子做为调整,从而获得一个相对均衡) e.Hash、 使用hash或者一致性hash也是一种很好策略。 f.等。
###路由问题 路由或者线路切换问题是负载均衡的核心;(如何根据业务(这很重要)来实现路由策略是一个很大的难题;这须要考虑上面的“均衡问题”以及下面的“高可用当机均衡问题”,总而言之理由要作的不只仅是简单的线路上的问题。) 固然这里但讲线路切换问题: 线路切换每每依赖于网络
a.基于解析服务 采用中间人模式,好比: 请求每每不会直接到达前置服务器,更多的时候咱们使用DNS,他是一个中间人的角色,经过解析一个域名得到前置服务器的具体IP,随后再直接基于解析出来的IP地址;再好比dubbo的负载咱们能够认为是借助一个中间人(注册中心)
b.物理线路切换 简单粗暴的将网线拔下来,插在另外一台相同服务器上是简单粗暴解决可用性的一个好方法;然而你不可能作到一秒钟内插拔200次甚至更多;固然你能够说我在光纤种使用不一样长度的波,或者无线网络,我基于不一样的频段或者频道来作(实际上这种方式并不能很好的用于此种场景);就目前而言物理层线路切换的代价过高了。
c.三层、四层的转发 多数状况下基于IP层的转发是效率相对最好也是最广泛,基本硬件负载或者基于IPVS(LVS)的负载 只需解析从新封装三到四层的协议,他不会产生产生流量,也不须要维护两份链接句柄(七层转发种会提到),若是基于LVS软负载,基于linux net filter实现的转发,只需在linux内核层工做,避免了内核层和用户层的内存拷贝所带来的开销,甚至一台廉价的戴尔PC服务器就能稳定的到达10W的connection,没有足够的资金购买硬件负载,而访问量极高的系统建议采用此种方式。
d.七层转发 所谓的七层协议,就是应用层协议(有的书上会说五层 what ever/),开发经常使用的HTTP协议就是第七层的协议,mysql服务器或者redis本身实现的协议也是第七层协议;使用NGX或者HTTPD解析七层协议,而后rewrite是目前主流的解决办法;理由很简单:设置简单,维护方便,可自定义程度高。相比于LVS我相信绝大多数系统工程师对NGX会更加熟悉一些,这就带来了设置接单维护成本低,出了问题好解决;相比第三四层的协议,七层能够获得最大灵活度,解析HTTP协议得到URL得到用户传递过来某一个参数(好比sessionid等),简单的脚本或者正则就能定义个性化的转发策略。一样MYSQL proxy,AMIBA这种代理中间件经过解析MYSQL协议得到发送的SQL,经过简单的脚本语言(好比mysql 使用lua...)能够很灵活的更具SQL的内容来肯定具体的后方服务器,好比读写分离; 七层转发会产生流量的,同时七层代理服务器须要维护先后两个链接句柄(收到用户请求产生并维持一个服务链接,同时做为客户端向后端服务发起请求是另一个链接),这种转发模式通常在用户层实现,系统须要将内核层的数据拷贝到用户空间,完成解析和处理,再将用户空间的数据拷贝到内核空间,由linux的网络子系统转发,因此咱们说他会产生流量,相比三四层的转发其代价就要高不少。
e.基于客户端的路由 咱们在客户端实现请求具体去哪个服务器,经过配置一个服务器集群列表或者从“名字服务器”查找和下载这个列表,而后由客户端决定具体选择哪条线路的路由。redis官方的“哨兵”方案就是这种模式。
综述:DNS轮询属于中间人模式,dubbo一样采用中间人方式;三四七层转发属于代理模式(proxy);基于用户选择其实是讲路由的功能放到客户端实现,好比淘宝的数据中间件等采用了这种模式(dubbo是向注册中心获取服务提供者列表而且存储的,策略在注册中心实现,一样服务器提供者的负载策略也不彻底取决于服务的消费者);选择四层转发(交换)仍是七层不只仅取决于性能需求,更多的仍是取决于功能需求,好比你的系统要求经过URL的某个关键字或者参数来决定具体线路的,你可能就必须得选择“七层设备”来作代理了。
###代理模式的单点问题 上面简单的讲负载均衡的方案或者方式概括了一下;其中的代理转发模式会存在“单点故障问题”,好比最简单前置服务器为NGX,后面有两台TOMCAT服务器,当前置NGX当机或者出现问题的时候,服务必然会中断。那么咱们应该怎么解决这个问题呢?
其中的一个答案是VIP(虚IP),虚拟IP的方案是基于VRRP协议(虚拟路由冗余协议)的,它将局域网中的多台设备(路由)虚拟成一个设备,以一主多从的形式工做。经常使用的开源方案是KeepAlived,从名字上大概能够看出keepAliveD接管一个对外的虚拟IP,并在多台设备之间维持心跳。 如下是网上的图片很简单的说明了这个方案:
另外一个答案是:中间人模式,好比基于DNS的切换
###负载均衡的高可用以及当机均衡问题 理想状况下使用均衡策略慢慢优化,能够获得一个相对满意的结果,可世事难料,忽然有一天B服务器挂了,若是不作任何事情你可能会损失1/3的页面请求,实际上此时咱们须要将这部分的请求从新定位的好的A和C服务器,选择一个好的策略或者算法避免将请求过于集中的切换到单台服务器(这可能会一下拖垮那台服务器)是一个重要的问题;我将其称为“当机再均衡问题”;假设B挂了,咱们经过合理的算法将请求定位到AC服务器,系统勉强能够支撑,此时咱们的工程师将B服务器修复,从新加入集群,2台服务器又回到了原来的三台服务器的状态,这依然须要“再次均衡”不是吗?
#通用的负载均衡方案
通常而言经常使用四层协议相对单一(注意基于四层交换设备不能理解四层以上的协议) ##LVS+KeepAlived 其中LVS负责四层转发并维持会话(经过检索会话表和标记来维持会话链接,避免发往相同地方的数据包走不一样的线路),而KeepAliveD则负责接管虚拟IP和维持心跳;
##HAProxy+KeepAlived 其中HAProxy负责四层或者七层的转发,而keepAlived负责接管虚拟IP和维持心跳;HAProxy是经常使用负载均衡方案,相比于LVS而言HaProxy工做在用户层,提供更多更丰富的功能;
而七层协议相对就丰富了,各个软件根据本身的功能需求能够实现本身的七层协议; 经常使用的七层协议包括邮件协议,HTTP协议,FTP,对于各个关系数据库或者非关系数据库通常也都有本身的协议。要理解和解析这些协议才能完成七层转发。
经常使用的HTTP代理包括市场上多数的硬件负载,NGX等web服务器;
#负载均衡经常使用场景 ##前置WEB服务的负载均衡 通常指接入服务器,好比静态页面服务器,接入代理服务器等的负载均衡 一般对NGX这种接入服务器作集群须要在其前面加入一个四层或者七层代理,使用上面所说的通用方案是比较好的选择,固然你也能够将NGX做为NGX的七层代理(在NGX前面再放一个NGX),造成一个树形的结构(固然我没试过那么作,印象当中NGX+NGX的方案只在为了数据转发问题的状况出现过,大概是机房A的服务器做为接入,转发到B的接入服务器,我的以为不是一个负载均衡的常规手段)。
##业务服务器的负载均衡 这里的业务服务器通常指完成必定业务功能和逻辑服务组件,好比tomcat、jetty等,咱们须要在这些业务服务器前面加一个Proxy来做把控全局: ###NGX+业务服务器 好比nginx/apache httpd+tomcat/jetty等。ngx做为前置接入,基于七层的NGX或者HTTPD是一个很好的选择。 ##Redis的负载均衡 常规的基于四层的 ###单机Redis没法知足业务需求的两种状况 1,性能没法知足(这里一般指响应速度),通常采用复制+负载均衡的方式实现这种业务需求场景 2,容量没法知足,咱们知道Redis将数据放在内存当中,而实际上内存大小是有限的,好比一台服务器64G的内存,而实际上咱们的数据量达到了128G左右,咱们忽略系统和软件运行所占的内存开销,128G的数据没法放到64G的单机上去,必须分布到2台甚至3台服务器上去,这些服务器上的数据是不同的,并不能简单的经过复制来实现,这个时候咱们须要对数据“分块”,将部分数据放到A,其余数据放到B。 基本的由第一种状况致使的问题咱们可使用复制+通用七层,七层,客户端实现等方式来实现负载均衡;而第二种状况相对要复杂一些,咱们也能够经过七层或者客户端实现路由算法的方式来实现数据的分布存储问题。 a,haproxy+KeepAliveD b,twemproxy:推特开发的代理服务器,基于七层转发,同时支持redis和memcached协议。可以使用KeepAlived来解决代理的点单问题。
##MYSQL负载均衡 MYSQ,其实任何数据存储方案都面临上面Redis一节种提到的两个问题,对于数据库来讲,更多被提到的是分表分库,这是基于业务讨论的,通常简单只是为了知足访问性能的需求实现的“同构”的方案先对简单,通常的叫法是读写分离,该方案的核心思想是讲读数据和写数据分离,以免锁带来的开销,其实现的基本思路是复制(主从复制); 除了通用的基于四层的负载均衡方案(HAProxy/LVS),咱们还可使用一些中间件来完成MySQL的负载均衡,一般更业务挂钩的状况下咱们都会选择七层转发做为,咱们知道MYSQL有本身的协议,对于
a,关于MYSQL集群和分布式问题 mysql提供ndb引擎,这是一个分布式的存储引擎,相比于简单的同构集群(好比读写分离等)
b,分库分表问题 随着业务规模的增长
c,关于复制: 数据库的复制多数采用二进制日志的方式,也有按照快照的复制方法,相比而言各有各的优点,好比你经过updage语句(update xxx where id < 10000)咱们假设这条语句更新了10000条数据,若是经过顺序的日志的方式来实现,咱们在同步从服务器的时候只须要发送和处理一条一句,而经过快照的方式咱们则须要将这10000条数据(至少是diff部分)发送到
复制的通讯通常采用推(push)或者拉(pull)的方式,二者的区别在于谁是主动一方,以及实时性问题。采用推的方式能够简单的理解为主服务器上数据发生变化主动推送到从服务器上。拉的方式则是每一个一段时间完成一次同步。
##应用程序的负载均衡 每种语言有本身的实现,这里讲一下dubbo的负载均衡。 dubbo的核心是registery,这至关于一个目录查找服务,提供服务的组件向注册中心注册本身的服务,消费服务的组件向注册中心询问服务提供者的位置。 dubbo是分层设计的,每一层解决不一样的问题,详细的设计图能够再官方文档上找到,dubbo实现负载均衡的层是cluster这一层实现,该层的主要目标是为上层提供一个通用的统一的界面,实现负载均衡在上层的透明。对于用户来讲相同的服务能够在不一样的机器上部署多分,同时用户能够经过简单配置来实现负载策略,咱们也能够经过实现LoadBalance相关接口来定制本身的负载策略,而ZK的一致性hash算法能够解决服务的单点问题