今天在脉脉上看到一道蚂蚁的笔试题,尝试解答一下
理解题目
首先题目的场景是高并发场景下,大量的请求先查询缓存,缓存查询不到的情况下,直接请求DB(DB存在该条数据),这个场景通常叫做“缓存击穿”,这样可能会给DB造成很大的压力。
解决这个问题的思路就是用另外一个结构来对高并发的流量进行削峰,最简单的方式就是引入一个新的线程池来处理这些请求。
尝试解答
package com.practice.jdk;
import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.Logger;
public class Demo {
private Logger logger = Logger.getLogger(Demo.class.getName());
private static HashMap<String, String> cache = new HashMap();
private ExecutorService es = Executors.newFixedThreadPool(1);
private void setCache(String key, String value) {
cache.put(key, value);
}
private String getFromDB(String key) {
//模拟DB响应时长
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.info("线程:" + Thread.currentThread().getName() + "从DB获取数据成功");
return "MOCK VALUE";
}
private String getFromCache(String key) {
return cache.get(key);
}
public String getValueFromApp(String key) {
String cache = getFromCache(key);
if (StringUtils.isNotEmpty(cache)) {
logger.info(String.format("线程%s从缓存获取数据[key=%s,value=%s]成功",Thread.currentThread().getName(),key,cache));
return cache;
}
Future<String> future = es.submit(() -> {
return getFromDB(key);
});
try {
String result = future.get();
setCache(key, result);
return result;
} catch (InterruptedException | ExecutionException e) {
logger.info("获取结果异常");
e.printStackTrace();
}
return StringUtils.EMPTY;
}
public static void main(String[] args) throws InterruptedException {
Demo demo = new Demo();
demo.setCache("f","v1");
demo.setCache("m","v2");
new Thread(()->{
demo.getValueFromApp("f");
}).start();
new Thread(()->{
demo.getValueFromApp("m");
}).start();
new Thread(()->{
demo.getValueFromApp("a");
}).start();
new Thread(()->{
demo.getValueFromApp("b");
}).start();
new Thread(()->{
demo.getValueFromApp("c");
}).start();
}
}复制
这里我将线程池核心线程设置为1,可以从日志看出最终是相当于串行请求DB。
十二月 07, 2021 12:23:52 上午 com.practice.jdk.Demo getValueFromApp
信息: 线程Thread-2从缓存获取数据[key=m,value=v2]成功
十二月 07, 2021 12:23:52 上午 com.practice.jdk.Demo getValueFromApp
信息: 线程Thread-1从缓存获取数据[key=f,value=v1]成功
十二月 07, 2021 12:23:53 上午 com.practice.jdk.Demo getFromDB
信息: 线程:pool-1-thread-1从DB获取数据成功
十二月 07, 2021 12:23:54 上午 com.practice.jdk.Demo getFromDB
信息: 线程:pool-1-thread-1从DB获取数据成功
十二月 07, 2021 12:23:55 上午 com.practice.jdk.Demo getFromDB
信息: 线程:pool-1-thread-1从DB获取数据成功复制
在当前场景单机的话,我在代码中假定数据库处理一个请求需要1s,则数据库承受的QPS=1,实际场景可以根据数据库承受的QPS来调整线程池大小。
除了线程池,Semaphore也是很适合这个场景,通过控制Semaphore的线程个数,作用和线程类似,这里我就不贴代码了。
扩展思考
看到很多人说用锁,锁和上面的答案区别在于,锁没法控制执行线程的数量。
如果是想动态调整并发度,可以了解下动态线程池。
文章转载自来搞笑的Yuan,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。
评论
相关阅读
2025年4月中国数据库流行度排行榜:OB高分复登顶,崖山稳驭撼十强
墨天轮编辑部
1323次阅读
2025-04-09 15:33:27
2025年3月国产数据库大事记
墨天轮编辑部
737次阅读
2025-04-03 15:21:16
2025年3月国产数据库中标情况一览:TDSQL大单622万、GaussDB大单581万……
通讯员
536次阅读
2025-04-10 15:35:48
征文大赛 |「码」上数据库—— KWDB 2025 创作者计划启动
KaiwuDB
458次阅读
2025-04-01 20:42:12
数据库,没有关税却有壁垒
多明戈教你玩狼人杀
409次阅读
2025-04-11 09:38:42
优炫数据库成功应用于国家电投集团青海海南州新能源电厂!
优炫软件
384次阅读
2025-03-21 10:34:08
天津市政府数据库框采结果公布!
通讯员
316次阅读
2025-04-10 12:32:35
最近我为什么不写评论国产数据库的文章了
白鳝的洞穴
314次阅读
2025-04-07 09:44:54
国产数据库需要扩大场景覆盖面才能在竞争中更有优势
白鳝的洞穴
273次阅读
2025-04-14 09:40:20
从HaloDB体验到国产数据库兼容性
多明戈教你玩狼人杀
268次阅读
2025-04-07 09:36:17