记一次简单版本同时大量请求的处理方案

0.前言

在出统计数据时,一个页面有10多个图表同时并发向同一个接口发起请求,返回不同的数据。如果不做任何处理,想象一下如果10个人同时访问页面那就是100次的数据库访问,这将会导致接口响应异常的慢。加上特殊的情况,数据库并发连接数只支持50次,也就是所如果连接数超过50个需要排队等待。在这样的情况下,做了如下几步处理来缓解这样的访问压力。

信号量限流
得到数据就返回
得到数据就返回
得到数据就返回
控制层
服务层
本地缓存
Redis缓存
数据库访问

1.使用信号量进行访问控流

1.1什么是信号量

一个资源有多个副本可供同时使用,比如打印机房有多个打印机、厕所有多个坑可供同时使用,这种情况下,Java 提供了另外的并发访问控制 – 资源的多副本的并发访问控制,信号量 Semaphore 即是其中的一种。

1.2 Semaphore原理

Semaphore 是用来保护一个或者多个共享资源的访问,Semaphore 内部维护了一个计数器,其值为可以访问的共享资源的个数。一个线程要访问共享资源,先获得信号量,如果信号量的计数器值大于 1,意味着有共享资源可以访问,则使其计数器值减去 1,再访问共享资源。如果计数器值为 0, 线程进入休眠。当某个线程使用完共享资源后,释放信号量,并将信号量内部的计数器加 1,之前进入休眠的线程将被唤醒并再次试图获得信号量。

1.3 Semaphore的使用

Semaphore semaphore = new Semaphore(10,true);
semaphore.acquire();
//do something here
semaphore.release();

2.使用本地缓存和Redis缓存

先访问本地缓存有值直接返回,没有访问Redis缓存,读到把值放进本地缓存返回。
线程池的创建看文章:线程池的应用~~

private Cache<String, SoftReference<Object>> localCache = CacheBuilder.newBuilder()
        //设置cache的初始大小为10,要合理设置该值
        .initialCapacity(50)
        //设置并发数为5,即同一时间最多只能有5个线程往cache执行写入操作
        .concurrencyLevel(5)
        //设置cache中的数据在写入之后的存活时间为3
        .expireAfterWrite(60, TimeUnit.SECONDS)
        //构建cache实例
        .build();

/**
* 获取本地缓存
*/
private Object getCache(String longKey) {
    
    
    Object o = null;
    // 返回与此缓存中的key关联的值,如果key没有缓存值,则返回null 。
    SoftReference<Object> objectSoftReference = localCache.getIfPresent(longKey);
    if(objectSoftReference != null && objectSoftReference.get() != null){
    
    
        o = objectSoftReference.get();
        if(o == null){
    
    
            o = toolRedis.get(longKey);
            if(o != null) {
    
    
                localCache.put(longKey, new SoftReference<>(o));
            }
        }else {
    
    
            //异步写日志,这里使用了线程池,executorService使用Bean对象引入
            executorService.submit(() -> log.info("命中本地缓存,当前本地缓存个数:{},缓存key:{}",
                    localCache.size(),localCache.asMap().keySet()));
        }
    }else{
    
    
        o = toolRedis.get(longKey);
        if(o != null) {
    
    
            localCache.put(longKey, new SoftReference<>(o));
        }
    }
    return o;
}

3.使用数据库访问

这是数据的出处,如果调用getCache(cacheKey)方法返回为空则去访问数据库。

文文的博客~

おすすめ

転載: blog.csdn.net/weixin_42119415/article/details/118888075