Vert.x SharedData能否可靠存储类LRU结构?有无低锁可变列表存储方案?
解决方案
1. 用AsyncMap的原子更新操作替代全局锁
不用给整个Map加锁,而是利用AsyncMap提供的get+replace原子组合操作处理列表更新,步骤如下:
- 通过
get(key)获取当前队列列表 - 修改列表:添加新元素,若长度超过设定容量则移除最早的条目
- 调用
replace(key, oldList, newList)完成原子替换 - 如果
replace返回false,说明期间有其他节点修改了该值,重试整个流程即可
这种方式仅当并发修改同一个key时才会触发重试,锁粒度远小于全局锁,示例代码:
private void addToQueue(AsyncMap<String, List<String>> asyncMap, String key, String item, int maxSize) { asyncMap.get(key) .onSuccess(currentList -> { List<String> newList = currentList == null ? new ArrayList<>() : new ArrayList<>(currentList); newList.add(item); if (newList.size() > maxSize) { newList.remove(0); // 移除最早条目 } asyncMap.replace(key, currentList, newList) .onSuccess(replaced -> { if (!replaced) { // 并发冲突,重试 addToQueue(asyncMap, key, item, maxSize); } }) .onFailure(err -> { // 处理错误 }); }) .onFailure(err -> { // 处理错误 }); }
2. 本地缓存+EventBus同步(适合读多写少场景)
如果队列访问有较强的局部性,可以在每个节点维护LocalMap的本地队列副本,更新逻辑如下:
- 优先操作本地
LocalMap里的队列:添加元素并检查容量,移除最早条目 - 发送EventBus消息到集群内其他节点,通知它们同步更新对应key的队列
- 其他节点收到消息后,更新自己的本地
LocalMap副本
这种方式大部分操作都是本地的,仅同步时用到EventBus,完全避免分布式锁,但要注意最终一致性——短时间内不同节点的队列副本可能不一致,适合对一致性要求不高的场景。
3. 细粒度Key锁
给每个队列对应的key单独申请分布式锁,而非给整个AsyncMap加锁:
- 通过
SharedData.getLock(key)获取该key专属的锁 - 锁获取成功后,执行
get→修改列表→put的操作 - 操作完成后释放锁
这样不同key的队列操作可以并行执行,只有同一key的并发请求才会互斥,锁竞争比全局锁小很多,示例代码:
private void addToQueueWithLock(SharedData sharedData, String key, String item, int maxSize) { sharedData.getLock(key) .onSuccess(lock -> { sharedData.<String, List<String>>getAsyncMap("my-queue-map") .onSuccess(asyncMap -> { asyncMap.get(key) .onSuccess(currentList -> { List<String> newList = currentList == null ? new ArrayList<>() : new ArrayList<>(currentList); newList.add(item); if (newList.size() > maxSize) { newList.remove(0); } asyncMap.put(key, newList) .onSuccess(v -> lock.release()) .onFailure(err -> { lock.release(); // 处理错误 }); }) .onFailure(err -> { lock.release(); // 处理错误 }); }) .onFailure(err -> { lock.release(); // 处理错误 }); }) .onFailure(err -> { // 处理锁获取失败 }); }
注意事项
- 原子更新的重试次数要限制,避免无限循环
- 容量检查逻辑要统一,确保所有节点执行相同的移除规则
- 若用EventBus同步,要处理消息丢失的情况(比如添加消息重试机制)
内容的提问来源于stack exchange,提问作者Guss
相关产品推荐
相关产品推荐

