服务一般须要考虑速度和容量限制,加强系统的鲁棒性。缓存
笔者曾负责过某公司内公众号服务开发。公众号接口服务接收到用户的推送请求后会构造公众号消息并写入消息队列,路由服务异步接收到消息后进行消息存储后,再交由推送服务向用户推送消息。基本流程以下图所示: bash
若存储服务异常,系统会出现什么问题?数据结构
基于信号量实现限制容量的本地缓存。容量大小为信号量个数,当路由服务发起消息存储请求时,信号量减1。当路由服务接收到存储成功通知后,信号量加1。异步
基于信号量实现的限容数据结构BlockingHashMap性能
public class BlockingHashMap<K, V> {
private static final int DEFAULT_MAX_AVAILABLE = 1000;
private final ConcurrentHashMap<K, V> inmap = new ConcurrentHashMap<>(DEFAULT_MAX_AVAILABLE);
private Semaphore sem;
public BlockingHashMap() {
this(DEFAULT_MAX_AVAILABLE);
}
public BlockingHashMap(int permits) {
sem = new Semaphore(permits);
}
public V put(K key, V value) {
boolean wasAdded = false;
try {
sem.acquire();
V v = inmap.putIfAbsent(key, value);
if (v != null) {
return v;
}
wasAdded = true;
} catch (Exception e) {
} finally {
if (!wasAdded) {
// 若添加失败,须要释放信号量
sem.release();
}
}
return value;
}
public V remove(K key) {
V value = inmap.remove(key);
if (value != null) {
// 只有当成功移除元素时才释放信号量
sem.release();
}
return value;
}
}
复制代码
基于信号量实现固定容量的本地缓存,简单有效。ui