充分发挥服务器的各项资源

在当前的网站架构中,经常会有较多的角色分工,如:缓存服务(文件型)、缓存加速服务(内存型)、PHP/Java 计算服务和数据库服务等等。每种服务对服务器的资源占用各有不同,例如:缓存加速服务就需要大量的内存,而 PHP/Java 计算服务则需要占用大量的 CPU 资源。如何充分发挥单机的资源利用,往往是运维的同学负责规划。认为的来进行分配,必然会有所疏漏,也正因此现在发展出 VMware 类虚拟服务器的云计算,可以实现一定的自动分配资源,达到节省成本的效果。

但使用 VMware 类方案并不太适合单个企业选用,原因一:架设一套自主的虚拟机集群,会产生软硬件成本,二:虚拟服务器系统本身要消耗掉一小部分性能。或者我们可以考虑以下方案 :) 可在原有的业务基础上进行简单的梳理,以达到需要的效果。

我们把服务器抽象出,磁盘、内存和 CPU 三项资源。服务角色可把 PHP/Java 归为计算类型,而 Memcached/Redis 等归为内存类型,对文件/页面缓存归为磁盘类,数据库较为特殊,它对三类资源的需求都比较高,将其定位特殊的全需求类型。

现在资源和服务类型都很清晰了,那么我们就可以针对服务器的三项资源进行网络化,抽象出三小块分布式服务。PHP/Java 计算类型,可在Web Server层加入分布式逻辑,使得业务可自动均衡的分配到服务器群;对于 Memcached/Redis 这些缓存加速服务基本都带有分布式支持能力;而磁盘类型的业务则需要找到一个适合业务所需要的解决方案(如业务本身对文件名没要求,那可考虑 FastDFS 类分布式存储系统,否则可考虑 MongoFS 类存储系统)以此我们可以构建出下图所绘的架构:

此架构不仅能让服务器的各项资源得到充分发挥,还具备分布式计算的热备能力,并且单台服务器的软件、配置环境标准化,可减少运维的工作量,日常维护也更加方便。是一举几得的好事!以下为我们某个业务的服务器组状态:

上面这组服务器,我们部署有 PHP/Memcached/MySQL 和一个分布式文件系统。

题外话:这素云计算的基础形态麽?嗯,有点云的意思,当然未能达到这个高度。主要因这个方案是非常基础的,仅适合单网站(公司)使用,如果非要说云,那只能说私有云。而要做公有云,我们还需要在此架构基础上,加入安全隔离、资源租赁和统计等很多子系统。

此文撰写于昨晚国航灰机晚点的几个小时里~晚上10点的票居然凌晨3点才到家~故留此印记。

使用 Nginx 构建一个“高”可用的 PHP 集群

  跳过没必要的介绍,直接进入主题。目前建立一个高可用集群的方案不少,可以使用硬件或软件 LVS 类构建,现在我说的方案是只用 Nginx 来进行构建。

  这个集群的架构如下图:

  上面我们共部署了5个节点,每个节点上配有 Nginx + PHP。这个架构的重点就在于,Nginx 不只是与本机的 PHP 通信,整个集群应该把 Nginx 部分抽象到面向业务的第一层,而 PHP 则在第二层。每层都为多节点均衡架构。

  其中 Nginx 层面使用 DNS 均衡实现,DNS 负载均衡是一个很传统的方案,在单个域名下绑定多个 IP 进行轮循,可有效的把业务请求分发到多个节点上,但某节点故障时则需要有相应的解析处理,把故障的节点从 DNS 记录中删除。目前推荐使用 DNSPOD 的解析服务,可支持 API 操作。这样我们就可以自己建立一个服务器状态管理的程序,自动切换 DNS 解析。(注意:域名解析的切换需要 5~10 分钟,当然这是由域名解析记录的 TTL 值决定,为避免大量的 DNS 解析影响请求打开速度,建议 10 分钟或以上为佳)

  第二层 PHP 则由 Nginx 使用 upstream 实现均衡,Nginx 本身的 upstream 就已支持节点健康维护的功能,可以放心的交给 Nginx 来做。而如果 PHP 业务层带缓存功能,则要考虑使用一致性哈希模块来实现 upstream 的均衡策略,否则节点故障对整个 PHP 集群的缓存造成大幅度的震荡。根据我们测试的数据,在普通哈希策略下,一个节点故障会导致 90% 的缓存失效,而使用一致性哈希则可降低到 50% 。并且我们的 Nginx 一致性哈希模块,还可以把故障节点的请求分发到邻近的节点,可以再提高部分缓存命中率,使得整体提升到 70% 的样子。

  这样一个架构方案给我们实现了一个“高”可用的 PHP 集群,并且没有单点故障的隐患存在。DNS 解析服务是多节点,Nginx 层是多节点,PHP 层更是多节点的模式。如使用 LVS 方案,LVS 服务本身也要做一套热备,才能避免单点问题,且增加了架构复杂性。

  应该选择那套架构方案还由业务决定,这里我只是提供一个新思路罢了 ;)

  Nginx 一致性哈希模块:ngx_consistent_hash-1.0.tar

             ngx_consistent_hash-1.1.tar.gz (Fix nginx reload bug)

  使用方法:

upstream backend {
server 192.168.1.101 weight=1;
server 192.168.1.102 weight=2;
server 192.168.1.103 weight=3;
server 192.168.1.104 weight=4;
server 192.168.1.105 weight=5;
consistent_hash $host$request_uri 2;
}

  consistent_hash 支持2个参数,第一个参数为哈希字符串,第二个参数为备份节点数量。当某节点故障时,将把该节点的请求分发到2个备份节点上。当然你可以设置1或更高,建议2为佳 :)

  模块对 nginx 原 upstream 模块的 weight 节点权重功能进行了替换,weight 的功能是配置节点在集群中的位置顺序。(做一致性哈希,这是必须的)

中国IDC质量问题与Yo2的解决方案

  嘿嘿,很有标题党的意识。大家见笑了~笑笑罢了 :D

  刚在 Yo2Mass 看到《从豆瓣宕机看IDC单点问题》 一文,自己是深有感触的。刚好今天我们电信的服务器也出了故障,断网4个多小时。从Yo2开张到现在,我们都不知道换多少个IDC。就是没能找到一个很稳定的(当然太贵的我们是租不起)。

  豆瓣所在的机房是北京实力比较厚的IDC之一,我们也有台服务器在他们的天津机房。一直用着,感觉还可以。虽然偶尔会出现某些地区访问速度慢的问题,但因它在教育网的访问速度挺好的,所以一直在用。万没想到,我一直说算稳定的IDC也会出现如此长时间的断网故障《2008.10.31 豆瓣访问故障》。刚查了下豆瓣的服务器信息,发现他们已经把服务器出口切换到其他机房。他们的数据估计都在原来的机房,新的出口应该是直接 Proxy 代理,访问速度并不理想。

  做网站的技术都知道什么是单点故障和它所造成的影响。传统的解决方案是使用LVS把访问请求分发到多个服务器,如果某台服务器故障,它可自动分发到另外的服务器,能很好的解决单点故障问题。但你再看远一点,在前端的LVS不是一个非常大的单点吗?万一它出现故障,那么它后面的N台服务器都无用武之地!大家都在努力解决单点故障的问题,却未意识到自己在制造一个更大的单点故障风险。

  Yo2也有单点故障的情况发生,但它的影响不至于扩散到全局,因为我们使用了CDN技术。我们目前在几个网络、分几个机房,架设了访问加速节点。CDN利用域名智能解析技术把用户的访问指向到不同的服务器,部分用户间是相对独立的,如网通用户与电信用户,甚至可以精确到某个省份和地区。比如今天电信服务器出现故障,就不会影响到网通和教育网用户的访问,并且我们及时在CDN上把电信的访问切换到其他的机房,能快速恢复服务(当然域名解析耗时比较长,大概1个小时左右)

  但CDN也不是灵丹妙药,不是什么网站应用都能使用CDN。比如一些动态页面就无法使用CDN系统的缓存功能,只能直接Proxy。如果网站应用是以动态内容为主,那么建立CDN系统也就等于把成本扩大1倍。因为它只能直接Proxy到后台服务器,CDN跑多高的带宽,后台的服务器都会跑这么高;后台服务器需要处理的数据量跟没使用CDN是一样的,并不会减少。除非把内容缓存在CDN的加速节点上,这样不仅能节约服务器的成本,并且访问速度会快很多。但目前商业运营的服务商,还未能提供这个完美的解决方案。

  Yo2是在成长过程中就意识到单点故障问题的严重性,我们必须把影响降低到最低。因没找到能提供解决方案的服务商和需要考虑运营成本,所以我们选择了自主根据Yo2作针对性的开发。目前我们是拥有一个算完美的解决方案。当然目前的加速节点还很少,单点故障的影响还是比较大。只是从以前的影响100%降低到40%左右,随着Yo2的成长,我们会继续增加更多的访问节点,单点故障的影响将会降到更低 :)