Nivelle 开拓视野冲破艰险看见世界 身临其境贴近彼此感受生活

架构学习(二)之高可用

2017-10-14
nivelle

高可用

负载均衡与反向代理

对于一般应用,有Nginx一般用于七层负载均衡,其吞吐量是有一定限制的.为了提升整体吞吐量,会在DNS和Nginx之间引入接入层,如果使用LVS(软件负载均衡器),F5(硬负载均衡器)可以做四层负载均衡,即首先DNS解析到LVS/F5,然后LVS/F5转发给Nginx,再由Nginx转发给后端Real Server.

image

LVS DR的工工作模式:工作在数据链路层,LVS和上游服务器共享同一个VIP,通过改写报文的目标MAC地址为上游服务器MAC地址实现负载均衡,上游服务器直接响应报文到客户端,不经过LVS,从而提升性能.但因为LVS和上游服务器必须在同一个子网,为了解决子网问题而不影响负载性能,可以在在LVS后边挂HaProxy,通过四到七层负载均衡器HaProxy集群来解决跨网和性能问题.

二层负载是通过改写报文的目标MAC地址为上游服务器MAC地址,源IP地址和目标IP地址是没有改变的,负载均衡服务器和真实服务器共享同一个VIP,如LVS DR工作模式.

术语介绍:

  1. 上游服务器配置:使用upstream server 配置上游服务器,指Nginx负载均衡到处理业务的服务器,也可以称为real server,即真实处理业务的服务器
  2. 负载均很算法:配置多个上游服务器时的负载均衡机制
  3. 失败重试机制:配置当超时或上游服务器不存活时,是否需要重试其他上游服务器.
  4. 服务器心跳检测:上游服务器的健康检查/心跳检查
  • upstream 配置

我们需要给Nginx配置上游服务器,即负载均衡到的真实处理业务的服务器,通过在http指令下配置upstram即可.

 upstream backend{
     server 192.168.61.1:9080 weight=1;
     server 192.168.61.1:9090 weight=2;
 }

upstram server的主要配置如下:

  1. ip地址和端口:配置上游服务器的IP地址和端口
  2. 权重:weight用来配置权重,默认都是1,权重越高分配给这台服务器的请求就越多.(如上配置为每三次请求转发给9080,其余两个转发给9090),需要根据服务器的实际处理能力设置权重.

然后,我们可以配置如下proxy_pass来处理用户请求.

location /{
    proxy_pass http"//backend;
}

当访问Nginx时,会将请求反向代理到backend配置的upstream server.

  • 负载均衡算法:负载均衡用来解决用户请求到来时如何选择upstream server进行处理,默认采用的是round-robin(轮询),同时他支持几种算法:

    1. round0robin:轮询,默认负载均和算法,即以轮询的方式将请求转发到上游服务器,通过配合weight配置可以实现基于权重的轮询
    2. ip_hash:根据客户端IP进行负载均衡,即相同的IP将负载均衡到同一个upstream server.

    3. hash key[consistent]:对某一个key进行或者使用一致性哈希算法进行负载均衡.使用Hash算法存在的问题是,当添加或者删除一台服务器时,将导致很多key被重新负载到不同的服务器;因此,建议考虑一致性哈希算法,这样当添加/删除一台服务器时,只有少数key将被重新负载均衡到不同的服务器.
    4. 哈希算法:此初是根据请求uri进行负载均衡,可以使用Nginx变量,因此,可以实现复杂的算法.
    5. 一致性哈希算法:consistent_key动态指定.
    6. least_conn:将请求负载均衡到最少活跃连接的上游服务器.如果配置的服务器较少,则将转而使用基于权重的轮询算法.
  • 失败重试:主要有两部分配置:upstream server 和 proxy_pass

upstream backend{
    server 192.168.61.1:9080 max_fails =2 fail_timeout =10s weight=1;
    server 192.168.61.1:9090 max_fails =2 fail_timeout=10s weight=1;
}

通过配置上游服务器的 max_fails 和 fail_timeout ,来指定每个上游服务器,当fail_timeout 时间内失败了max_fails 次请求,则认为不可用.然后将摘掉该上游服务器,fail_timeout时间后会再次将该服务器加入到存活上游服务器列表进行重试.

  • 健康检查:Nginx对上游服务器的健康检查默认采用的是惰性策略,Nginx商业版提供了health_check进行主动健康检查.当然也可以集成nginx_upsream_check_module模块来进行主动健康检查,它支持TCP心跳和Http心跳来实现健康检查.

    • TCP心跳检查: ``` upsream backend{ server 192.168.61.1:9080 weight =1; server 192.168.61.1:9090 weight=2; check interval =3000 rise=1 fall=3 timeout=2000 type = tcp }
    1. interval:检测时间间隔,此处配置了每隔3s检测一次
    2. fall:检测失败多少次后,上游服务器被标识为不存活
    3. rise:检测成功多少次后,上游服务器被标识为存活,并可以处理请求
    4. timeout:检测请求超时时间配置
    
    - Http心跳检查
    

    upsream backend{ server 192.168.61.1:9080 weight =1; server 192.168.61.1:9090 weight=2; check interval =3000 rise=1 fall=3 timeout=2000 type = http; check_http_send “HEAD/status HTTP/1.0\r\n\r\n”; check_http_expect_alive http_2xx http_3xx; }

    ```

    1. check_http_send:即检查时发的HTTP请求内容
    2. check_http_expect_alive:当上游服务器返回匹配的响应状态码时,则认为上游服务器存活

隔离

将系统或资源分割开,系统隔离是为了在系统发生故障时,能限定传播范围和影响范围,即发生故障后不会出现滚雪球效应,从而保证只有出问题的服务不可用,其他服务还可继续使用.资源隔了通过隔离来减少资源竞争,保障服务间的互相不影响和可用性.

  • 线程隔离

线程隔离主要是指线程池隔离,在实际使用时,我们会把请求分类,然后交给不同的线程池处理.当一种业务的请求处理发生问题时,不会将故障扩散到其他线程池,从而保证其他服务可用.

image

  • 进程隔离

面对大而全的系统,首先想到的解决方案是通过部署多个实例,经由负载均衡进行路由转发.但是,这种情况无法避免某个模块因为BUG而出现OOM导致整个系统不可用.因此,较好的解决方案是通过将系统拆分为多个子系统来实现物理隔离.通过进程隔离使得某一个子系统出现问题时不会影响到其他子系统.

image

  • 集群隔离

随着系统发展,单实例服务无法满足需求,此时需要服务化技术,通过部署多个服务形成服务集群,来提升系统容量.

image

随着调用方的增多,当秒杀服务被刷会影响到其他服务的稳定性时,考虑为秒杀提供单独的服务集群,即为服务分组,这样当某一个分组出现问题时,不会影响到其他分组,从而实现了故障隔离.

image

  • 读写隔离

通过主从模式将读和写集群分离,读服务只从Redis集群获取数据,当主Redis集群出现问题时,从Redis集群还是可用的,从而不影响用户访问.当Redis集群出现问题时,可以进行其他集群的重试.

image

  • 热点隔离

秒杀,抢购属于非常合适的热点例子,对于这种热点,是能提前知道的,所以将秒杀和抢购做成独立系统或服务进行隔离,从而保证秒杀抢购流程出现问题时不影响主流程

对于突发读热点通过缓冲来搞定,而写热点我们一般通过缓存+队列模式削峰.


下一篇 限流

评论