JAVA知识点全总结——(九)系统业务开发
9. 系统业务开发
9.1 设置系统缓存
可以使用缓存做数据库的一个缓冲,如果有大量的数据直接连进数据库肯定导致异常,先把数据存放在缓存中,在用一些算法进行处理,确保安全性,可靠性。
9.2 进行应用降级
降级是指将一些非核心的服务端功能有限制的降级,这样可以释放计算机的资源,用来保证核心的业务能够顺利进行。降级的话可以有很多个级别,用来配合不同的异常等级。如果采取降级的话肯定会对现有的一些服务有影响,但是总体上能够保证核心的服务能够继续进行。比如举个例子,如果一个购物网站流量特别大,正常的购买服务不能进行,为了节省带宽,我们可以将网站里的大图替换成小图片,可能清晰度会收到影响,但是可以节省非常多的时间来加载其他的业务部分。
9.3 控制系统限流
限流是指控制系统输入输出的流量来确保数据的正确性,也确保整个系统不会发生崩溃的情况。一般来说系统的吞吐量是可以测算的,一般如果达到了阈值,我们就要采取一些措施来进行限流。
9.3.1 令牌桶限流算法
令牌桶的思想是用一个容器存放令牌,这个令牌是个抽象的概念,我们每秒钟按照固定的速率向其中存放令牌
- 如果遇到流量,需要使用令牌才能进行通过限流进行下一步的操作,这个时候流量需要获取令牌才能进行,否则就丢弃或者阻塞
- 流量获取相应数量的令牌,通行。令牌桶中数量减少,按照时间恢复
- 可能有的流量过大,需要的令牌比令牌桶中的数量还大,可以预支令牌,但是预支之后就不能再次预支了,除非恢复为正数
令牌桶的方法实际上是控制稳定的限流的量,但是允许流量的波动,可以预支比较灵活。但是问题在于如果一次预支过大也需要进行控制。
9.3.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,防止服务不可能时,出现串联故障,导致雪崩效应。服务熔断一般是下游服务故障引起,而服务降级一般是从整体负荷考虑。如果遇到熔断,则上级会调用相应的降级方案,过一段时间再进行调用。
上一篇: IE遍历数组时遇到的问题
下一篇: golang学习(八):数组