You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@ignite.apache.org by max904 <ma...@yandex.ru> on 2020/07/28 11:56:35 UTC

Severe performance impact to key-value API on an SQL-enabled cache (even with empty QueryEntity configuration)

I've come across strange and severe performance impact that Ignite
QueryEntity makes onto the regular cache operations.
I narrowed it down just to adding "empty" QueryEntity to the
CacheConfiguration as below:
    final QueryEntity queryEntity = new QueryEntity(EmployeeId.class,
Employee.class);
    queryEntity.setTableName("EMPLOYEE");
    cacheConfig.setQueryEntities(Collections.singletonList(queryEntity));
Below are the results of JMH run for put/get cache operations

TEST 1: Employee cache put/get with NO QueryEntity added.
Result "EmployeeBenchmark.putGetBinary":
  51566.775 �(99.9%) 2186.773 ops/s [Average]
  (min, avg, max) = (51431.529, 51566.775, 51659.873), stdev = 119.864
  CI (99.9%): [49380.001, 53753.548] (assumes normal distribution)

Benchmark                        Mode  Cnt      Score       Error  Units
EmployeeBenchmark.putGetBinary  thrpt    3  51566.775 �  2186.773  ops/s

----------------------

TEST 2: Employee cache put/get with 'empty' QueryEntity added.
Result "EmployeeBenchmark.putGetBinary":
  22305.457 �(99.9%) 20543.041 ops/s [Average]
  (min, avg, max) = (21156.787, 22305.457, 23407.399), stdev = 1126.033
  CI (99.9%): [1762.416, 42848.498] (assumes normal distribution)

Benchmark                        Mode  Cnt      Score       Error  Units
EmployeeBenchmark.putGetBinary  thrpt    3  22305.457 � 20543.041  ops/s

The difference is very significant (5/2 and in some runs even 5/1) and I
cannot explain it by any indexing (there is none in both cases).
- How can this be explained and mitigated?
- Am I doing something wrong?

I have already checked the article on "indexes not fitting into maximum
inline size" as possible cause of performance degradation on the key-value
API, but it does not apply in my case (there are no indexes defined).

Find more concrete details below...
----------------------

// The cache configuration is very simple as below.
// Where Employee and EmployeeId are very simple Java beans.

final CacheConfiguration<EmployeeId, Employee> cacheConfig = new
CacheConfiguration<>();
cacheConfig.setTypes(EmployeeId.class, Employee.class);
cacheConfig.setName("employee");

// The following fragment disabled in TEST 1 and enabled in TEST 2
final QueryEntity queryEntity = new QueryEntity(EmployeeId.class,
Employee.class);
queryEntity.setTableName("EMPLOYEE");
cacheConfig.setQueryEntities(Collections.singletonList(queryEntity));

IgniteCache<BinaryObject, BinaryObject> employeeCache =
ignite.getOrCreateCache(cacheConfig).withKeepBinary();

// The benchmark code is extremely simple - create new Employee BinaryObject
and perform put/get on it
// Note that I have to "clone" the key due to the other bug I reported
earlier (https://issues.apache.org/jira/browse/IGNITE-12911)

@Benchmark
@OutputTimeUnit(TimeUnit.SECONDS)
@BenchmarkMode(Mode.Throughput)
@Warmup(iterations = 1, time = 5)
@Measurement(iterations = 3)
public void putGetBinary(Blackhole bh) throws Exception {
  final BinaryObject employee = newEmployee(ignite, employeeNumber);
  final BinaryObject employeeId =
      ignite.binary().builder((BinaryObject) employee.field("id")).build();
  employeeCache.put(employeeId, employee);
  bh.consume(employeeCache.get(employeeId));
}

// The Employee BinaryObject instantiated like to following

static BinaryObject newEmployee(Ignite ignite, AtomicInteger employeeNumber)
{
  final BinaryObjectBuilder employeeId =
ignite.binary().builder(EmployeeId.class.getName());
  employeeId.setField("departmentNumber", 123, Integer.class);
  employeeId.setField("employeeNumber", employeeNumber.incrementAndGet(),
Integer.class);

  final BinaryObjectBuilder address =
ignite.binary().builder(Address.class.getName());
  address.setField("street", "101 2nd St", String.class);
  address.setField("city", "Palo Alto", String.class);
  address.setField("state", "CA", String.class);
  address.setField("zip", 94306, Integer.class);
  address.setField("country", "USA", String.class);

  final BinaryObjectBuilder employee =
ignite.binary().builder(Employee.class.getName());
  employee.setField("id", employeeId);
  employee.setField("firstName", "John", String.class);
  employee.setField("lastName", "Smith", String.class);
  employee.setField("birthDate", newDate(1968, 12, 24), Date.class);
  employee.setField("hireDate", newDate(2010, 6, 15), Date.class);
  employee.setField("homeAddress", address);

  return employee.build();
}




--
Sent from: http://apache-ignite-users.70518.x6.nabble.com/

Re: Severe performance impact to key-value API on an SQL-enabled cache (even with empty QueryEntity configuration)

Posted by Ilya Kasnacheev <il...@gmail.com>.
Hello!

Yes, it is possible that adding a primary key will have such impact, given
that you don't do anything meaningful in your test: you have trivial
objects and you just put these to memory.

In this case, any overhead translates to a lot of performance drop because
growth from zero (of CPU time/op) is fast.

Regards,
-- 
Ilya Kasnacheev


вт, 18 авг. 2020 г. в 11:43, max904 <ma...@yandex.ru>:

> >> I'm not sure what this test doing
>
> The test is demonstrating significant reduction of the throughput when
> empty
> QueryEntity added to the cache config.
>
> >> how many ops are done per iteration?
>
> Iterations are time based. It uses the default defined by JMH. One
> iteration
> conducted to warm up during 5 seconds and three iterations conducted to
> take
> the measurement using default interval (I think something around 10
> seconds).
>
> >> Why do you need to start Ignite for every iteration
>
> No particular reason. Done just in sake of clean benchmark results. What
> difference does it make?
>
> >> but I want to say that adding indexing to your cache means having a
> >> primary key, in your case a composite primary key, and updating this
> >> index is going to take some CPU time, especially since there's nothing
> >> else to consume it.
>
> First of all, there are no explicit indexes defined by the test.
> The throughput got reduced from 51566.775 ops/s in simple K-V case to
> 22305.457 ops/s when "empty" QueryEntity added. It's more than 50%!
> Do you believe that implicit primary key creation has such severe impact?
>
>
>
>
>
> --
> Sent from: http://apache-ignite-users.70518.x6.nabble.com/
>

Re: Severe performance impact to key-value API on an SQL-enabled cache (even with empty QueryEntity configuration)

Posted by max904 <ma...@yandex.ru>.
>> I'm not sure what this test doing

The test is demonstrating significant reduction of the throughput when empty
QueryEntity added to the cache config.

>> how many ops are done per iteration?

Iterations are time based. It uses the default defined by JMH. One iteration
conducted to warm up during 5 seconds and three iterations conducted to take
the measurement using default interval (I think something around 10
seconds).

>> Why do you need to start Ignite for every iteration

No particular reason. Done just in sake of clean benchmark results. What
difference does it make?

>> but I want to say that adding indexing to your cache means having a
>> primary key, in your case a composite primary key, and updating this
>> index is going to take some CPU time, especially since there's nothing
>> else to consume it.

First of all, there are no explicit indexes defined by the test.
The throughput got reduced from 51566.775 ops/s in simple K-V case to
22305.457 ops/s when "empty" QueryEntity added. It's more than 50%!
Do you believe that implicit primary key creation has such severe impact?





--
Sent from: http://apache-ignite-users.70518.x6.nabble.com/

Re: Severe performance impact to key-value API on an SQL-enabled cache (even with empty QueryEntity configuration)

Posted by Ilya Kasnacheev <il...@gmail.com>.
Hello!

I'm not sure what this test doing (how many ops are done per iteration? Why
do you need to start Ignite for every iteration), but I want to say that
adding indexing to your cache means having a primary key, in your case a
composite primary key, and updating this index is going to take some CPU
time, especially since there's nothing else to consume it.

Regards,
-- 
Ilya Kasnacheev


чт, 30 июл. 2020 г. в 10:42, max904 <ma...@yandex.ru>:

> Thank you, Anton!
>
> Please find the reproducer code attached.
> employee_benchmark.zip
> <
> http://apache-ignite-users.70518.x6.nabble.com/file/t2036/employee_benchmark.zip>
>
>
> I ran the test with Java 11 and Ignite 2.8.1.
>
> Following additional dependencies needed in order to run JMH benchmark:
>
> testImplementation 'org.openjdk.jmh:jmh-core:1.23'
> testImplementation 'org.openjdk.jmh:jmh-generator-annprocess:1.23'
> testAnnotationProcessor 'org.openjdk.jmh:jmh-generator-annprocess:1.23'
>
>
>
>
> --
> Sent from: http://apache-ignite-users.70518.x6.nabble.com/
>

Re: Severe performance impact to key-value API on an SQL-enabled cache (even with empty QueryEntity configuration)

Posted by max904 <ma...@yandex.ru>.
Thank you, Anton!

Please find the reproducer code attached.
employee_benchmark.zip
<http://apache-ignite-users.70518.x6.nabble.com/file/t2036/employee_benchmark.zip>  

I ran the test with Java 11 and Ignite 2.8.1.

Following additional dependencies needed in order to run JMH benchmark:

testImplementation 'org.openjdk.jmh:jmh-core:1.23'
testImplementation 'org.openjdk.jmh:jmh-generator-annprocess:1.23'
testAnnotationProcessor 'org.openjdk.jmh:jmh-generator-annprocess:1.23'




--
Sent from: http://apache-ignite-users.70518.x6.nabble.com/

Re: Severe performance impact to key-value API on an SQL-enabled cache (even with empty QueryEntity configuration)

Posted by akurbanov <an...@gmail.com>.
Hello, 

I'll try to do this, but just in case, could you provide (attach or github
link) standalone executable reproducer to showcase the observed performance?

Best regards,
Anton



--
Sent from: http://apache-ignite-users.70518.x6.nabble.com/