当我们的网站PV值达到很大时,单机部署已经顶不住并发的访问量,这时通常需要部署多个站点做负载均衡。IIS实现负载均衡比较常用的方式是Server Farms/NLB/Nginx,其中Server Farms和NLB比较简单无脑,安装好程序,通过可视化界面配置Server站点以及负载均衡的策略即可。我们来看一下更轻量化的实现方式,通过Nginx反向代理。
Nginx安装配置
前往Nginx官网下载Nginx安装,下载后解压运行nginx.exe,然后访问localhost,如出现下面画面证明Nginx正常无问题:
注意80端口可能被IIS占用了,运行Nginx前需要先将IIS80端口网站停掉,或者修改nginx配置文件改为其它端口再运行
网站准备
这里我们写一个简单的网站,作为需要负载均衡访问的站点,并且在IIS上部署三个站点模拟三台服务器。
<%@ Page Title="主页" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
CodeBehind="Default.aspx.cs" Inherits="WebTest._Default" %>
<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
<h2>
欢迎使用 ASP.NET!
<h3>
服务器地址:<%= Request.ServerVariables.Get("Server_Name").ToString()%></h3>
<h3>
服务器端口:<%= Request.ServerVariables.Get("Server_Port").ToString()%>
</h3>
</h2>
<p>
若要了解关于 ASP.NET 的详细信息,请访问 <a href="http://www.asp.net/cn" title="ASP.NET 网站">www.asp.net/cn</a>。
</p>
<p>
您还可以找到 <a href="http://go.microsoft.com/fwlink/?LinkID=152368" title="MSDN ASP.NET 文档">
MSDN 上有关 ASP.NET 的文档</a>。
</p>
</asp:Content>
网站代码比较简单,就是在网页上显示当前服务器的地址及端口,然后在IIS上新建三个站点指向这个网页,端口分别为8010,8020,8030,如下:
分别访问这三个站点结果如下:
配置Nginx代理
修改nginx.config配置文件如下:
#添加集群,名称为jq_test
upstream jq_test{
server 127.0.0.1:8010; #将服务器地址添加到集群中
server 127.0.0.1:8020;
server 127.0.0.1:8030;
}
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm Default.aspx; #修改主页为我们站点上的Default.aspx
proxy_pass http://jq_test;
}
然后切换到nginx目录下运行命令nginx -s reload重启nginx服务,然后我们重新访问localhost地址,发现已经指向了我们部署的三个IIS站点,如下:
可以看到Nginx已经把对80端口的访问转发到了我们部署的IIS站点上,并且我们不停刷新发现,每次转发后页面上显示的服务器端口都在变化,说明转发到了不同的站点上。至此,Nginx+IIS实现负载均衡已经初步实现。
后续问题优化
在实现负载均衡后,我们就需要面临由单机应用转变为分布式应用需要面对的问题:
1. 如果我们的站点使用了session,现在请求被负载均分到多个站点了,那么这多个站点间如何共享session?
分布式应用常用的session共享方式是数据库或者Redis存储,读写session都从同一个数据库或Redis操作,在后面的博文中我们会讲述通过redis实现session的共享。
2. 如果多台服务器的配置不同,希望将更多的请求分到配置更高的服务器如何实现?
nginx可以通过加权法来控制请求的分配比例,通过nginx.config配置如下:
upstream Jq_test{
server 127.0.0.1:8082 weight=4;
server 127.0.0.1:9000 weight=1;
}
其中,weight值就是权重,权重越大,相应的分配到的请求越多。负载均衡还有很多策略,Server Farms/NLB 这两种负载实现方式有更多经典策略的实现,大家可以自己尝试下。
3. 在做了负载均衡后,每次站点有更新需要同步到所有站点,假如负载的站点总共有10个,那么需要将更新包更新到10台服务器上,耗时且容易出错遗漏。
多服务器站点更新可以使用GoodSync 文件同步程序,会自动检测文件的修改新增,然后同步到其它服务器上。在linux下可以使用rsync
4. 在某些场景比如限量秒杀时,我们会对下单等业务代码做加锁控制,如果是单机部署,我们只需要通过lock就能保证最终秒杀数在控制内,但是在分布式部署后,lock不能保证其它服务器上的进程受控制因此失效
解决这个问题就需要增加针对分布式系统的锁设计,常见的实现方式就是通过Redis和Zookeeper来做一个控制中心,尝试占用锁和解锁都统一通过这个控制中心。后面的博文中再详细讲解如何实现。