欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-07-15 08:18:36
...

上一篇: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,防止服务不可能时,出现串联故障,导致雪崩效应。服务熔断一般是下游服务故障引起,而服务降级一般是从整体负荷考虑。如果遇到熔断,则上级会调用相应的降级方案,过一段时间再进行调用。