当前位置:  首页  >  PHP资讯  >  开源动态

从小流量到高并发:开发者眼中的LNMP架构

本篇从单台机器架构开始,然后会遇到了哪些瓶颈,哪些坑,如何解决等,是一个典型的LNMP架构网站的架构演变。希望对大家有价值。

本篇从单台机器架构开始,然后会遇到了哪些瓶颈,哪些坑,如何解决等,是一个典型的LNMP架构网站的架构演变。希望对大家有价值。

  有一天,我突发奇想创建了一个站点,基于 LNMP 架构,起初只有我自己访问,后来因为我点儿正,访问量越来越大,所以最终导致下面说的架构演变。

  单台机器

  单台机器因为只是一个小网站,访问量一天也没有多少UV(100以内),所以用一台1核1G内存的机器就够了。机器上安装的是 CentOS 系统,然后搭建了 nginx+php-fpm+mysql 的环境。

  两台机器

  

  访问量越来越大,日UV突破5000,单台机器不够了,本可以增加机器配置编程4核8G,但是考虑到还要换机器,所以直接添置一台数据库服务器单独跑 MySQL服务。

  原来的服务器只需要跑 Nginx+PHP-FPM,新加服务器跑 MySQL 服务。 在这里,往往会遇到一个问题,就是如何在多台机器上编译安装 LNMP 环境,在单台机器上编译都没有问题,PHP 放在最后,因为它依赖 MySQL,但我们这里需要把 MySQL 放到另一台机器,所以编译肯定会报错。解决这个问题,其实很简单,即使 Web上不需要 MySQL,我们也要安装一下,因为编译 PHP 的时候依赖它。

  增加memcached

  

  访问量持续增加,UV上万了,DB 服务器和 WEB 服务器压力越来越大,这时候我们需要加一个缓存来缓解 DB 服务器的压力。同样是两台机器,只不过 Web机器配置需要升级了,原来的1核1G内存不够用了,不仅要加 CPU 还要加内存,因为在 Web 上我们需要运行 memcached 服务,同时 PHP 也需要安装memcache 扩展。

  增加Web服务器,MySQL主从分布

  访问量又扩大了,UV到了5W,数据库服务器因为一开始配置就挺高,所以没有压力,但是 Web 服务器负载有点高了,在高峰期可以感觉到网站访问变慢。所以,这时候不得不考虑要加一台 Web 服务器。另外,数据库是单点,如果磁盘损坏,可能会带来意想不到的后果,所以我们有必要加一台从 DB 服务器,作为数据备份用。

  

  在这里,两台 Web 服务器并没有做负载均衡。主要是为了节省资源,暂时先不去购买服务器做负载均衡。

  我们使用 DNS 轮询的方法来把用户的请求分发到两台机器上,但这种该架构有个问题,一旦一台 Web 机器宕机,将会有一半的用户访问不到业务。

  还有一个问题,我们也需要考虑到,如何保证 Web 服务器上的数据一致,比如用户可能会上传图片到 Web 服务器上,假如他上传到了 Web1 上,那 WEB2 是不存在这个图片的。所以我们需要做一个共享存储让 Web1 和 Web2 同时可以访问,所以在这里我把 WEB1 的一个目录使用 NFS 共享出来,让 Web2 去挂载。

  还有一个问题就是memcached服务如何分配,在这里,我是把 memcaced 服务分别安装到两台 Web 上的,自己用自己的 memcached 服务。

  MySQL读写分离

  访问量持续上升,UV已到了数十万。网站在高峰期总是会卡顿那么一段时间。经排查,发现在 MySQL 服务器上有很多慢查询,经过各种调优依然没有太明显效果,最后决定做读写分离。

  做读写分离有两种方案,第一可以借助程序来实现,把所有的写操作指向到主 MySQL ,所有的读操作指向到从 MySQL。对于这种方案,机器数量和环境不用做任何调整,唯一要做的是程序代码要改一下。第二可以借助 mysql-proxy 来实现,不用修改代码,节省开发成本,但需要增加一个角色。架构是这样的,如下图:

  

  负载均衡

  两台 Web 服务器因为有一台配置比较老,因此在高峰期时,终究是没有能扛住而挂掉。结果影响了一半的用户访问不到网站了,这就是所谓的单点故障。经过此次事故,我又开始修改架构,尽量避免单点故障,在 Web 前端设置了负载均衡设备,并且做了高可用。

  

  在这里我拿 Nginx 做了负载均衡器,并没有使用 LVS和HAProxy,我觉得 Nginx 更容易操作,更好控制。

  为了节省成本,我并没有单独把 mysql-proxy 摘出来作为独立服务器,因为那样的话,也得为它考虑单点问题。在这个架构中,其实还有一个缺陷,就是 NFS 服务端也是有风险的,更加保险的做法是单独搞一台服务器做NFS服务。

  继续扩展

  UV上升到100万,两台 Web 服务器明显不够用了,而瓶颈并不在 MySQL 上。所以,只增加 Web,同时把 NFS 服务器单独摘出来,并做一个备用 NFS 服务器。

  

  引入NoSQL

  UV近1000万,三台 Web 服务器也早已不够,增加到5台。而 MySQL 服务器压力逐渐变大,针对 MySQL 的慢查询,发现压力主要体现在个别 SQL 语句上,该优化的已经优化到极致,对于这几个查询,其实是可以使用 NoSQL 的。

  于是,我找懂PHP开发的朋友修改了程序,把一些访问量大的数据存储到Redis,从而减少了对 MySQL 服务器的压力。 而 Redis 为了防止单点也做了主从。

  

  MySQL架构演变

  假设一个网站(Discuz)从最开始访问量很小做到日PV千万,我们来推测一下它的MySQL服务器架构演变过程。

  第一阶段

  网站访问量日PV量级在1W以下。单台机器跑Web和DB,不需要做架构层调优(比如,不需要增加memcached缓存)。此时,数据往往都是每日冷备份的,但有时候如果考虑数据安全性,会搭建一个MySQL主从。

  第二阶段

  网站访问量日PV达到几万。此时单台机器已经有点负载,需要我们把Web和DB分开,需要搭建memcached服务作为缓存。也就是说,在这个阶段,我们还可以使用单台机器跑mysql去承担整个网站的数据存储和查询。如果做 MySQL 主从,目的也是为了数据安全性。

  第三阶段

  网站访问量日PV达到几十万。单台机器虽然也可以支撑,但是需要的机器配置要比之前的机器好很多。

  如果经费允许,可以购买配置很高的机器来跑mysql服务,但是并不是说,配置翻倍,性能也翻倍,到了一定阶段配置增加已经不能带来性能的增加。

  所以,此阶段,我们会想到做MySQL服务的集群,也就是说我们可以拿多台机器跑MySQL。但是,MySQL集群和Web集群是不一样的,我们需要考虑数据的一致性,所以不能简单套用做Web集群的方式(lvs,nginx代理)。

  可以做的架构是,MySQL主从,一主多从。为了保证架构的健壮和数据完整,主只能是一个,从可以是多个。

  还有一个问题,我们需要想到,就是在前端Web层,我们的程序里面指定了MySQL机器的ip,那么当机器有多台时,程序里面如何去配置?Discuz其实有一个功能,支持MySQL读写分离。即我们可以拿多台机器跑MySQL,其中一台写,其他多台是读,我们只需要把读和写的 IP 分别配置到程序中,程序自动会去区分机器。当然,如果不使用 discuz 自带的配置,我们还可以引用一个软件叫做 mysql-proxy, 使用他来实现读写分离。它支持一主多从的模式。

  第四阶段

  网站访问量日PV到几百万。之前的一主多从模式已经遇到瓶颈,因为当网站访问量变大,读数据库的量也会越来越大,我们需要多加一些从进来,但是从的数量增加到数十台时,由于主需要把bin-log全部分发到所有从上,那么这个过程本身就是一件很繁琐的事情,再加上频繁读取,势必会造成从上同步过来的数据有很大延迟。

  所以,我们可以做一个优化,把MySQL原来的一主多从变为一主一从,然后从作为其他从的主,而前面的主只负责网站业务的写入,而后面的从不负责网站任何业务,只负责给其他从同步bin-log。这样还可以继续多叠加几个从库。

  第五阶段

  网站访问量日PV到1千万的时候,我们发现,网站的写入量非常大,我们之前架构中只有一个主,这里的主已经成为瓶颈了。所以,需要再近一步做出调整。比如,我们可以把业务分模块,把用户相关的单独分离出来,把权限、积分等也可以分离出来单独跑一个库,然后再做主从,也就是所谓的分库。

  当然也可以换一个维度,把访问量或者写入量大的表单独分离出来,跑在一台服务器上,也可以把一个表分成多个小表。这一步操作,涉及到一些程序上的改动,所以需要事先和开发同事做好沟通和设计。

  总之,这一步要做的就是分库分表。

  小结

  再往后发展,继续把大表分小表即可。 比如阿里淘宝网站的数据量是巨量的,他们的数据库全部都是 MySQL,他们的 MySQL 架构就是遵循分库分表这个原则的,只不过他们划分规则会有很多维度,比如可以根据地域划分,可以根据买家、卖家划分,可以根据时间划分等。

吐了个 "CAO" !
扫码关注 PHP1 官方微信号
PHP1.CN | 中国最专业的PHP中文社区 | PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | PHP问答
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved PHP1.CN 第一PHP社区 版权所有