Как создать кэш с отложенной записью из памяти в базу данных? - PullRequest
0 голосов
/ 17 октября 2018

Моя цель - кэшировать данные на 60-е годы.Как только запись снова будет прочитана из кеша, я хочу удалить ее из кеша (разрешить только однократное чтение).

Если эти 60 с истечением времени истекли, а запись все еще доступна в кеше, я хочузапись за записью в базе данных.

Существует ли какая-либо существующая технология / spring / apache framework, которая уже предлагает такой кеш?(sidenote: я не хочу использовать сложные библиотеки, такие как redis, ehcache и т. д. для такого простого сценария использования).

Если установить вручную, я буду делать следующее.Но, возможно, есть лучшие варианты?

@Service
public class WriteBehindCache {
    static class ObjectEntry {
        Object data;
        LocalDateTime timestamp;

        public ObjectEntry(Object data) {
              this.data = data;
              timestamp = LocalDateTime.now();
        }
    }

    Map<String, ObjectEntry> cache = new ConcurrentHashMap<>();

    //batch every minute
    @Scheduled(fixedRate = 60000)
    public void writeBehind() {
        LocalDateTime now = LocalDateTime.now();
        List<ObjectEntry> outdated = cache.values()
             .filter(entry -> entry.getValue().timestamp.plusSeconds(60).isBefore(now))
             .collect(Collectors.toList());

        databaseService.persist(outdated);
        cache.removeAll(outdated); //pseudocode
    }

    //always keep most recent entry
    public void add(String key, Object data) {
        cache.put(key, new ObjectEntry(data));
    }

    //fallback lookup to database if cache is empty
    public Object get(String key) {
        ObjectEntry entry = cache.remove(key);
        if (entry == null) {
            entry = databaseService.query(key);
            if (entry != null)  databaseService.remove(entry);
        }
        return entry;
    }
}

1 Ответ

0 голосов
/ 20 октября 2018

Ваше решение имеет две проблемы:

  • Вы выполняете последовательное сканирование для сохранения, которое будет дорогостоящим при большом количестве записей
  • Код имеет условия гонки
  • Из-за условий гонки код не удовлетворяет вашим требованиям.Можно создать последовательность одновременного доступа, когда запись удаляется из кэша, но также записывается в базу данных

Существует ли какая-либо существующая инфраструктура технологии / spring / apache, которая уже предлагает такиекеш?(sidenote: я не хочу использовать сложные библиотеки, такие как redis, ehcache и т. д. для такого простого варианта использования).

Я думаю, что вы можете решить проблемы параллелизма на основе ConcurrentHashMap.Но я не знаю элегантного способа для тайм-аута.Тем не менее, возможное решение - использовать библиотеку кеширования.Я хотел бы предложить пример, основанный на cache2k , который не тяжелый (около 400 тыс. Jar), ​​а также имеет другие хорошие варианты использования.В качестве дополнения также существует хорошая поддержка абстракции кэширования Spring.

public static class WriteBehindCache {

  Cache<String, Object> cache = Cache2kBuilder.of(String.class, Object.class)
    .addListener((CacheEntryExpiredListener<String, Object>) (cache, entry)
      -> persist(entry.getKey(), entry.getValue()))
    .expireAfterWrite(60, TimeUnit.SECONDS)
    .build();

  public void add(String key, Object data) {
    cache.put(key, data);
  }

  public Object get(String key) {
    return cache.invoke(key, e -> {
      if (e.exists()) {
        Object v = e.getValue();
        e.remove();
        return v;
      }
      return loadAndRemove(e.getKey());
    });
  }


  // stubs
  protected void persist(String key, Object value) {
  }

  protected Object loadAndRemove(String key) {
    return null;
  }

}

При таком подключении кеш блокирует параллельную операцию с одной записью, поэтому можно с уверенностью сказать, что для одной записи выполняется только одна операция базы данных.время.

Вы можете сделать это аналогично другим библиотекам кэширования.При использовании API JCache / JSR107 код выглядел бы почти идентично.

Более "легкий" подход - использовать expiringmap

от jhalterman. Лично я считаю, что кэш должен бытьв каждом наборе инструментов для разработчиков.Тем не менее, я являюсь автором cache2k.Конечно, я должен это сказать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...