三俗话题:LNMP架构卡顿如何升级换代?

2019-11-13 00:16:29 浏览数 (1)

我要先废话一波儿

千算万算,思维缜密,语言上前后思考,上一篇文章终究还是没有逃过一劫。上一篇文章是啥?---《持续搞【附近】---听说MongoDB是专业的(三)》

【劫】是啥?反正就是坏在这个文章标题上了:大家说我忽视了PostGIS和Redis,纷纷表示让我了解一下,【爱PostGIS人士】表示十分难过并表示遗憾。我真的应该换个万金油文章标题,比如沿用之前的《可能》系列,比如说:

《持续搞【附近】---很有可能MongoDB是专业的(三)》

很显然,这个实现LBS地理位置查询的方案调研明显整体走向要变成《论地球上LBS方案实现方案横向demo演示》。没关系,写就写吧,下篇文章我索性把ES和PostGIS全部终结掉。只不过相对于ES来说,我以前从来没有用过PostGIS。

然而,知其然不知其所以然。按照我的理解,诸位了解他们的【引擎】算法和存储数据结构,实际上要更重要。说白了就是你用R-Tree,我用B-Tree,他搞geo-hash,剩下的搞S2。其实这些都搞明白了,那无论是ES还是PostGIS抑或MySQL 5.7,翻来覆去这点儿东西,你心里都清楚地跟明镜似的。

然而,我快顶不住了:

  • 一来是我自己实在是想换个其他的口味BB一下
  • 二来是有宝贝儿跟我说“ 你能不能给整点儿实际的,别搁那儿一天天整那些唬人的玩意 ”,“ 我们就想知道我们老板的网站卡了怎么办 ”,“ 老板说了APP太卡让加班,也不给钱升级服务器,我哪儿知道咋办 ”

所以,今天的话题就是如何整治LNMP的卡顿拥堵问题,而且还要捎带改进一下单点架构,避规掉绝大多数的单体故障。多年老军医老李手把手带你解决实际问题,工作中能帮老板省钱,面试中能糊一下面试官。

实际上这件事源自于去年的一件真实案例(依稀记得是2018年的7月份左右),我之前发在了社区里,不过阅读量并不高。所以,今天索性偷懒(实际上是太忙了,没法骗工资没空写文章了)就简单修改了一下搬到公众号里,算是搞二次贡献。这篇文章主要就是教你利用云服务商提供好的现成服务,简单地将LNMP架构改造升级为【可能是高可用的LNMP架构】,请注意我用了【可能】。

本文建议阅读对象:

  • 小型公司,业务量已经有一定的量,需要保证线上稳定
  • 由于老板问题导致技术团队里并没有老司机带队,开发人员能应付传统CRUD业务,但是对整体架构上比较陌生

开始装逼

文中以及标题中所有人名、公司名以及产品名均以化名方式出现

上周日接到微信群里一个好友(后文中称XF)的求助,大概意思就是不知道为什么产品新注册用户开始猛增,导致服务器崩溃,在收到通知后通过紧急升级服务器配置到16核CPU和16G内存勉强支撑住了。这个产品的名字叫做YQB,所以标题中我就用洋枪棒来称呼产品了。

首先介绍一下他们产品原有的技术状况,整体是LNMP架构,PHP框架使用的是YII 2.0,http服务器自然就是nginx了,mysql、redis、memcache、php挤在一台服务器上,产品前端以app为主,网页只有一个官网。本来平时没这么多用户,突然由于路子打开了,导致每天以比原来百倍的用户新增量持续增长,所以,原有的架构开始腐化,开始出现卡顿、持续高负载。

XF这次求助主要是因为他们公司服务端只有两个人,而且工作经验都比较短,都不知道清楚该怎么改造才能适应以后,所以让我来出个解决方案。

其实讲道理,是没太大难度的。不过问题说回来,只说架构上的问题,我尽量不去掺乎具体的代码。所以,这次改造的目的就是如下几条:

  • 解体原有的巨无霸一体系统
  • 将架构分层,每层都避免单点故障
  • 更容易地进行横向扩展
  • 更容易和安全地进行代码增量测试
  • 当上线新业务的时候,不用停服

其实,一旦说机器卡,大家肯定张口就是“加机器”。然而,加机器也是有讲究的:

首先是机器加到刀刃上,一加必中!

其次是加的又快又方便

像洋枪棒这种原有的架构,加机器的时候就很难满足上面的两点要求。因为MYSQL、PHP-FPM、NGINX是拥挤在一台机器上的,所以这三个中任何一个出现性能上的瓶颈都会导致服务卡顿。如果说是MYSQL卡,实际上只需要升级MYSQL需要的部分即可,但是mysql、php、nginx拥挤在一起,机器升级了,但并不是升级在刀刃了,这个会很难受。其次是,这样加机器并不是很方便。虽然你可以制作一个镜像,然后通过镜像快速配置好第二台机器的软件环境,但是,第二台机器的mysql、redis以及memcache是完全没用的,还得用第一台机器的mysql、redis等等。

其次是,由于都是单点,所以一旦出现故障,就意味着服务将处于完全不可用的状态。

最后是,如果你有新的代码要上线,但由于测试并不充分,所以能不能可以只让一小部分用户会触发新的业务代码,一旦发现错误,就可以稳稳地回滚代码,代码上的问题不会影响大部分用户。

所以,为了满足一些这些要求,这次的改动就以下面为准:

上述架构将原来的巨无霸单体系统进行了拆解分层,大体来说从上到下分为nginx,php-fpm,redis,mysql四层。升级完成后,相对于原来优点如下:

  • 避免了原来单点故障带来的停服风险。比如nginx挂了一台,那么最起码还有一台nginx继续提供服务
  • 通过性能分析可以锁定是具体哪一层出现性能卡顿,只需要横向扩展该层的机器即可。比如通过观察,发现fpm层的没每台服务器cpu都很高了,那么只需要为fpm这一层新加一台机器即可
  • 上线新的代码可以通过负载均衡流量权重入口来实验代码是否存在巨大故障而不影响绝大部分的用户。新的业务代码可以只先上到一台fpm机器上,然后负载均衡上为该台机器只分配一个很小的权重,这样通过小流量长时间观察就可以收集到是否有严重错误

利用云服务商提供的服务有:

  • 负载均衡层的高可用可由云服务商提供
  • rds的高可用由云服务商提供
  • redis由云服务商提供的主从双机版本提供高可用

通过上述改造达成的新架构可以保证相当长一段时间内架构上健康程度。实际上,截止到写这篇公众号文章的今天,这种简单粗暴的LNMP架构一直支撑XF公司的业务支撑到现在,差不多快一年了(PS:业务量每日新增用户约在几千左右,整体并发大约在几千左右)。

上午,我和XF大概讲了这个整体结构。

下午,在与XF的商议过程中发现其在代码上的几处不合理的地方:

  • 用户的token存储在了mysql数据库中,每次访问都要去mysql数据库中查询token对应的用户信息才能完成完整的session,给mysql形成了巨大的访问压力
  • MySQL或者Redis可以考虑使用pconnect方式
  • 如果愿意,可以尝试将nginx fpm更改为【swoole http server】或者【golang server】。升级后的新架构可以允许他们将重构好的swoole或golang业务程序接入到入口负载均衡中去,小流量观察

如果将上述地方再修改一下,不仅机器数量可以缩减节省成本,而且整体的响应速度一定会继续得到一次提升。

毕竟收人家钱了...

0 人点赞