{{announcement.body}}
{{announcement.title}}

High-Performance Persistence With MicroStream (Part One)

DZone 's Guide to

High-Performance Persistence With MicroStream (Part One)

Read on!

· Performance Zone ·
Free Resource

High-performance yoga.

High-performance? Sign me up!


For some time, there has been a new competitor in the field of persistence and serialization. We are talking about Project MicroStream. What is it exactly? MicroStream claims to be a high-performance and, most importantly, developer-friendly solution for the challenges of serialization and persistence. How easy, fast and comfortable that is, we will look at in detail in a multi-part series.

You may also like: Understanding Batch, Microbatch, and Stream Processing

Preparations

As befits a proper tutorial, we start here with a HelloWorld. We start with an empty maven project. Ok, I have to admit, it's not that empty, because I disregard dependencies like jUnit5 and the like. To get access to the necessary binaries, we first need the coordinates of the Maven repository.

  <repositories>
    <repository>
      <id>microstream-releases</id>
      <url>https://repo.microstream.one/repository/maven-public/</url>
    </repository>
  </repositories>


From this repository, we now get the component with which we get a local embedded storage unit.

    <dependency>
      <groupId>one.microstream</groupId>
      <artifactId>storage.embedded</artifactId>
      <version>02.00.00-MS-GA</version>
    </dependency>


HelloWorld — Storing

The necessary elements are now available, and we can now begin to persist a HelloWorld. For this, I create a class named HelloWorld in which there is exactly one attribute of the typed string. That should not pose a particular challenge for MicroStream and let us take a look at the unconfigured behavior.

public class HelloWorld {
  private String value;
  public String getValue() {
    return value;
  }
  public void setValue(String value) {
    this.value = value;
  }
}


To try out the behavior, I formulate several usage examples as jUnit5 — tests. The starting point for the first attempt is the following jUnit tests.

public class HelloWorldTest {
  @Test
  void test001() {
    final HelloWorld value = new HelloWorld();
    value.setValue("HelloWorld");
    // do something with MicroStream
  }
}


MicroStream was built in such a way that you need a reference point. In the documentation, this is called StorageRoot. In the example here it is merely our class HelloWorld. The description lets one suspect that one transfers his object trees to the storage engine so that it then makes itself from top to bottom once. First of all, it is a tree with exactly one node, our HelloWorld. This example is our first attempt, subsequently implemented.

final HelloWorld value = new HelloWorld();
value.setValue("HelloWorld");
final EmbeddedStorageManager storageManager = EmbeddedStorage.start();
storageManager.setRoot(value);
storageManager.storeRoot();
storageManager.shutdown();


What exactly happens here?

- (Line 3) Start the storage engine.
- (Line4) Set the root node.
- (Line 5) The engine persists the tree.
- (Line 6) The entire engine shuts down and exits.

If you do that now, you will not see anything in the console at first. However, something in the directory of our project has changed a bit. A folder with the name storage was created. It contains files and another folder called channel_0. The assumption is evident that here our HelloWorld has nestled. The ensuing next step is, therefore, to bring this identity to life from our stored entity. To do this, we write another jUnit5 test to keep the writing and reading process separate at first.

HelloWorld — Reading

Since we did not set configuration parameters during the writing process, we will not set any configuration parameters to read the entity. The assumption is here once that it will behave symmetrically. In the beginning, a StorageEngine is started again and loaded with the method root() of the RootNode. The return value is of type Object. Unfortunately, we cannot specify the type with Generics. But maybe in one of the next versions, there will be a method with the signature root().

We can now check this instance using the instanceof operator for its relationship to our HelloWorld. If that went well, we'll risk a cast on type HelloWorld and then use the value for a comparison using the getValue() method. Of course, the last instruction to the StorageEngine is again a shutdown().

final EmbeddedStorageManager storageManager = EmbeddedStorage.start();
final Object                 root           = storageManager.root();
Assertions.assertTrue(root instanceof HelloWorld);
HelloWorld helloWorld = (HelloWorld) root;
Assertions.assertEquals("HelloWorld", helloWorld.getValue());
storageManager.shutdown();


If you do that now, you will be rewarded with a positive test result. So far, it seems to work already. Now I'm curious if that works well with Kotlin.

Immutable HelloWorld

Immutable data structures are enjoying increasing popularity in the Java world. That's why I want to test next if this can also be implemented without further ado. For this, our class HelloWorld now gets a player named HelloWorldImmutable. The difference with the first type is that there will still be a get method for the value, but a constructor parameter will replace the set method.

public class HelloWorldImmutable {
  private String value;
  public HelloWorldImmutable(String value) {
    this.value = value;
  }
  public String getValue() {
    return value;
  }
}


The corresponding jUnit5 tests will look like this.

final HelloWorldImmutable value = new HelloWorldImmutable("HelloWorldImmutable");
final EmbeddedStorageManager storageManager = EmbeddedStorage.start();
storageManager.setRoot(value);
storageManager.storeRoot();
storageManager.shutdown();


Please do not forget to delete the directory storage before running this test now. Everything seems to be going so well. After running this test method, there is again a directory named storage in the project directory. Also, the other items in this directory are included as was the case in the previous run. There is now nothing in the way to continue reading the currently stored entity of the type HelloWorldImmutable. Again, a jUnit5 test is used.

final EmbeddedStorageManager storageManager = EmbeddedStorage.start();
final Object                 root           = storageManager.root();
Assertions.assertTrue(root instanceof HelloWorldImmutable);
HelloWorldImmutable helloWorld = (HelloWorldImmutable) root;
Assertions.assertEquals("HelloWorldImmutable", helloWorld.getValue());
storageManager.shutdown();


Also, in this case, you will be rewarded with an unbeaten test run. In summary, one can say right up to this step that there are no special requirements for a classic Java bean to write and load. Admittedly, this has, of course, be a small case. After these first steps, the idea immediately comes to mind that a try with Kotlin can be worthwhile.

Kotlin — HelloWorld

The first step in our case is to map the class HelloWorld and the class HelloWorldImmutable using Kotlin. This results due to the language Kotlin different possibilities.

class HelloWorldKotlin { var value: String? = null }

class HelloWorldImmutableKotlin(val value: String)

data class HelloWorldKotlinDataclass(val value:String)


I do not want to go into detail about the differences here. Here it is only about whether writing and loading the entities also works without problems — the associated jUnit5 tests structured in the same way as the experiments with the Java classes. The result is green in all cases. It looks like nothing would block the usage of Kotlin.

Conclusion

We took a first look at MicroStream StorageEngine and saved a trivial entity. That worked with Java as well as Kotlin-Classes. Further experiments are now in the way. In the next few sections, we will look at how to deal with more complex object graphs and how to customize the properties of the StorageEngine to personal needs.

The source code for this article can found on GitHub at the URL below.  https://github.com/Java-Publications/microstream-2019-001.

Happy Coding!


Further Reading

Spark Streaming vs. Structured Streaming

Accelerate: Building and Scaling High-Performing Technology Organizations [Book Review]

Is a High-Performing Data Architecture Top of Your Digital Agenda?

Topics:
persistence ,high performance ,java ,kotlin ,serialization and deserialization ,microstream

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}