JAVA知识点全总结——(九)系统业务开发

上一篇:JAVA知识点全总结——(八)算法与数据结构

9. 系统业务开发

9.1 设置系统缓存

可以使用缓存做数据库的一个缓冲,如果有大量的数据直接连进数据库肯定导致异常,先把数据存放在缓存中,在用一些算法进行处理,确保安全性,可靠性。

9.2 进行应用降级

降级是指将一些非核心的服务端功能有限制的降级,这样可以释放计算机的资源,用来保证核心的业务能够顺利进行。降级的话可以有很多个级别,用来配合不同的异常等级。如果采取降级的话肯定会对现有的一些服务有影响,但是总体上能够保证核心的服务能够继续进行。比如举个例子,如果一个购物网站流量特别大,正常的购买服务不能进行,为了节省带宽,我们可以将网站里的大图替换成小图片,可能清晰度会收到影响,但是可以节省非常多的时间来加载其他的业务部分。

9.3 控制系统限流

限流是指控制系统输入输出的流量来确保数据的正确性,也确保整个系统不会发生崩溃的情况。一般来说系统的吞吐量是可以测算的,一般如果达到了阈值,我们就要采取一些措施来进行限流。

9.3.1 令牌桶限流算法

令牌桶的思想是用一个容器存放令牌,这个令牌是个抽象的概念,我们每秒钟按照固定的速率向其中存放令牌

  1. 如果遇到流量,需要使用令牌才能进行通过限流进行下一步的操作,这个时候流量需要获取令牌才能进行,否则就丢弃或者阻塞
  2. 流量获取相应数量的令牌,通行。令牌桶中数量减少,按照时间恢复
  3. 可能有的流量过大,需要的令牌比令牌桶中的数量还大,可以预支令牌,但是预支之后就不能再次预支了,除非恢复为正数 

令牌桶的方法实际上是控制稳定的限流的量,但是允许流量的波动,可以预支比较灵活。但是问题在于如果一次预支过大也需要进行控制。

9.3.2 漏桶限流算法

  1. 漏桶中有一个稳定的容量,接受上游容量,如果装满了桶就丢弃多余的部分,或者阻塞
  2. 漏桶下面会稳定的以一定的速率进行处理,永远恒定

漏桶的速率是恒定的,稳定性好,但是如果一次流量过大可能导致大量的数据积压不能处理。

9.4 应用级限流

一般的应用容器都会有一个最大链接访问量或者QPS的限制,比如TomCat就在配置里面能够设置最大连接数。或者我们平时的线程池或者连接池类似的结构都能看作限流的工具。

9.4.1 Atomic接口限流

最简单的Atomic原子类可以实现简单的限流,用类似的手法还有信号量等等,都可以实现。

try { 
    if(atomic.incrementAndGet() > 限流数) {
        //拒绝请求 
    } 
    //处理请求
} finally { 
    atomic.decrementAndGet();
}

9.4.2 RateLimiter接口令牌桶

使用Guava的工具包RateLimiter可以进行限流,这个类是按照令牌桶的方式进行限流操作。


RateLimiter limiter = RateLimiter.create(5);
System.out.println(limiter.acquire());
System.out.println(limiter.acquire());
System.out.println(limiter.acquire());
System.out.println(limiter.acquire());
System.out.println(limiter.acquire());
System.out.println(limiter.acquire()); 

\\将得到类似如下的输出: 0.0 0.198239 0.196083 0.200609 0.199599 0.19961

可以一次使用10个令牌但是要等待“负债”,偿还完毕之后才能继续。

9.4.3 接口时间窗口限流

一个时间窗口内请求数的限制,因为如果这个是一个非常底层的服务,有非常多的服务去调用那么令牌桶可能让很多请求等待比较久,或者需要设置很大,效果不好。可以按照时间进行分配,在每个时间段之内对调用量进行限速,这样就起到了一个间接限流的过程。

LoadingCache<Long, AtomicLong> counter = CacheBuilder.newBuilder() 
    .expireAfterWrite(2, TimeUnit.SECONDS) 
    .build(new CacheLoader<Long, AtomicLong>() { 
        @Override 
        public AtomicLong load(Long seconds) throws Exception { 
            return new AtomicLong(0); 
        } 
    });
long limit = 1000;
while(true) { 
    //得到当前秒 
    long currentSeconds = System.currentTimeMillis() / 1000; 
    if(counter.get(currentSeconds).incrementAndGet() > limit) { 
        System.out.println("限流了:" + currentSeconds); 
        continue; 
    } 
    //业务处理
}

因为SmoothBursty允许一定程度的突发,会有人担心如果允许这种突发,假设突然间来了很大的流量,那么系统很可能扛不住这种突发。因此需要一种平滑速率的限流工具,从而系统冷启动后慢慢的趋于平均固定速率(即刚开始速率小一些,然后慢慢趋于我们设置的固定速率)。Guava也提供了SmoothWarmingUp来实现这种需求,其可以认为是漏桶算法,但是在某些特殊场景又不太一样。

另外一个例子,假如我们会产生一个数据流,然后我们想以每秒5kb的速度发送出去.我们可以每获取一个令牌(permit)就发送一个byte的数据,这样我们就可以通过一个每秒5000个令牌的RateLimiter来实现。

另外,我们也可以使用非阻塞的形式达到降级运行的目的,即使用非阻塞的tryAcquire()方法。分布式限流

9.4 设置系统熔断

服务熔断也称服务隔离,服务熔断对服务提供了proxy,防止服务不可能时,出现串联故障,导致雪崩效应。服务熔断一般是下游服务故障引起,而服务降级一般是从整体负荷考虑。如果遇到熔断,则上级会调用相应的降级方案,过一段时间再进行调用。

猜你喜欢

转载自blog.csdn.net/QuinnNorris/article/details/81207929