【发布时间】:2017-12-23 04:59:10
【问题描述】:
我在最近的一次系统设计面试中遇到了以下问题:
设计一个与缓存和数据库接口的 AppServer。
我想出了这个:
public class AppServer{
public Database DB;
public Cache cache;
public Value get(Key k){
Value res = cache.get(k);
if(res == null){
res = DB.get(k);
cache.set(k, res);
}
}
public void set(Key k, Value v){
cache.set(k, v);
DB.set(k, v);
}
}
此代码很好并且可以正常工作,但是对问题的跟进是:
- 如果有多个线程怎么办?
- 如果有多个 AppServer 实例怎么办?
- AppServer 性能突然下降很多,我们发现这是因为我们的缓存一直丢失。缓存大小是固定的(已经是最大的了)。我们如何防止这种情况发生?
回复:
- 我回答说我们可以使用锁或条件变量。在 Java 中,我们可以在每个方法中添加 Synchronized 以实现互斥,但面试官提到这样做效率不高,只希望同步关键部分。
我以为我们只需要同步void set(Key k, Value v)中的2个set行和Value get(Key k)中的1个set方法,但是面试官要求也同步res = DB.get(k);。我最后同意了他的观点,但并不完全理解。线程没有独立的栈和共享的堆吗?所以当一个线程执行get时,它会将res存储在栈帧上的局部变量中,即使另一个线程顺序执行get,前一个线程也会保留它的get值。然后每个线程设置各自获取的值。
- 我们如何处理 AppServer 的多个实例?
我想出了一个像 Kafka 这样的分布式队列解决方案,每次我们执行 set / get 命令时,我们都会将该命令排队,但他也提到 set 是可以的,因为该操作在缓存 / db 中设置了一个值,但是如何你会返回正确的值吗?有人可以解释一下吗?
还有版本控制系统和事件系统的可能解决方案吗?
- 可能的解决方案:
- L1、L2、L3 缓存 - 层和更多缓存
- 区域/分段缓存 - 为用户组使用不同的缓存。
- 还有其他想法吗?
将支持所有有见地的回复:)
【问题讨论】:
-
@ElliottFrisch ?
-
来自链接:“它做什么?”,答案 3“并发”:并行执行。并发感知请求缓存。通过请求折叠自动批处理。
-
@ElliottFrisch 我不完全理解,您能否详细说明并解决问题的其他部分? :)
-
好奇是否有人知道如何解决这个问题?
标签: java multithreading caching architecture distributed-system