前面讨论的理论已经很完备。我们制定了一个构建服务器集群的计划,还需要一个负载均衡服务来分配流量。现在该撸起袖子把这些理论变成现实了。
首要问题是负载均衡服务该用哪款软件呢?可供的选择有很多:既可以花大钱买专用于负载均衡的硬件,也可以购买由云服务商提供的产品,比如亚马逊的弹性负载均衡(AWS Elastic Load Balancer)。但我们还只是一个预算非常有限的创业小作坊。我们需要的负载均衡服务不仅要强大可靠,最好还能是免费的。
最佳选择已在眼前,就在我们的服务器上。
深入技术细节:Nginx作为负载均衡
目前我们主要使用Nginx作为网络服务器,它是一个称职的服务员,可以效率很高地返回静态文件给用户并把网络请求转发到Django应用。其实,Nginx同时也可提供世界级的负载均衡服务。只需要在配置文件里面加上几行,我们就可以让我们的服务员同时变身为聪明的超市经理。
这对于我们绝对是巨大的好消息。因为我们无需学习然后安装新的复杂软件来实现负载均衡。我们能够继续信任手头熟悉的工具:Nginx。
实现起来确实非常简单。我在DigitalOcean再次购买了一款同配置(每月5美元)的服务器。现在我们就拥有了两位可以同时炒菜的厨师。然后我SSH登录到我们的域名(dukaan.app)指向的第一台服务器。这台服务器现在多了个角色:作为负载均衡服务器。
我打开Nginx配置文件(/etc/nginx/nginx.conf)并添加了两小段配置。
我们的Nginx负载均衡配置
# 定义处理应用逻辑的应用服务器集群。这个集群被称为"app_servers"。
upstream app_servers{
# 这就是见证奇迹之处:Nginx将依据这条配置采用前述的最少连接算法(流量会被送给拥有最少连接的服务器)
least_conn;
# 列出应用服务器集群的内网IP(出于安全和效率考虑)
server 10.132.2.31; # 我们第1台应用服务器
server 10.132.4.55; # 我们第2太应用服务器
# 如果需要拓展,这里可以添加更多服务器
}
server{
listen 80;
server_name dukaan.app;
location / {
# 以下这行配置就足以让Nginx把所有流量转发到上面我们定义的应用服务器集群"app_servers"
proxy_pass http://app_servers;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
好了。上面配置中的upstrem部分定义了我们的应用服务器集群。least_conn;那行指定了我们智能的流量分配策略。proxy_pass指令让Nginx开始做流量分配。保存并重启Nginx之后,我们的负载均衡服务就已经上线开始运行了。
架构更新
我们的系统架构再次演进。现在用户流量走向更复杂一些但也更具韧性。
- 用户访问dukaan.app网站。请求到达作为负载均衡的Nginx。
- 负载均衡服务检查两台应用服务器看看哪台当前活跃连接数量更少。
- 接着请求会被转发给有较少连接的那台服务器(比如2号服务器)。
- 2号服务器运行着Django代码,需要数据来处理分配给它的用户请求。
- 2号服务器连接到我们唯一那台数据库服务器读取所需数据。
- 处理完毕后,响应被原路返回给用户。
如果1号服务器宕机了,Nginx作为负载均衡服务将通过健康检查及时发现这种情况并停止转发流量给1号服务器。接下来所有流量将全部转发给2号服务器。网站此时仍然在线。系统实现了一定程度的容错性。流量爆发和服务器宕机都能应对自如。此刻我们又感觉膨胀了。
新问题:图书馆开始拥挤了
启用负载均衡之后,网站确实完美地工作了一段时间。当流量增长时,我们也不会很慌。我们只需要购买第3台服务器,把它的内网IP加到Nginx的upstream配置里面然后重新启动Nginx就好了。分分钟,我们就可以雇佣新的厨师开始干活。
如果有10个厨师同时在炒菜,但他们都很焦躁,怎么办?
因为他们都需要食材。他们只能同时跑到同一个储藏室,对着同一个管理员咆哮希望尽快拿到属于自己的食材。
瓶颈再次转变:不再是单台服务器导致的CPU处理能力(通过水平拓展暂时解决了),而是上一章拯救我们的英雄,那只单台数据库巨兽。
当一整个服务器集群都在疯狂请求数据时,数据库服务器也开始力不从心。数据库服务器的CPU占用率开始攀升,数据库查询速度开始变慢。
我们的厨房已经完成了扩容,但我们的储藏室/图书馆仍然只有一个房间,一个管理员,而且即将过载。
第4章关键知识点总结
- 水平拓展是可以同时实现高可用和大规模的唯一长期技术路径。虽然比垂直拓展更复杂,但是性价比更高,更灵活,并且能消除单点隐患。
- 负载均衡是实现水平拓展的必需网络交警。它能够为一个服务器集群分配流量并且具备容错能力。
- 尽量从简单选择入手。强大的Nginx可以同时作为网络服务器和负载均衡服务,帮你降低起步的复杂度。
- “最少连接”可作为默认的负载均衡算法。相比简单的轮询算法,它能够更公平地分配工作负荷。
- 技术瓶颈总会变化。刚解决某个性能问题之后,负载就会自然往下一个最薄弱环节聚集(麻绳专挑细处断)。现在我们的应用服务器暂时不再是问题,我们的数据库将燃起新的火苗。