移动互联网、云计算和大数据的成熟和发展,让更多的好想法得以在很短的时间内实现为产品。此时,若是用户需求抓得准,用户数量将极可能得到爆发式增加,而不须要像以往同样须要精心运营几年的时间。然而用户数量的快速增加(尤为是短期内的爆发式增加),一般会让应用开发者有些吃不消,不得不面临一些严峻的技术挑战:如何避免由于单台机器当机致使服务不可用;如何避免在服务容量不足时,用户体验降低,等等。在系统构建之初就采用高可用和可伸缩架构,将能有效避免这些问题。
如何构建高可用可和可伸缩架构呢?七牛云存储首席架构师李道兵在3月22的「开发者最佳实践日」第十期沙龙活动上给出了本身的想法。他结合本身多年的实践经验,针对一些不太复杂的业务场景,从入口层、业务层、缓存层和数据库层四个层面细致讲述了如何构建高可用和可伸缩系统。但愿你们读完这篇文章,能以为高可用和可伸缩不是一个遥不可及的东西,投入不高的成本就能在项目早期把高可用和可伸缩归入架构设计之中。
如何实现高可用
入口层
入口层,一般指Nginx和Apache等层面的东西,负责应用(无论是Web应用仍是移动应用)的服务入口。咱们一般会将服务定位在一个IP,若是这个IP对应的服务器当机了,那么用户的访问确定会中断。此时,能够用Keepalived来实现入口层的高可用。例如,机器A 的IP是 1.2.3.4,机器 B 的 IP 是 1.2.3.5, 那么再申请一个 IP 1.2.3.6(称为⼼跳IP), 平时绑定在机器A上,若是A当机,IP会自动绑定在机器B上;若是B当机,IP会自动绑定在机器A上。对于这种形式,咱们将DNS绑定到心跳IP上,便可实现入口层的高可用。
但这个方案有一点小问题。第一,它的切换可能会有一到两秒的中断,也就是说,若是不是要求到很是严格的毫秒级就不会有问题。第二,对入口的机器会有些浪费,由于买了两台机器的入口,可能就只有一台机器用上。对一些长链接的应用可能会致使服务中断,这时候就须要客户端作配合作一些从新建立链接的工做。简单来讲,对于比较普通的业务来讲,这个方案就能解决一部分问题。
这里要注意,Keepalived在使用上会有一些限制。
两台机器必须在同一个网段,不是在同一个网段,没有办法实现互相抢IP。
内网服务也能够作心跳,但须要注意的是,之前为了安全咱们会把内网服务绑定在内网IP上,避免出现安全问题。但为了使用keepalived,必须监听在全部IP上(若是监听在心跳IP上,那么机器没有持有该IP时,服务没法启动),简单的方案是启用 iptables, 避免内网服务被外网访问。
服务器利用率降低,这时能够考虑作混合部署来改善这一点。
比较常见的一个错误时,若是有两台机器,两个公网IP,DNS上把域名同时定位到两个IP,就以为已经作了高可用了。这彻底不是高可用,由于若是一台机器当机,那么就有一半左右的用户没法访问。
业务层
业务层一般是由PHP、Java、Python、Go等写的逻辑代码构成的,须要依赖于后台数据库及一些缓存层面的东西。如何实现业务层的高可用呢?最核心的就是,业务层不要有状态,将状态分散到缓存层和数据库。目前你们一般喜欢将如下几种数据放入业务层。
第一个是session,即用户登陆相关的数据,但好的作法是将session放在数据库里,或者一个比较稳定的缓存系统中。
第二个是缓存,在访问数据库时,若是一个查询很慢,就但愿将这些结果暂时放到进程里,下次再作查询时就不用再访问数据库了。这种作法带来的问题是,当业务层服务器不仅一台时,数据很难作到一致,从缓存拿到的数据就多是错误的。
一个简单的原则就是业务层不要有状态。在业务层没有状态时,一台业务层服务器当掉了以后,Nginx/Apache会自动将全部的请求打到另一台业务层的服务器上。因为没有状态,两台服务器没有任何差别,因此用户彻底感觉不到。若是把session放在业务层里面的话,那么面临的问题是,这个用户之前是登陆在一台机器上的,这个进程死掉后,用户就会被登出了。
友情提醒:有一段时间比较流行cookie session,就是将session中的数据加密以后放在客户的cookie里,而后下发到客户端,这样也能作到与服务端彻底无状态。但这里面有不少坑,若是能绕过这些坑就能够这样使用。第一个坑是怎么保证加密的密钥不泄露,一旦泄露就意味着攻击者能够伪造任何人的身份。第二个坑是重放攻击,如何避免别人经过保存 cookie 去不停地尝试的验证码,固然也还有其余一些攻击手段。若是没有好办法解决这两方面的问题,那么cookie session尽可能慎用。最好是将session放在一个性能比较好的数据库中。若是数据库性能不行,那么将session放在缓存中也比放在cookie里要好一点。
缓存层
很是简单的架构里是没有缓存这个概念的。但在访问量上来以后,MySQL之类的数据库扛不住了,好比在SATA盘里跑MySQL,QPS到达200、300甚至500时,MySQL的性能会大幅降低,这时就能够考虑用缓存层来挡住绝大部分服务请求,提高系统总体的容量。
缓存层作高可用一个简单的方法就是,将缓存层分得细一点儿。好比说,缓存层就一台机器的话,那么这台机器当了之后,全部应用层的压力就会往数据库里压,数据库扛不住的话,整个网站(或应用)就会随之当掉。而若是缓存层分在四台机器上的话,每台只有四分之一,这台机器当掉了之后,也只有总访问量的四分之一会压在数据库上面,数据库能扛住的话,网站就能很稳定地等到缓存层从新起来。在实践中,四分之一显然是不够的,咱们会将它分得更细,以保证单台缓存当机后数据库还能撑得住便可。在中小规模下,缓存层和业务层能够混合部署,这样能够节省机器。
数据库层
在数据库层面实现高可用,一般是在软件层面来作。例如,MySQL有主从模式(Master-Slave),还有主主模式(Master-Master)都能知足需求。
MongoDB也有ReplicaSet的概念,基本都能知足你们的需求。
总之,要想实现高可用,须要作到这几点:入口层作心跳,业务层服务器无状态,缓存层减少粒度,数据库作一个主从模式。对于这种模式来说,咱们作的高可用不须要太多服务器,这些东西均可以同时部署在两台服务器上。这时,两台服务器就能知足早期的高可用需求了。任何一台服务器当机用户彻底无感知。
如何实现可伸缩
入口层
在入口层实现伸缩性,能够经过直接水平扩机器,而后DNS加IP来实现。但须要注意,尽管一个域名解析到几十个IP没有问题,可是不少浏览器客户端只会使用前几个IP,部分域名供应商对此有优化(如每次返回的IP顺序随机),但这个优化效果不稳定。
推荐的作法是使用少许的Nginx机器做为入口,业务服务器隐藏在内网(HTTP类型的业务这种方式居多)。另外,也能够把全部IP下发到客户端,而后在客户端作一些调度(特别是非HTTP型的业务,如游戏、直播)。
业务层
业务层的伸缩性如何实现?与作高可用时的解决方案同样,要实现业务层的伸缩性,保证无状态是很好的手段。此外,加机器继续水平部署便可。
缓存层
比较麻烦的是缓存层的伸缩性,最简单粗暴的方式是什么呢?趁着半夜量比较低的时候,把整个缓存层所有下线,而后上线新的缓存层。新的缓存层启动起来以后,再等这些缓存慢慢预热。固然这里一个要求,你的数据库能抗住低估期的请求量。若是扛不住呢?取决于缓存类型,下面咱们先能够将缓存的类型区分一下。
强一致性缓存:没法接受从缓存拿到错误的数据 (好比用户余额,或者会被下游继续缓存这种情形)。
弱一致性缓存:能接受在一段时间内从缓存拿到错误的数据 (好比微博的转发数)。
不变型缓存:缓存key对应的value不会变动 (好比从SHA1推出来的密码, 或者其余复杂公式的计算结果)。
那什么缓存类型伸缩性比较好呢?弱一致性和不变型缓存的扩容很方便,用一致性Hash便可;强一致性状况稍微复杂一些,稍后再讲。使用一致性Hash,而不用简单Hash的缘由是缓存的失效率。若是缓存从9台扩容到10台,简单Hash 状况下90%的缓存会立刻失效,而若是使用一致性Hash状况,只有10%的缓存会失效。
那么,强一致性缓存会有什么问题?第一个问题是,缓存客户端的配置更新时间会有微小的差别,在这个时间窗内有可能会拿到过时的数据。第二个问题是,若是扩容以后再裁撤节点,会拿到脏数据。好比 a 这个key以前在机器1,扩容后在机器2,数据更新了,但裁撤节点后key回到机器1,这时候就会拿到脏数据。
要解决问题2比较简单,要么保持永不减小节点,要么节点调整间隔大于数据的有效时间。问题1能够用以下的步骤来解决:
1. 两套hash配置都更新到客户端,但仍然使用旧配置;
2. 逐个客户端改成只有两套hash结果一致的状况下会使用缓存,其他状况从数据库读,但写入缓存;
3. 逐个客户端通知使用新配置。
Memcache 设计得比较早,致使在伸缩性高可用方面的考虑得不太周到。Redis在这方面有很多改进,特别是 @ngaut 团队基于 redis开发了 codis 这个软件,一次性地解决了缓存层的绝大部分问题。推荐你们考察一下。
数据库
在数据库层面实现伸缩,方法不少,文档也不少,此处不作过多赘述。大体方法为:水平拆分、垂直拆分和按期滚动。
总之,咱们能够在入口层、业务层面、缓存层和数据库层四个层面,使用刚才介绍的方法和技术实现系统高可用和可伸缩性。具体为:在入口层用心跳来作到高可用,用平行部署来伸缩;在业务层作到服务无状态;在缓存层,能够减少一些粒度,以方便实现高可用,使用一致性Hash将有助于实现缓存层的伸缩性;数据库层的主从模式能解决高可用问题,拆分和滚动能解决可伸缩问题。
本文中分享的这些技巧和方法,主要想帮助不太复杂的业务场景或者中小型应用快速搭建起高可用可伸缩的系统。关于如何构建高可用和可伸缩系统还有不少更为细节的点和实践经验值得探讨,望之后能与你们作更充分的交流。
参考来源:
七牛李道兵:高可用可伸缩架构实用经验谈
http://www.lai18.com/content/407147.htmlhtml