I am attempting to save an Employee object to the off-heap tier of the EHCache using the Kryo serializer, and it is occupying more space than when I attempted to save it without the Kryo serializer. I have provided the code snippet and tier statistics below. Any suggestion why is it behaving like this?
Tier Statistic with Kryo
tierStats=[TierStats(tierName=OffHeap, allocatedByteSize=6094848, occupiedByteSize=4184000, evictions=0, expirations=0, hits=0, misses=0, mappings=1000, puts=0, removals=0)])
Tier Statistic without Kryo
tierStats=[TierStats(tierName=OffHeap, allocatedByteSize=4259840, occupiedByteSize=119200, evictions=0, expirations=0, hits=0, misses=0, mappings=1000, puts=0, removals=0)])
Also I used Kryo to serialize same set of objects and saved in the fie, and the file size is around 4KB which is way less than occupiedByteSize in EHCache
version
implementation 'org.ehcache:ehcache:3.10.0'
implementation 'com.esotericsoftware:kryo:5.6.0'
Code Snippet
public class Employee implements Serializable {
String name;
int id;
public Employee(String name, int id) {
this.name = name;
this.id = id;
}
}
public class EmployeeKryoSerializer implements Serializer<Employee> {
private static final Kryo kryo = new Kryo();
public EmployeeKryoSerializer(ClassLoader loader) {
kryo.register(Employee.class);
}
@Override
public ByteBuffer serialize(Employee object) throws SerializerException {
Output output = new Output(new ByteArrayOutputStream());
kryo.writeObject(output, object);
output.close();
return ByteBuffer.wrap(output.getBuffer());
}
@Override
public Employee read(ByteBuffer binary) throws SerializerException {
Input input = new Input(new ByteBufferInputStream(binary));
return kryo.readObject(input, Employee.class);
}
@Override
public boolean equals(Employee object, ByteBuffer binary) throws ClassNotFoundException, SerializerException {
return object.equals(read(binary));
}
}
public class KryoSerializationTest {
public static void main(String[] args) throws IOException {
Employee test = new Employee("TestName", 1);
testNormalKryoDummyObject(test);
testEHCacheDummyObject(test);
}
private static void testNormalKryoDummyObject( Employee test) throws IOException {
Kryo kryo = new Kryo();
kryo.register(Employee.class);
Output output = new Output(new ByteArrayOutputStream());
for (int i = 0; i < 1000; i++) {
kryo.writeObject(output, test);
}
output.close();
FileOutputStream fileOutputStream = new FileOutputStream("kryo_employee.bin");
fileOutputStream.write(output.getBuffer());
fileOutputStream.flush();
fileOutputStream.close();
}
private static void testEHCacheDummyObject(Employee test){
StatisticsService odStatisticsService = new DefaultStatisticsService();
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.using(odStatisticsService)
.build(true);
Cache<String, Employee> odPairCache = cacheManager.createCache("TEST_EH_CACHE",
CacheConfigurationBuilder.newCacheConfigurationBuilder(
String.class,
Employee.class,
ResourcePoolsBuilder.newResourcePoolsBuilder().offheap(100, MemoryUnit.MB).build())
.withValueSerializer(EmployeeKryoSerializer.class)
.build());
for (int i = 0; i < 1000; i++) {
odPairCache.put("XYZ"+i+"-"+"ABC",test);
printEHStatistic("TEST_EH_CACHE", odStatisticsService);
}
}
private static void printEHStatistic(String cacheName, StatisticsService odStatisticsService) {
CacheStatistics cacheStatistics = odStatisticsService.getCacheStatistics(cacheName);
EHCacheStatistic ehCacheStatistic =
EHCacheStatistic.builder()
.cacheName(cacheName)
.cacheMissPercentage(cacheStatistics.getCacheMissPercentage())
.cacheEvictions(cacheStatistics.getCacheEvictions())
.cacheExpirations(cacheStatistics.getCacheExpirations())
.cacheGets(cacheStatistics.getCacheGets())
.cacheMisses(cacheStatistics.getCacheMisses())
.cacheRemovals(cacheStatistics.getCacheRemovals())
.cachePuts(cacheStatistics.getCachePuts())
.cacheHits(cacheStatistics.getCacheHits())
.cacheHitPercentage(cacheStatistics.getCacheHitPercentage())
.tierStats(new ArrayList<>())
.build();
cacheStatistics
.getTierStatistics()
.forEach(
(tierName, tierStats) -> ehCacheStatistic
.getTierStats()
.add(
TierStats.builder()
.tierName(tierName)
.allocatedByteSize(tierStats.getAllocatedByteSize())
.occupiedByteSize(tierStats.getOccupiedByteSize())
.evictions(tierStats.getEvictions())
.expirations(tierStats.getExpirations())
.hits(tierStats.getHits())
.misses(tierStats.getMisses())
.mappings(tierStats.getMappings())
.puts(tierStats.getPuts())
.removals(tierStats.getRemovals())
.build()));
System.out.println(ehCacheStatistic.toString());
}
}
Need to know why EHcache taking more space with Kryo Serializer
I can't speak for what Kryo is doing but the default serializer in Ehcache is giving you:
That's 27 bytes in total. Default Ehcache serialization is pretty space efficient. I'm sure with enough configuration you could get Kryo underneath this. That would be an exercise for someone more experienced with Kyro though.