Размер хранилища файлов Infispan не пропорционален размеру данных

Я написал небольшой PoC с бесконечным кешем (код ниже), чтобы попытаться оценить производительность с бесконечной продолжительностью. во время его работы я обнаружил, что для моей конфигурации infinispan, по-видимому, не очищает старые копии записей кэша с диска, что приводит к использованию дискового пространства, которое на порядки больше ожидаемого.

Что я могу сделать, чтобы сократить использование диска примерно до размера фактических данных?

вот мой тестовый код:

import org.infinispan.AdvancedCache;
import org.infinispan.manager.DefaultCacheManager;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Random;

public class App {
    final static int ELEMENTS_PER_BIN = 1000;
    final static int NUM_OF_BINS = 100;

    public static void main(String[] args) throws Exception {
        File storeFile = new File("store/store.dat");
        if (storeFile.exists() && !storeFile.delete()) {
            throw new IllegalStateException("unable to delete store file from previous run");
        }

        DefaultCacheManager cm = new DefaultCacheManager("infinispan.xml");
        AdvancedCache<String, Bin> cache = cm.<String,Bin>getCache("store").getAdvancedCache();

        Random rng = new Random(System.currentTimeMillis());

        for (int i=0; i<ELEMENTS_PER_BIN; i++) {
            for (int j=0; j<NUM_OF_BINS; j++) {
                String key = "bin-"+j;
                Bin bin = cache.get(key); //get from cache
                if (bin==null) {
                    bin = new Bin();
                }
                bin.add(rng.nextLong()); //modify
                cache.put(key, bin); //write back
            }
        }

        long expectedSize = 0;

        for (int j=0; j<NUM_OF_BINS; j++) {
            String key = "bin-"+j;
            Bin bin = cache.get(key);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(bin);
            oos.flush();
            oos.close();
            expectedSize += baos.size();
            baos.close();
        }

        long actualSize = new File("store/store.dat").length();

        System.err.println(ELEMENTS_PER_BIN+" elements x "+NUM_OF_BINS+" bins. expected="+expectedSize+" actual="+actualSize+" in "+cache.size()+" elements. diff="+(actualSize/(double)expectedSize));
    }

    public static class Bin implements Serializable{
        private long[] data = null;
        public void add(long datum) {
            data = data==null ? new long[1] : Arrays.copyOf(data, data.length+1); //expand capacity
            data[data.length-1] = datum;
        }
    }
}

и вот бесконечная конфигурация:

<infinispan
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="urn:infinispan:config:6.0 http://www.infinispan.org/schemas/infinispan-config-6.0.xsd"
        xmlns="urn:infinispan:config:6.0">
    <namedCache name="store">
        <eviction strategy="LRU" maxEntries="20"/>
        <persistence passivation="false">
            <singleFile location="store">
                <async enabled="false"/>
            </singleFile>
        </persistence>
    </namedCache>
</infinispan>

Infinispan (должен быть?) настроен как сквозной кэш с 20 последними элементами в оперативной памяти и оперативной копией всего на диске.

выполнение приведенного выше кода дает это:

1000 элементов х 100 бункеров. ожидается =807300 фактических =411664404 в 100 элементах. Diff= +509,92741731698254

Это означает, что для 788 КБ данных я получаю файл ~392 МБ!

Что я делаю неправильно?

рассматриваемая версия infinispan - 6.0.2.

1 ответ

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

Кстати, для определения ожидаемого размера вам также необходимо:

  • использовать JBoss Marshalling вместо сериализации Java
  • а также сериализовать ключ
  • сериализовать метаданные Infinispan (например, время жизни записи, время последнего использования, возможно, версия и т. д.)
Другие вопросы по тегам