vlambda博客
学习文章列表

Basis Part 1、Load Balancing-负载均衡系统

前文系列:

负载均衡 (LB) 在任何分布式系统中都是一个关键组件。常基于某些规则(轮询、随机、加权、最小连接数等算法)跨多个资源实例分配请求。LB 在分发请求时还会跟踪所有资源的状态。如果服务器无法接受新请求 Or 没有响应或是某类错误率阈值达到水位,LB 将停止向此类服务器发送流量。

负载均衡降低了单台服务器的负载压力的同时,防止了任何一个应用程序或服务器成为单点故障,从而提高整体的可用性。

说白了负载就是要做到两个事:
1、保持较短的请求响应时间和较小的请求阻塞概率;
2、负载均衡算法的overhead在可控级别,不占用过多的CPU 、网络等资源情况下做稳定的服务分发;

分析一个系统或者组件,常见的推进做法是What-Why-How,负载均衡的概念其实大家或多或少都有耳闻,如果能结合常用的场景分析的话会更好理解~

| WHAT:

负载均衡的定位或者说她作用的介质,可抽象成三类

  • 用户和Web服务之间:常见的nginx之类的就是这层;
  • Web服务和内部应用服务之间:企业内部的应用一般分成Web应用和服务应用,前者一般充当前台有着直接对接客户的能力,后者则是企业各种微服务化的功能应用,比如xxx详情系统之类的,负载在这层更像是内部的请求路由;
  • 应用服务和底层组件之间:一般来说,业务系统之下,横向的服务能力往往会被多个系统所共同调用,DB或是常见的消息服务会比较依赖负载做请求的分配;


然后,随着需求的变换和场景的丰富,负载均衡的形式也随着演变成各(yi)式(dui)各(lun)样(zi):

硬件负载

常见的有:F5、A10、Array等
功能强大,可定制化,性能较好,使用简单,但缺点也比较明显,就是维护成本高,灵活性差

软件负载:

常见的有:LVS、Nginx、Haproxy等
灵活性高,可基于需求自由组合,稳定性和性能稍差一筹

说到Nginx,就一般离不开正向代理和反向代理,这两种用法就简单用两个图概括一下吧

Basis Part 1、Load Balancing-负载均衡系统


Basis Part 1、Load Balancing-负载均衡系统


反向代理和负载均衡的关系

先看一份简单的配置信息

负载均衡的配置

worker_processes 1;

events {
   worker_connections 1024;
}

http{
    upstream lxx {//默认是80端口
        server 192.168.0.62 weight=2;
        server 192.168.0.161 weight=3;
    }

    server {
        listen 80;
        location / {
            proxy_pass http://lxx;
        }
    }
}

反向代理的配置

worker_processes 1;

events {
   worker_connections 1024;
}

http{
    upstream lxx {//默认是80端口
        server 192.168.0.62 weight=2;
        server 192.168.0.161 weight=3;
    }

    server {
        listen 80;
        location / {
            proxy_pass http://lxx;
            #Proxy Settings
            proxy_redirect     off;
            proxy_set_header   Host             $host;
            proxy_set_header   X-Real-IP        $remote_addr;
            proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
            proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
            proxy_max_temp_file_size 0;
            proxy_connect_timeout      90;
            proxy_send_timeout         90;
            proxy_read_timeout         90;
            proxy_buffer_size          4k;
            proxy_buffers              4 32k;
            proxy_busy_buffers_size    64k;
            proxy_temp_file_write_size 64k;
        }
    }
}

从配置上看,下面多了一丢丢代理的信息,而从功能上来看,两者都是基于规则做转发负载均衡可以把用户的请求按照相关算法和规则发送到web集群的某台机器,而反向代理也是实现了如此的功能

那么他们的区别究竟在哪呢?

答:目的不同!缓存,是反向代理主要的目的,以便减少并发操作,负载均衡是做反向代理的目的之一

更简单的说法就是,负载均衡是反向代理时的一个特殊用法,反向代理本来只是为了屏蔽端与端之前的直接联系,但这个需要被藏起来的端多了以后,反向代理时就需要考虑这个问题,而他的这个做法被当成了一种负载均衡,emmmmm~

如果没有反向代理,压力直接放到一个单一的http server上。而有了反向代理,典型情况下,一个ngnix做反向代理,后面有若干个http Server。所有的流量想到ngnix,这个东西根据配置的策略,或者轮转,或者随机或者压力分流,把流量导向给后面的Http server。从而达到负载均衡。

当然实际业务中都是两种结合起来用的。硬件和软件负载一般不分家,大多像下图一样愉快的玩耍

Basis Part 1、Load Balancing-负载均衡系统


| Why

负载均衡的好处是?


其实是在引言的基础上做一点补充:

  • 用户体验更快、稳定而不间断的服务。用户不必挤在一个服务器等待她完成自己先前的任务后再来服务自己。相反,他们的请求会立即传递给当前更容易获得的资源。

  • 服务提供商的停机时间更少,吞吐量更高。即使整个服务器出现故障也不会影响最终用户体验,因为负载均衡器只会将其路由到健康的服务器。

  • 负载平衡使运维或是开发能更好地动态调控流量&批量操控流量(需要接入类似于阿里云工作台一样的东东),同时减少用户的等待时间。

  • 负载均衡其实还可以提供诸如预测分析之类的好处(这个少见,不做过多讨论),可以在流量瓶颈发生之前确定它们。因此,智能负载均衡器为企业提供了可操作的分析。这些是自动化的关键,可以帮助推动业务决策。


木有负载均衡的情况下什么常见场景会出大事?

  • 各种网关类应用,网关最主要的功能是负载

  • 数据存储,容易出现热点倾斜等问题

  • 一些云产品像是云服务器之类的会缺失部分动态和自适应能力

| How

简单讲讲Nginx是怎么玩的吧


Nginx基于两种负载均衡算法(轮转法)(IP哈希法),以filter那样的设计模式一样的流水线做法依次处理请求-传递“结果”-处理请求-....,但有一点比较特殊的是:filter不会强依赖上一个filter的结果,她传递的是模块,也就是filter,而不是filter的结果。


传递模块的好处是?

答:模块可以压缩来自后端服务器的响应,然后像流一样的到达客户端,直到整个响应发送完成。


工作原理

客户端发送HTTP请求 –>Nginx基于配置文件中的位置选择一个合适的处理模块 ->(如果有)负载均衡模块选择一台后端服务器 –>处理模块进行处理并把输出缓冲放到第一个过滤模块上 –>第一个过滤模块处理后输出给第二个过滤模块 –>然后第二个过滤模块又到第三个 –>依此类推 –> 最后把响应发给客户端。


具体到代码的话。。。


| More

一致性哈希与Key的选择

传统的哈希在分布式系统中的缺点:无法很好的支持分布式系统中频繁的节点上线(节点失活替换、节点扩容)问题,因为算法是固定的,计算出来的结果是固定的,但总数却是实时变换的,这次算出来后面就找不到点位啦。

解法:环状一致性哈希,同时通过虚拟节点的方案解决一致性哈希部分节点负载不均衡的情况

DNS和CDN中的负载均衡技术


高可用Keepalived技术

TCP三次握手建立连接:当客户端在发起请求前,需要先与服务端建立TCP连接,而每一次的TCP连接是需要三次握手(三次握手的机制就不再做赘述~)来确定的,如果客户端与服务端之间网络差一点,这三次交互消费的时间会比较多,而且三次交互也会带来网络流量。当然,当连接断开后,也会有四次的交互,当然对用户体验来说就不重要了。所以我们需要一种能不会重复建立连接的交互方式来保障数据的传输,这就是所谓的长连接。

keepalive对长连接保活:以nginx为例,nginx需要客户端在请求头connection中带上keep-alive(http 1.0为clode,1.1则默认带上keep-alive),nginx会在输出完响应体后,设置当前连接的ke的属性,等待下一次连接,但!他也不可能一直等是吧,所以会有一个最大等待时间keepalive_timeout超过进入close状态