F5Nginx&负载均衡&redis

负载均衡的主要作用如下:
高并发: 负载均衡通过算法调整负载,尽力均匀的分配应用集群中各节点的工作量,以此提高应用集群的并发处理能力(吞吐量)。
伸缩性: 添加或减少服务器数量,然后由负载均衡进行分发控制。这使得应用集群具备伸缩性。
高可用: 负载均衡器可以监控候选服务器,当服务器不可用时,自动跳过,将请求分发给可用的服务器。这使得应用集群具备高可用的特性。
安全防护: 有些负载均衡软件或硬件提供了安全性功能,如:黑白名单处理、防火墙,防 DDos 攻击等。

负载均衡算法

1,随机算法(Random)
    private static final Random random = ThreadLocalRandom.current();
    protected static MyNode doSelect(List<MyNode> nodes, String ip) {
        int length = nodes.size();
        AtomicInteger totalWeight = new AtomicInteger(0);
        System.out.println("begin:"+totalWeight);

        for (MyNode node : nodes) {
            Integer weight = node.getWeight();
            totalWeight.getAndAdd(weight);
        }
        System.out.println("totalWeight:"+totalWeight);

        if (totalWeight.get() > 0) {
            int offset = random.nextInt(totalWeight.get());
            System.out.println("offset:"+offset);
            for (MyNode node : nodes) {
                System.out.println("node:"+node);
// 让随机值 offset 减去权重值
                offset -= node.getWeight();
                if (offset < 0) {
// 返回相应的 Node
                    return node;
                }
            }
        }
// 直接随机返回一个
        return nodes.get(random.nextInt(length));
    }

2,轮询负载均衡算法实现 @@@该方案并没有做的原子操作
    private final AtomicInteger position = new AtomicInteger(0);
    @Override
    protected N doSelect(List<N> nodes, String ip) {
        int length = nodes.size();
// 如果位置值已经等于节点数,重置为 0
        position.compareAndSet(length, 0);
        N node = nodes.get(position.get());
        position.getAndIncrement();
        return node;
    }
    Thread t1 = new Thread(){
        public void run(){
            MyNode node = doSelect2(nodes,"");
            System.out.println(node);
        }
    };
    Thread t2 = new Thread(){
        public void run(){
            MyNode node = doSelect2(nodes,"");
            System.out.println("t2:"+node);
        }
    };
    t1.start();
    t2.start();
    System.out.println("start");

  

 

3,其他算法
加权轮询算法
最小活跃数
源地址哈希
源地址哈希(IP Hash) 算法 根据请求源 IP,通过哈希计算得到一个数值,用该数值在候选服务器列表的进行取模运算,得到的结果便是选中的服务器。
一致性哈希

 

 

 


硬件负载均衡的主流产品有:F5 和 A10。
软件负载均衡的 主流产品 有:Nginx、HAProxy、LVS 。
Nginx、HAProxy 可以作为四层或七层负载均衡器。
LVS 可以作为四层负载均衡器。其负载均衡的性能要优于 Nginx。

网络通信分类
1)七层负载均衡 :就是可以根据访问用户的 HTTP 请求头、URL 信息将请求转发到特定的主机。
DNS 重定向
HTTP 重定向
反向代理
2)四层负载均衡 :基于 IP 地址和端口进行请求的转发。
修改 IP 地址
修改 MAC 地址

DNS 即域名解析服务
DNS 即 域名解析服务,是 OSI 第七层网络协议。DNS 被设计为一个树形结构的分布式应用,自上而下依次为:根域名服务器,一级域名服务器,二级域名服务器,... ,本地域名服务器。显然,如果所有数据都存储在根域名服务器,那么 DNS 查询的负载和开销会非常庞大。
因此,DNS 查询相对于 DNS 层级结构,是一个逆向的递归流程,DNS 客户端依次请求本地 DNS 服务器,上一级 DNS 服务器,上上一级 DNS 服务器,... ,根 DNS 服务器(又叫权威 DNS 服务器),一旦命中,立即返回。为了减少查询次数,每一级 DNS 服务器都会设置 DNS 查询缓存。
DNS 负载均衡的工作原理就是:基于 DNS 查询缓存,按照负载情况返回不同服务器的 IP 地址。
DNS 重定向的 优点:
使用简单:负载均衡工作,交给 DNS 服务器处理,省掉了负载均衡服务器维护的麻烦
提高性能:可以支持基于地址的域名解析,解析成距离用户最近的服务器地址(类似 CDN 的原理),可以加快访问速度,改善性能;
DNS 重定向的 缺点:
可用性差:DNS 解析是多级解析,新增/修改 DNS 后,解析时间较长;解析过程中,用户访问网站将失败;
扩展性低:DNS 负载均衡的控制权在域名商那里,无法对其做更多的改善和扩展;
维护性差:也不能反映服务器的当前运行状态;支持的算法少;不能区分服务器的差异(不能根据系统与服务的状态来判断负载)。

反向代理服务的主流产品:Nginx Apache 。
反向代理:发生在 服务端,用户不知道代理的存在。
正向代理:发生在 客户端,是由用户主动发起的
客户端通过主动访问代理服务器,让代理服务器获得需要的外网数据,然后转发回客户端

 

 

 


好在redis官方从版本 2.6.12 开始 SET 命令本身已经包含了设置过期时间的功能。
设置超时时间失败,就释放该锁,避免死锁
1、缓存集中失效
解决:过期时间=基础时间+随机时间
2、缓存穿透
方案一:查存DB 时,如果数据不存在,预热一个特殊空值到缓存中。这样,后续查询都会命中缓存,但是要对特殊值,解析处理。
方案二:构造一个BloomFilter过滤器,初始化全量数据,当接到请求时,在BloomFilter中判断这个key是否存在,如果不存在,直接返回即可,无需再查询缓存和DB
3、缓存大Key
大key要设置合理的过期时间,尽量不淘汰那些大key
缓存的粒度,既不能过大,如果过大很容易导致网络拥堵;也不能过小,如果太小,查询频率会很高,每次请求都要查询多次。
4、缓存数据一致性
方案一:当缓存更新失败后,进行重试,如果重试失败,将失败的key写入MQ消息队列,通过异步任务补偿缓存,保证数据的一致性。
方案二:设置一个较短的过期时间,通过自修复的方式,在缓存过期后,缓存重新加载最新的数据
5、数据并发竞争预热
一旦缓存中的数据过期、或因某些原因被删除等,导致缓存中的数据为空,大量的并发线程请求(查询同一个key)就会一起并发查询数据库,数据库的压力陡然增加
方案:
引入一把全局锁,当缓存未命中时,先尝试获取全局锁,如果拿到锁,才有资格去查询DB,并将数据预热到缓存中。虽然,client端发起的请求非常多,但是由于拿不到锁,只能处于等待状态,休眠500ms尝试3次,当缓存中的数据预热成功后,再从缓存中获取

 

posted @ 2021-12-26 16:52  XUMT111  阅读(411)  评论(0编辑  收藏  举报