...
The current database schema does not allow for Hibernate to use JDBC write batching. There is work worke in progress to address this.
...
There is work in progress to address this behavior using a custom algorithm using JDBC. The use of a graph database would implicitly fix such issues.
Updating data nodes
(NOTE: I have removed the previous test results here, as the testing was flawed).
Analysis is still ongoing, but here is an overview of some of the findings:
- For making CM-handle state updates, NCMP uses CpsDataService::updateDataNodesAndDescendants (plural - taking a Map<xpath, json>). The performance of this function is poor. Because it takes a map of JSON, it needs to instantiate new YangParser for piece of JSON. Better performance would be achieved by using CpsDataService::updateDataNodeAndDescendants (singular - taking a single piece of JSON). Note this API could be removed after, since it is only used by NCMP, and was never exposed as part of the public REST API.
- Related: CpsDataService::saveListElementsBatch likewise has very poor performance compared with CpsDataService::saveListsElements, which can achieve the same effect by correctly preparing the input JSON. The poor performance stems from needing a new YangParser instance for each chunk of JSON instead of a single YangParser for one JSON string. This API is not publicly exposed via the REST API and is only used in one place in NCMP, so it could be removed.
- The main public API for updating data nodes is CpsDataService::updateDataNodeAndDescendants (singular). This API has very high variations in performance, depending on how the JSON is prepared, for example, given an update that effects exactly the same data nodes:
- updating a top-level node with parent path of '/' is much slower than updating the descendants. See table below.
- As such, it is now advised to update data trees at the deepest possible level.
Comparison of updating using different approaches
There are multiple was of updating data nodes, each with different performance.
In these scenario, 1,000 Open ROADM device nodes are already defined. A number of these existing data nodes will be updated using CpsDataService::updateDataNodeAndDescendants (singular).
...
See here: https://vladmihalcea.com/the-best-way-to-map-a-onetomany-association-with-jpa-and-hibernate/ for explanation on why this occurs. Basically, unidirectional mapping OneToMany suffers from poor performance due to the order in which Hibernate writes out the entities. Switching to either unidirectional ManyToOne, or bidirectional OneToMany and ManyToOne could solve the issue using pure Hibernate, but they come with drawbacks. (To Do: More details on this.)
Updating data nodes
NOTE: I have removed the previous test results here, as the test analysis was flawed. Analysis is ongoing as per CPS-1674.
Performance tests to support new analysis are provisionally available at: https://gerrit.nordix.org/c/onap/cps/+/19086
Updating data leaves
In this scenario, 1,000 Open ROADM OpenROADM device nodes are already defined. The data leaves of a number of these existing data nodes will be updated using CpsDataService::updateNodeLeaves.
...
Deleting data nodes
In this scenario, 300 Open ROADM OpenROADM device nodes are already defined. A number of these data nodes will be deleted using CpsDataService::deleteDataNodes. The types of nodes will be varied, for example, deleting container nodes, list elements, or whole lists.
...
- Delete performance is linear on the amount of data being deleted (as expected).
- Raw performance of deleting container nodes is around 35,000 fragments per second. (So we can delete data nodes more than around 10x faster than creating them.)
- Deleting lists is much slower than deleting the parent container of the list (this can be improved).
- Of note, attempting to delete non-existing data nodes takes longer than actually deleting the equivalent amount of nodes with descendants - it is a slow operation.
...
Total device nodes | 500 | 1,000 | 1,500 | 2,000 | 2,500 | 3,000 |
---|---|---|---|---|---|---|
Fragments read | 43,000 | 86,000 | 129,000 | 172,000 | 215,000 | 258,000 |
Time (seconds) | 0.42 | 1.19 | 1.54 | 2.16 | 2.53 | 2.67 |
Fragments per second | 102,381 | 72,269 | 83,766 | 79,630 | 85,657 | 96,629 |
e
Graph of time taken to read top-level container node with all descendants
...