星星之火

燎原之势不可挡
posts - 127, comments - 374, trackbacks - 0, articles - 3
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

系统架构——负载均衡整理总结

Posted on 2020-04-21 15:24  星星之火116  阅读(...)  评论(...编辑  收藏

系统架构——负载均衡整理总结

基本定义

集群:多个服务器处理相同的事,多服务器代码是一样的。

分布式:多个服务器协同做一件事      

有了集群,承载能力肯定可以提升

有了集群,就一定有负载均衡(请求转发) 

负载均衡:英文名称为Load Balance,其含义就是指将负载(工作任务)进行平衡、分摊到多个操作单元上进行运行。

实现负载均衡的方式主要有DNS负载均衡、硬件、软件负载均衡,本文主要讲解使用软件实现负载均衡。

DNS负载均衡 

DNS可以为一个域名配置多个ip:port 

按地域&随机 

集群的调用由DNS完成,很不靠谱,因为DNS没办法知道服务器状况    

DNS配置的是到这个负载均衡服务器,而不是某台服务器

硬件的负载均衡  

F5、Array、Netscale集成解决方案,收费(不在讨论范围之内,知道即可)

软件的负载均衡  

七层协议

 

LVS

Linux Visual Server 基于4层(传输层)协议转发,只有IP和Port,只能简单分发,但是效率高---配置麻烦

HAProxy

基于7层的协议(应用层)

Nginx(重点讲解)

基于7层协议(应用层)转发,负载均衡策略丰富 

随机(平均)、权重、IPHash(用户固定分配某台服务器)、UrlHash(url进行hash分配)

下载安装

Nginx 下载地址:http://nginx.org/en/download.html

根据自己的需求选择下载的Nginx包;

这里可以采用稳定版本:1.16.1

环境配置

可以通过DOS命令启动服务:也可以直接双击nginx.exe 启动服务;

启动服务:start nginx   

退出服务:nginx -s quit

强制关闭服务:nginx -s stop

重载服务:nginx -s reload  (重载服务配置文件,类似于重启,服务不会中止)

验证配置文件:nginx -t

使用配置文件:nginx -c "配置文件路径"

使用帮助:nginx –h

负载均衡配置

我们可以看到nginx文件夹内有一个conf文件夹,其中有好几个文件,其他先不管,我们打开nginx.conf,可以看到一段:

 

 这段代码在server里面,相当于一个代理服务器,当然可以配置多个。

下面我们仔细来分析一下:

listen:表示当前的代理服务器监听的端口,默认的是监听80端口。注意,如果我们配置了多个server,这个listen要配置不一样,不然就不能确定转到哪里去了。

server_name:表示监听到之后需要转到哪里去,这时我们直接转到本地,这时是直接到nginx文件夹内。

location:表示匹配的路径,这时配置了/表示所有请求都被匹配到这里

root:里面配置了root这时表示当匹配这个请求的路径时,将会在这个文件夹内寻找相应的文件,这里对我们之后的静态文件伺服很有用。

index:当没有指定主页时,默认会选择这个指定的文件,它可以有多个,并按顺序来加载,如果第一个不存在,则找第二个,依此类推。

部署多台应用服务器,端口号分别为9101 和9102、9103

Nginx 的 upstream目前支持的分配算法: 

轮询 ——1:1 轮流处理请求(默认)

每个请求按时间顺序逐一分配到不同的应用服务器,如果应用服务器down掉,自动剔除,剩下的继续轮询。 

权重 ——you can you up

通过配置权重,指定轮询几率,权重和访问比率成正比,用于应用服务器性能不均的情况。 

ip_哈希算法

        每个请求按访问ip的hash结果分配,这样每个访客固定访问一个应用服务器,可以解决session共享的问题。 

      通过在upstream参数中添加的应用服务器IP后添加指定参数即可实现,如:

 

upstream webApi { 

               server localhost:9101 weight=6; 

               server localhost:9102;  

               server localhost:9103;

               # ip_hash;

               #设置为ip_hash之后,将某个ip请求定向到同一台后端,这样该ip下的某个客户端和后端就会建立起稳固的serssion

               #以下情况不能使用ip_hash,nginx不是最前端的服务器;nginx的后端还有其它方式的负载均衡

    }    

 server { 

        listen       90; 

        server_name  localhost; 

        #charset koi8-r; 

        #access_log  logs/host.access.log  main; 

        location / { 

             proxy_pass http://webApi; 

            index  index.html index.htm; 

        } 

     }

 

      通过以上配置,便可以实现,在访问localhost:90这个网站时,由于配置了proxy_pass地址,所有请求都会先通过nginx反向代理服务器,在服务器将请求转发给目的主机时,读取upstream为 webApi的地址,读取分发策略,配置server1权重为6,所以nginx会将大部分请求发送给server1,也就是9101端口;较少部分给9102,9103来实现有条件的负载均衡,当然这个条件就是服务器的硬件指数处理请求能力。 

Nginx其他配置

1)down

    表示单前的server暂时不参与负载

2)Weight

    默认为1.weight越大,负载的权重就越大。

3)max_fails

    允许请求失败的次数默认为1.当超过最大次数时,返回proxy_next_upstream 模块定义的错误

4)fail_timeout

    max_fails 次失败后,暂停的时间。

5)Backup

    其它所有的非backup机器down或者忙的时候,请求backup机器。所以这台机器压力会最轻。

使用Nginx的高可用 

      除了要实现网站的高可用,也就是提供n多台服务器用于发布相同的服务,添加负载均衡服务器分发请求以保证在高并发下各台服务器能相对饱和的处理请求。同样,负载均衡服务器也需要高可用,以防如果负载均衡服务器挂掉了,后面的应用服务器也紊乱无法工作。

     实现高可用的方案:添加冗余。添加n台nginx服务器以避免发生上述单点故障。

存在的主要问题——用户持久化

Http是无状态的,在集群的情况下不一定每次都请求的同一台服务器上,因为会存在用户持久化、识别的问题。解决办法有以下几种:

会话粘滞

通过Nginx 的IP Hash负载策略将同一个IP请求转发到同一个服务器,但实际上并未做到真正的负载均衡,会出现某台服务器访问量过大,其他服务器访问不饱和的情况,不建议使用。

Session共享

StateServer

将用户信息存储在StateServer服务器中,需要进行一些配置(配置麻烦)

数据库

将Session信息存储在数据库中,读取数据库有额外开销,高并发时,数据库瓶颈

Redis

将用户信息存储在Redis服务器上,每次获取都从Redis读取。

新建一个.NET Core Web应用程序项目
在Nuget 引入Redis包

Microsoft.Extensions.Caching.Redis

在Startup的ConfigureServices方法里注册session和redis服务

在Configure方法里使用Session

分别如下:

public void ConfigureServices(IServiceCollection services)

        {

            services.AddControllersWithViews();

            services.AddSession();

            //注册Redis分布式缓存服务

            services.AddDistributedRedisCache(options =>

            {

                options.Configuration = "127.0.0.1:6379";//这里是本机,真实环境可以指定具体dRedis服务器

                options.InstanceName = "RedisDistributeCache";

            });

        }

 

  public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

        {

            if (env.IsDevelopment())

            {

                app.UseDeveloperExceptionPage();

            }

            else

            {

                app.UseExceptionHandler("/Home/Error");

            }

            app.UseSession();

………

}

新建一个控制器,用来设置和获取Session信息如下:

public class XFHController : Controller

    {

        private readonly ILogger<XFHController> _logger;

        private IConfiguration _configuration;

        public XFHController(ILogger<XFHController> logger,IConfiguration configuration)

        {

            _logger = logger;

            _configuration = configuration;

        }

        private static int _TotalCount = 0;

        public IActionResult Index()

        {

            this._logger.LogWarning($"This is XFHController Index{this._configuration["port"]}");

            ViewBag.BrowserUrl = $"{Request.Scheme}://{Request.Host.Host}:{Request.Host.Port}/";//浏览器地址

            ViewBag.InternalUrl = $"{Request.Scheme}://{base.Request.Host.Host}:{this._configuration["port"]}";

            ViewBag.TotalCount = _TotalCount++;

 

            string user = HttpContext.Session.GetString("CurrentUser");

            if(string.IsNullOrWhiteSpace(user))

            {

                base.HttpContext.Session.SetString("CurrentUser", $"XFH-{this._configuration["port"]}");

                this._logger.LogWarning($"This is XFHController {this._configuration["port"]} session");

            }

            base.ViewBag.SessionUser = base.HttpContext.Session.GetString("CurrentUser");

            return View();

        }

}

开启Redis服务

找到Redis的安装路径,点击redis-server.exe,如下:

 

开启成功,如下:

 

启动应用服务集群

dotnet XFH.LBS.dll --urls=http://*:9101 --ip=”127.0.0.1” --port=9101

dotnet XFH.LBS.dll --urls=http://*:9102 --ip=”127.0.0.1” --port=9102

dotnet XFH.LBS.dll --urls=http://*:9103 --ip=”127.0.0.1” --port=9103

在浏览器里访问http://localhost:90/XFH

这时即可看到不同的站点使用的的用户信息都是同一个。

 

打开Redis Desktop Manager,查看Redis存储信息,

如下:

 

Memcache

目前市面上以使用Redis居多,不过原理都是一样的,不展开详述。

请求携带

cookie

有安全、带宽、浏览器等的限制

token

JWT、IdentityServer4