用户规模越来越大,系统不能承受的服务器之重

0
Lua HTML C/C++ Go 挨踢生涯 13672 次浏览

                                    用户规模越来越大,系统不能承受的服务器之重

 有一家客户,他在一周内流量暴涨,连自己都没有想到在三天内从一个基本上没有什么人用的应用,突然变成了全国人民都非常喜爱用的一个应用。然后一周内dau就突破了两百万。他们的服务器可能就几台,他们的程序员可能就几个人。那么面对着突然到来的流量暴增,技术人员压力非常大。加班加点的可能几夜都合不上眼的,因为流量暴涨所带来的各种各样的技术问题,在一两天里面集中地爆发出来,流量暴涨、程序的bug,被无数人使用之后各种程序bug也会出来。那么如果是短时间内访问暴涨、技术架构弹性不足,导致服务器压垮、性能问题、架构可扩展性问题等等都暴露出来了……

作为企业老板,每个人都希望自己的产品做大、做好,那么问题就来了,当你的后台系统遇到上述挑战时,再去解决bug,那时候就火烧眉毛了,解决不及时的后果,大牛网小编就不去往下说了。为此,我们在开发我们的产品时,就应该未雨绸缪,做到多大的并发量访问后台负荷运转没问题。对此,大牛网从后台服务器角度来给企业分析如何减轻服务器的压力。

一个运营的系统在正式上线后将会遇到各种层级的高并发请求,因此我们必须对此做出相应的策略和技术解决方案,首先我们需要认清系统的高并发由3个层面导致:

1. 传输层
大量用户对系统请求后,将会造成网络带宽和Web服务器的I/O瓶颈。

2. 计算层
接收大量用户请求进行计算,将会造成业务服务器和业务支撑服务器的瓶颈。

3. 存储层
传输层和计算层将会产生大量的数据,数据量暴增,将会导致数据库和储存上的瓶颈。【】

      那我怎么样才能建立一个可靠的服务器架构?来自知乎的作者牛浩帆根据自己的实际经验给出了自己的见解:

初级篇:(单机模式)


假设配置:(Dual core 2.0GHz,4GB ram,SSD
基础框架:apache(PHP) + Mysql / IIS + MSSQL
(最基础框架,处理一般访问请求)
进阶1:替换ApacheNginx,并在数据库前加上cache层【数据库的速度是最大的瓶颈】
Nginx(PHP) + Memcache + Mysql(此时已经具备处理小型访问量的能力)
进阶2:随着访问量的上涨,最先面临的问题就来了:CGI无法匹配上Nginx的高IO性能,这时候可以通过写扩展来替代脚本程序来提升性能,C扩展是个好办法,但是大家更喜欢用简单的脚本语言完成任务,Taobao团队开源了一个Nginx_lua模块,可以用luaNginx扩展,这时候可处理的并发已经超越进阶一个档次了。
Nginx(nginx_lua or C) + Memcache + Mysql
(此时处理个同时在线三四千人没有问题了)
进阶3:随着用户的增多,Mysql的写入速度成了又一大瓶颈,读取有memcache做缓存,但写入是直接面对Mysql,性能受到了很大阻碍,这时候,要在NginxMysql中间加入一层写缓存,队列系统就出场了,就以RabbitMQ为例,所有写入操作全部丢到这只兔子的胃里面,然后屁股后面写个接应程序,一条条的拉出来再写入mysql。而RabbitMQ的写入效率是MysqlN倍,此时架构的处理能力又上一阶层。
|----write------>RabbitMQ--------
Nginxlua or c----- |--------->Mysql
|----read------>Memcache--------
(此时的并发吞吐能力已经可以处理万人左右在线)
中级篇:(分而治之)
此时我们在单机优化上已经算是达到极限,接下来就要集群来显示作用了。
数据库篇: 数据库总是在整个环节中是吞吐能力最弱的,最常见的方法就是sharding
sharding可以按多种方法来分,没有定式,看情况。可以按用户ID区段分,按读写分等等,可用参考软件:mysql proxy(工作原理类似lvs
缓存篇:memcache一般采用的是构建memcache pool,将缓存分散到多台memcache节点上,如何将缓存数据均匀分散在各节点,一般采用将各节点顺序编号,然后hash取余对应到各个节点上去。这样可以做到比较均匀的分散,但是有一个致命点就是,如果节点数增加或减少,将会带来几乎80%的数据迁移,解决方案我们在高级篇再提。
WEB服务器篇: web服务器集群的建设,最常见的就是lvs方式(memcache pool同样可以如此组建)lvs的核心就是调度节点,调度节点负责将流量通过算法分散到各个节点上,因调度所耗资源很少,所以可以产生很高的吞吐率,后台节点数量可以任意增删,但此法弊病就是如果调度节点挂了,则整个集群都挂了,解决方案我们在高级篇提。
方法2:参见 HAProxy - The Reliable, High Performance TCP/HTTP Load Balancer
高级篇:(高可用性+高可扩展性的集群)
单点调度故障解决:
集群的好处显而易见,但是有一个弊端就是单节点进行调度,如果节点出现故障,则整个集群全部都无法服务,对此的解决方案,我们使用keepalived来解决。Keepalived for Linux
keepalived是基于VRRP协议(VRRP协议介绍)的,请一定先了解VRRP协议后再进行配置。
keepalived可以把多台设备虚拟出一个IP,并自动在故障节点与备用节点之间实现failover切换。这样我们配置两台货多台lvs调度节点,然后配置好keepalived就可以做到lvs调度节点出现故障后,自动切换到备用调度节点。(同样适用于mysql
memcache集群扩展解决:
memcache因为我们一般采用的都是hash后除以节点数取余,然后分配到对应节点上,如果节点数出现变化,以前的缓存数据将基本都不能命中。
解决方法:consistent hashing 简介:一致性哈希
consistent hashing大概的思路就是,把hash后的值保证在 0 ~ (2^32)-1 的数值上,然后把这一连串数字对应映射到一个想象的圆上。 
把要存储的各个值hash后,放到圆上,如图

然后把cache节点也用同样的hash方法,映射到圆上,然后每个刚才hash过的value顺时针寻找离自己最近的节点,这个节点就是存储它的节点。

为了提高存储的平衡性,算法还可以加入虚拟节点的概念,即每个实际cache节点,会在圆上对应N个虚拟的节点,这样可以提高算法的命中率,更加平衡。


      假如现在已经遇到了服务器的瓶颈,那么有没有具体的解决的策略呢?来自linux社区的作者lindianli给出了他的一些解决方案:

1. 负载均衡

负载均衡将是大型网站解决高负荷访问和大量并发请求采用的终极解决办法。

1)单个重负载的运算分担到多台节点设备上做并行处理,每个节点设备处理结束后,将结果汇总,返回给用户,系统处理能力得到大幅度提高.

2)大量的并发访问或数据流量分担到多台节点设备上分别处理,减少用户等待响应的时间,这主要针对Web服务器、FTP服务器、企业关键应用服务器等网络应用。

 

2. 数据库集群

就是利用至少两台或者多台数据库服务器,构成一个虚拟单一数据库逻辑映像,像单数据库系统那样,向客户端提供透明的数据服务。

 

3. 库表散列

采用Hash算法把数据分散到各个分表中这样IO更加均衡。

上面提到的数据库集群由于在架构、成本、扩张性方面都会受到所采用DB类型的限制,于是我们需要从应用程序的角度来考虑改善系统架构,库表散列是常用并且最有效的解决方案。我们在应用程序中安装业务和应用或者功能模块将数据库进行分离,不同的模块对应不同的数据库或者表,再按照一定的策略对某个页面或者功能进行更小的数据库散列,比如用户表,按照用户ID进行表散列,这样就能够低成本的提升系统的性能并且有很好的扩展性。sohu的论坛就是采用了这样的架构,将论坛的用户、设置、帖子等信息进行数据库分离,然后对帖子、用户按照板块和ID进行散列数据库和表,最终可以在配置文件中进行简单的配置便能让系统随时增加一台低成本的数据库进来补充系统性能。

 

4. 图片服务器分离

大家知道,对于Web服务器来说,不管是ApacheIIS还是其他容器,图片是最消耗资源的,于是我们有必要将图片与页面进行分离,这是基本上大型网站都会采用的策略,他们都有独立的图片服务器,甚至很多台图片服务器。这样的架构可以降低提供页面访问请求的服务器系统压力,并且可以保证系统不会因为图片问题而崩溃,在应用服务器和图片服务器上,可以进行不同的配置优化,比如apache在配置ContentType的时候可以尽量少支持,尽可能少的LoadModule,保证更高的系统消耗和执行效率。

 

5. 镜像

镜像是大型网站常采用的提高性能和数据安全性的方式,镜像的技术可以解决不同网络接入商和地域带来的用户访问速度差异,比如ChinaNetEduNet之间的差异就促使了很多网站在教育网内搭建镜像站点,数据进行定时更新或者实时更新。

自动把整个数据库或其中的关键数据复制到另一个磁盘上,每当主数据库更新时,DBMS会自动把更新后的数据复制过去,即DBMS自动保证镜像数据与主数据的一致性。

出现介质故障时,可由镜像磁盘继续提供数据库的可用性,同时DBMS自动利用镜像磁盘进行数据库的修复,不需要关闭系统和重装数据库副本。

数据库镜像还可以用于并发操作。即当一个用户对数据库加排他锁修改数据时,其他用户可以读镜像数据库,而不必等待该用户释放锁。

数据库镜像是通过复制数据实现的,频繁地复制自然会降低系统运行效率,因此在实际应用中用户往往只选择对关键数据镜像,如对日志文件镜像,而不是对整个数据库进行镜像。

 

6. 缓存

Apache提供了自己的缓存模块,也可以使用外加的Squid模块进行缓存,这两种方式均可以有效的提高Apache的访问响应能力。在使用web语言开发的时候,各种语言基本都有自己的缓存模块和方法。

 

7. HTML静态化

静态化的html页面效率最高、消耗最小,所以我们可以尽可能使我们的网站上的页面采用静态页面。但是对于大量内容并且频繁更新的网站,我们无法全部手动去挨个实现,于是出现了我们常见的信息发布系统CMS,像我们常访问的各个门户站点的新闻频道,甚至他们的其他频道,都是通过信息发布系统来管理和实现的,信息发布系统可以实现最简单的信息录入自动生成静态页面,还能具备频道管理、权限管理、自动抓取等功能。

除了门户和信息发布类型的网站,对于交互性要求很高的社区类型网站来说,尽可能的静态化也是提高性能的必要手段,将社区内的帖子、文章进行实时的静态化,有更新的时候再重新静态化也是大量使用的策略,像Mop的大杂烩就是使用了这样的策略,网易社区等也是如此。同时,html静态化也是某些缓存策略使用的手段,对于系统中频繁使用数据库查询但是内容更新很小的应用,可以考虑使用html静态化来实现,比如论坛中论坛的公用设置信息,这些信息目前的主流论坛都可以进行后台管理并且存储再数据库中,这些信息其实大量被前台程序调用,但是更新频率很小,可以考虑将这部分内容进行后台更新的时候进行静态化,这样避免了大量的数据库访问请求。

 

8. CDN加速技术

CDN的全称是内容分发网络。其是通过在现有的Internet中增加一层新的网络架构,将网站的内容发布到最接近用户的网络边缘,使用户可以就近取得所需的内容,提高用户访问网站的响应速度。CDN网络是在用户和服务器之间增加Cache层,主要是通过接管DNS实现,将用户的请求引导到Cache上获得源服务器的数据。缓存服务器从实际IP地址得得到内容以后,一方面在本地进行保存,以备以后使用,另一方面把获取的数据返回给客户端,完成数据服务过程。【3】

大家都知道APP应用其实是客户端和服务器端共同来完成的功能。那么对于客户端来说,可能就是一些界面进行优化,然后功能有些叠加。但是在服务器端,那就真的是要做到性能、架构有质的提升,需要的不止是技术。

 

【1】 大型互联网站解决高并发的常见策略 作者 新锋

【2】 知乎 作者牛浩帆 

链接http://www.zhihu.com/question/20657269/answer/15763722

【3】 linux社区 作者lindianli 

链接http://www.linuxidc.com/Linux/2014-09/106451.htm


 

请尽量让自己的答案能够对别人有帮助

55个答案

默认排序 按投票排序
1 2 3