Application developers have historically had to balance the use of fast, volatile, byte-oriented system memory with slower but much larger and non-volatile disk storage. Persistent memory technologies such as Intel® Optane™ Persistent Memory (PMem) blur the line between storage and memory by being both byte addressable and persistent. It gives developers a third choice for data placement that offers both traditional DRAM and storage characteristics, but with capacities far larger than DRAM and at performance levels that are considerably higher than that of storage.
PMem-aware applications can achieve far greater performance than apps designed only to take advantage of traditional storage devices because with PMem, data does not have to transfer between the CPU and slower storage tiers. However, applications must be modified to utilize the persistence and performance features of PMem fully.
Developers can use the open source Persistent Memory Development Kit (PMDK), which is a collection of libraries and tools available for both Linux and Windows. The following five tips, taken from our book Programming Persistent Memory: A Comprehensive Guide for Developers, can help developers kick-start the process and more quickly gain the maximum benefit of persistent memory.
There are many benefits to using persistent memory, including low-latency, high-bandwidth access to data in application spaces such as content delivery networks, in-memory databases, and fraud detection.
Tip 1: Persistent memory is more than a replacement for storage or memory
For flexibility, persistent memory supports existing file and block I/O storage APIs. The temptation is understandable to simply replace storage with persistent memory, but that does not allow you to extract maximum value from the technology. Instead, think of PMem as a new tier between storage and memory, and place the data in each tier based on its access requirements.
We can use PMem for latency-sensitive persistent data while using storage for large capacity data and memory for latency-sensitive volatile data. For example, move a journal or a ‘write ahead’ log from traditional storage to the new tier.
Tip 2: Persistent memory programming includes certain responsibilities you cannot ignore
The application accesses persistent memory through memory-mapped files on file systems with direct access (DAX) support. However, the application has responsibilities over and above what traditional files require. For example, to ensure data durability, it is important to detect platform and CPU capabilities, such as whether the platform supports CPU cache flushing. When CPU caches are included in the powerfail protected domain, there is no need to carry out a flush followed by a write as writes are considered persistent. An application may continue to flush CPU caches if platforms do not support CPU cache flushing.
Tip 3: Using persistent memory libraries will save time and money
PMem programming isn’t always straightforward, especially when working with powerfail-safe transactions, ensuring data persistence , PMem allocations and handling PMem errors. The PMDK includes a range of libraries that solve such problems. Available in several Linux distributions, these production-quality libraries are tuned and optimized for Intel platforms and designed to shield application developers from the complexities and remove the need to implement code specific to each platform or device. The ‘shrink to fit’ libraries shorten readiness times and enable developers to pull in only what they need, including transaction APIs and PMem allocators.
As for time savings, the libraries in the PMDK offer an easy-to-use API without having to understand the intricacies of each CPU or different generations of persistent memory products. In short, the libraries assume the responsibilities for architecture and hardware-specific operations and allow you to use simple APIs to implement them.
Tip 4: A surprising number of persistent memory use cases boil down to a key-value store
A significant benefit of PMem versus a traditional key-value store is that it no longer needs to read full blocks from the storage device using block I/O operations.
PMemKV is a local/embedded key-value datastore optimized for persistent memory which provides different language bindings and storage engine options. Some of the storage engine options include sorted, unsorted, and concurrent engines that implement hash maps, red-black, B+, and Radix trees. Storage engines are easily extendable, or new engines can be created to suit the application requirements.
PMem key-value store accesses the keys and values directly without allocating buffers in volatile memory. Data can be modified in-place without read-modify-write operations that often suffer from write amplification, leading to premature device failure and lower performance.
Tip 5: Use PMem-aware Java libraries
Java developers can use persistent memory in several ways. Without making any code changes, JVM v10.x and later allows the Java Virtual Machine to allocate the Java object heap on an alternative memory device, such as persistent memory, specified by the runtime option, -XX:AllocateHeapAt=<path>. JVM 12.0.1 introduced a feature to allocate old generations of Java heap on an alternative memory device, such as persistent memory, specified by the -XX:AllocateOldGenAt=<path> runtime option. The feature in G1 and parallel GC allows them to allocate part of heap memory in persistent memory to be used exclusively for old generation objects. The rest of the heap is mapped to DRAM where young generation objects are always placed.
The Java binding for pmemkv supports Java types String, byte and ByteBuffer. Written in C and C++, pmemkv provides applications with the performance benefits of persistent memory and easy-to-use APIs.
The second method of programming PMem from Java is through the Low-Level Persistence Library (LLPL), an open source Java library that gives developers access to persistent memory in a fast and flexible way. By providing Java access to persistent memory at a memory-block level, LLPL provides a foundation for building custom abstractions or retrofitting existing code. The library offers management of heaps of persistent memory and manual allocation and deallocation of persistent memory blocks within a heap.
Over time, native persistent memory constructs are being added to the Java language. JDK v14 introduced Non-Volatile Mapped Byte Buffers, so the FileChannel API can be used to create MappedByteBuffer instances that refer to persistent memory. Foreign-Memory Access API allows Java programs to safely and efficiently access foreign memory outside of the Java heap, including persistent memory.
By following these five expert tips, you will be able to unlock the significant performance/persistence features of Intel Optane Persistent Memory. Explore the PMDK libraries and tools available at https://pmem.io/ and find more opportunities to optimize your code at the Intel Developer Zone.
Programming Persistent Memory further explores this revolutionary technology and how it is propelling innovation in the industry. The book covers the operating system and hardware requirements, explains fundamental concepts, introduces persistent memory programming APIs, discusses RDMA with persistent memory, reviews security features, and presents many examples.