nodejs学习4:一个网站是怎么越做越大

0 阅读16分钟

你有没有好奇过,一个最初只有几个人访问的个人博客,最后是怎么变成能扛住百万级流量的互联网巨头?

其实这背后就是一部不断给系统“打补丁”、“加层” 的进化史,今天就来拆解这个过程。

从单台服务器到集群:解决单点故障

一切的起点,往往是一台孤零零的服务器。

就像你开了一家只有一个店员的小店,刚开始只有你和几个朋友访问,这台机器完全够用。

慢慢博客有了名气,访问的人越来越多。

这时候最大的隐患就出现了,这台机器一旦宕机(比如断电、硬件坏了),整个网站就彻底打不开了,这就是单点故障

为了解决这个问题,我们的方案很直接:多买几台服务器,组成集群

原来只有1台机器,现在变成3台。用户访问时,随机分配到其中一台。哪怕其中一台挂了,另外两台还能正常工作,网站不会彻底瘫痪。

这就像小店从1个店员变成3个,一个请假了,另外两个还能继续营业。

image.png

引入负载均衡:让流量分配更聪明

多台服务器的问题来了:用户该访问哪一台?

如果让用户自己选,就会出现两种麻烦:

  1. 用户需要记住所有服务器的地址,太复杂。
  2. 如果某台机器已经宕机了,用户还傻傻地去访问,结果就是连接失败。

没有什么问题是加一层解决不了的,如果有,那就再加一层。

于是我们在服务器前面加了一层:负载均衡(Load Balance,简称LB) ,通常用Nginx来实现。

  • 所有用户的请求先统一发给LB。
  • LB 根据每台服务器的繁忙程度,智能地把请求分配到最空闲的机器上。
  • 如果某台机器宕机了,LB会自动把它从“可用列表”里剔除,再也不会把请求分给它。

这就像小店门口多了个领班,客人来了,领班看哪个店员最闲,就把客人引过去,不会让客人自己瞎找。

image.png

加入API网关:给流量安检

随着网站越来越火,麻烦也来了:有人开始恶意攻击,用大量请求挤爆服务器

大量请求怎么就能挤爆服务器?

这里的恶意攻击,最常见的就是DDoS攻击(分布式拒绝服务攻击),简单说就是“坏人”利用大量设备,同时向我们的网站服务器发送海量请求,目的不是访问网站、获取内容,而是让服务器忙不过来,最终崩溃、无法正常为合法用户提供服务。

这就像一家热门小店,突然冲进来上百名故意捣乱的人,不消费、只围堵门口、频繁喊店员,导致正常客人进不来、店员被忙晕,小店彻底无法营业。

除此之外,还有一种常见的恶意攻击是爬虫恶意抓取,有些“坏人”会用程序(爬虫),疯狂抓取网站的内容(比如文章、图片、用户信息),这些程序发送请求的速度极快,一次能发送上百个请求,同样会占用服务器大量资源,虽然不会直接“挤爆”服务器,但会导致服务器响应变慢,影响合法用户的访问体验。

这时候我们需要在负载均衡和服务器之间,再加一层API网关,所有流量必须先经过网关的安检

网关的核心功能有:

  • 鉴权:验证你是不是合法用户,比如登录状态是否有效。
  • 防爬:阻止恶意爬虫疯狂抓取数据。
  • 限流:限制同一个用户的访问频率,防止恶意刷流量。
  • 协议转换:把用户的HTTP请求,转换成后端服务器更高效的RPC协议。

这就像小店门口加了个保安,先查身份证、限制人流,防止闹事的人冲进去影响正常营业。

同时,网关本身也会做成集群,避免它自己变成新的单点故障。

image.png

流量路径:用户 → 负载均衡器 → API网关(安检) → 服务器,网关集群确保自身不成为单点。

静态资源分离:让重复访问更高效

网站热门后,我们发现一个现象:很多人访问的是同样的内容,比如一篇爆款文章、一个公共的JS文件。

每次都让服务器重新生成这些内容,既浪费算力又浪费流量。

于是我们做了静态资源分离,也就是把文章、图片、JS/CSS这些不怎么变化的内容,提前生成静态文件(比如HTML),比如,现在前端用vue、react开发前端页面打包成dist静态文件。

拿到静态文件后,存放在服务器的硬盘里面。

当第一个用户请求某张图片时,Nginx发现自己的“缓存内存”里没有这张图片,就会先去服务器的硬盘中把这张图片取出来,一方面发给这个用户,另一方面,会把这张图片“复制一份”,存在自己的缓存内存里,还会给这张图片做个“标记”,比如,标记"这是某张图片,有效期1小时",就像给菜贴个保质期标签。

这里会有个疑问:静态文件一般都是浏览器缓存的,过期了才会从Nginx获取,然后从服务器硬盘里面取,似乎 Nginx 内存不需要缓存静态文件?

其实这个理解只对了一半,浏览器缓存和Nginx缓存两层缓存,各司其职,不是二选一,一起用才能让访问更快、更省资源

  • 浏览器缓存 :是存在你自己的电脑/手机浏览器里的。比如你第一次访问网站,浏览器会把图片、JS这些静态文件,存到自己的浏览器缓存里;下次你再访问这个网站,浏览器会先看自己的缓存里有没有,没过期就直接用,不用再发请求给服务器。这是“你个人专属的缓存”,只服务于你自己

  • Nginx缓存 :是存在网站服务器的Nginx里的,服务于所有访问网站的用户。比如你是第一个访问的用户,浏览器没有缓存,请求会到Nginx,Nginx缓存后,后面其他用户(不管有没有浏览器缓存)请求这张图片时,Nginx都能直接从自己的缓存里取,不用再去后端硬盘找。这是“所有用户共享的缓存”,服务于所有人

image.png

静态请求(图片、文章等):用户 → 负载均衡器 → 静态缓存 → 直接返回;业务请求(如登录、查询):用户 → 负载均衡器 → 网关 → 业务服务器,分工更高效。

负载均衡高可用:防止“领班”也请假

现在我们的架构里,Nginx(负载均衡)成了新的单点,如果它挂了,整个网站还是会瘫痪。

为了解决这个问题,我们给Nginx做了主备模式

  • 部署两台Nginx,一台“主”,一台“备”。
  • 备机会通过keepalived机制,时刻监听主机的状态(就像心跳检测)。
  • 一旦主机宕机,备机会在秒级内自动顶上,接管所有流量。
  • 对用户来说,完全感知不到这个切换过程。

这就像小店的领班也配了个副手,领班一旦有事,副手立刻无缝接班,不会让客人没人管。

对应架构流程图

image.png

用户只需要记住一个虚拟IP,主负载均衡器工作时,所有流量走主节点;主节点故障,备节点自动接管,虚拟IP不变,用户无感知。

引入LVS:扛住更大的流量

当网站变成"巨头"级别,每天有几百万甚至上千万人访问时,Nginx也开始力不从心了。

可能有朋友会疑惑,Nginx不是很强大吗?为什么流量大了就扛不住了?这背后的核心原因,和Nginx的工作机制密切相关。

首先,我们要明确:Nginx虽然是优秀的负载均衡器,但它本质上是一款“应用层”的软件,工作在OSI模型的第七层(应用层)。

这就意味着,Nginx在处理用户请求时,需要做很多”额外工作”,而这些工作在流量激增时,会成为它的“负担”,具体有三个核心原因:

  • 需要建立完整的TCP连接:用户访问网站时,会和Nginx建立TCP连接(相当于两个人打电话前,先确认线路通畅),Nginx还要和后端的服务器建立另一层TCP连接。每一个用户请求,都需要Nginx维护两个TCP连接,当百万级用户同时访问时,TCP连接数会暴增,Nginx需要消耗大量的内存和CPU资源来维护这些连接,一旦资源耗尽,就会出现卡顿、拒绝连接的情况。

为什么应用层软件大多用 TCP 连接?

应用层传递的都是和用户相关的 “关键业务数据”(比如登录密码、文章内容、订单信息),这些数据一旦丢失、乱序,就会出大问题:比如你登录时密码传丢了,就登不上网站;文章内容乱序了,就没法正常阅读。

TCP 刚好能解决这个问题,它会建立连接(就像快递员先确认你和朋友都在,再收件),传输过程中会确认每一个数据包是否收到(丢了就重发),还会按顺序组装数据包(不会乱序),完美适配应用层 “可靠传输” 的需求。

  • 需要处理应用层协议解析:Nginx不仅要转发请求,还要解析用户请求的应用层协议(比如HTTP协议),判断请求的类型、路径、头部信息等,甚至还要处理SSL加密、URL重写等操作。这些解析和处理操作都需要消耗CPU资源,流量越大,CPU的负载就越高,当CPU使用率达到100%时,Nginx就无法再处理新的请求。

  • 抗并发能力有上限:Nginx的并发处理能力虽然比普通服务器强,但它毕竟是单进程多线程(或多进程)的架构,每一个线程/进程能处理的请求数是有限的。当并发请求数超过Nginx的处理上限(通常是几万并发),多余的请求就会被排队等待,甚至直接丢弃,导致用户访问变慢、网站打不开。

简单来说,Nginx就像一个“全能领班”,既要接待客人(建立连接),又要听懂客人的需求(解析协议),还要安排客人就座(转发请求),平时客人少的时候游刃有余,但一旦客人暴增到百万级,这个“全能领班”就会忙不过来。

这时候,我们就需要一个更“专业”、更“高效”的“底层管理者”——LVS,来分担Nginx的压力,这也是我们引入LVS的核心原因。

那么,LVS到底是什么东西?

LVS的全称是Linux Virtual Server(Linux虚拟服务器),它是一款工作在网络层(OSI模型第四层) 的负载均衡器,和Nginx的“应用层”工作模式完全不同。

它的核心作用不是“处理”请求,而是“转发”请求,它不解析应用层协议,不建立完整的TCP连接,只负责将用户的数据包,快速转发到后端的Nginx或服务器集群,相当于一个“高速中转站”,只做最简单、最高效的转发工作。

如果说Nginx是“楼层领班”,既要接待客人,又要安排座位,那么LVS就是“商场大门的引导员”,它的工作只有一个:看到客人(用户请求数据包),就快速指引到对应的楼层(后端Nginx),全程不和客人过多交流,也不处理客人的具体需求。

具体来说,LVS工作在网络层,只关注数据包的“源IP”“目标IP”和“端口”,它会提前配置好后端Nginx的地址,当用户的数据包过来时,LVS只需要修改数据包的目标IP(指向后端空闲的Nginx),然后直接转发出去,整个过程几乎不消耗CPU资源,转发速度极快。而且,LVS不需要和用户、后端服务器建立完整的TCP连接,只需要转发数据包,大大减少了资源消耗。

总结一下:当网站流量达到百万级、千万级,Nginx因为需要处理连接、解析协议,资源消耗激增,无法扛住海量并发;而LVS作为底层的“高速中转站”,只做转发、不做多余处理,性能更强、消耗更少,能轻松扛住海量流量。因此,我们需要引入LVS,和Nginx配合使用,形成LVS负责底层海量流量转发,Nginx负责应用层请求处理的双层负载均衡架构。

这里会有一个核心疑问:用户发送的HTTP请求属于OSI模型的第七层(应用层),而LVS工作在第四层(网络层),这两个不同层级的“组件”,到底是怎么建立连接、传递请求的?

其实答案很简单,层级不直接对话,而是通过数据包封装,层层传递、各司其职。

当你在浏览器输入网址、发送请求时,这个HTTP请求(7层内容)不会直接发给LVS,而是会被电脑的网络协议层层打包,就像我们寄快递时,把物品(HTTP请求)放进快递盒,再贴上快递单(包含IP、端口等信息)。

具体来说,HTTP请求(7层)会先交给6层(表示层)、5层(会话层)处理(不用管具体作用),然后传递到4层(传输层),在这里会被加上TCP头部,包含源端口(用户设备的端口)和目标端口(网站的端口,比如80、443);接着传递到3层(网络层,LVS工作的层级),加上IP头部,包含源IP(用户设备的IP)和目标IP(网站的公网IP,这个IP其实是LVS的虚拟IP);最后传递到2层(数据链路层)、1层(物理层),通过网络发送出去。

当打包好的数据包到达LVS时,LVS作为4层负载均衡器,只会“查看”数据包的4层(TCP头部)和3层(IP头部)信息,也就是源IP、目标IP、源端口、目标端口,不会拆开数据包去看里面的HTTP请求内容(7层)。

LVS会根据自己的配置(提前设定好的后端Nginx地址),修改数据包的“目标IP”——把原来的“网站公网IP”(LVS的虚拟IP),改成后端空闲的Nginx服务器的IP,然后直接把这个“未拆包”的数据包,转发给这台Nginx。

当数据包被LVS转发到Nginx后,Nginx作为7层软件,会做“拆包”操作——先去掉数据包的1-4层头部(IP、TCP等信息),提取出里面的HTTP请求(7层内容),然后解析这个请求(比如判断是请求静态资源还是业务数据),再转发给后端的服务器处理。

处理完成后,服务器会把响应结果(比如文章内容、登录结果),按照同样的流程“打包”成数据包,反向传递给LVS,LVS再修改数据包的“源IP”(改成自己的虚拟IP),转发给用户,用户的浏览器拆包后,就能看到网站内容了。

image.png

DNS负载均衡:解决“楼层经理”的单点问题

最后,连LVS也可能成为单点,而且流量太大,一台LVS扛不住。

我们的终极方案是:DNS负载均衡,它的核心原理很简单,借助DNS(域名解析系统)的“域名→IP映射”功能,实现流量分流。

DNS负载均衡的实现,主要分为3步:

第一步:提前配置域名与多LVS IP的映射关系

我们先给网站的域名,比如www.xxx.com, 配置多个目标IP——这些IP分别对应不同地区、不同节点的LVS服务器(比如南方LVS的IP、北方LVS的IP、西部LVS的IP)。

就像全国连锁商场,给“某商场”这个品牌名,绑定了全国各个分店的地址(南方分店地址、北方分店地址),用户只需要记住“某商场”这个品牌(域名),不用记住各个分店的具体地址(LVS的IP)。

第二步:用户发起访问,请求DNS解析域名

当用户在浏览器输入网站域名比如www.xxx.com) ,点击访问时,用户的设备会先向DNS服务器发送“解析请求”,本质就是问:“www.xxx.com 对应的IP地址是什么?我要去访问它。”

这就像用户打开地图(DNS),搜索“某商场”,地图需要告诉用户,离他最近的商场分店地址(LVS的IP)。

第三步:DNS智能返回对应LVS的IP,实现负载均衡。

image.png

总结:网站变大的核心逻辑

从一个默默无闻的博客,到一个巨头平台,整个技术演进的核心逻辑其实只有两点:

  1. 不断解决单点故障:哪里是单点,就给哪里加备份、加集群。

  2. 不断分层解耦:把复杂的问题拆成更小的模块,每个模块只做一件事,比如,负载均衡只负责分流,网关只负责安全,服务器只负责业务逻辑。

这就像一个人成长为一家大公司:从单打独斗,到分工明确的团队,再到跨地域的集团,每一步都是为了更稳定、更高效、更能扛事

看完这篇文章,你是不是对“网站是怎么变大的”有了更清晰的认识?

其实不管是网站还是其他系统,进化的本质都是在解决问题的过程中,不断优化和迭代