1 Background
Traditional RDBMS systems are notable for three things: locking: the ability to lock records so that no one else can change them.
Read consistency: You (and only you) can see your changes until you commit them, at which point others can see them.
Unfortunately, its poor scalability: online transaction processing (OLTP) workloads do not scale well. In reality, doubling the number of CPU cores won’t double your capacity.
This failure led many to try NoSQL solutions, but over time it became clear that locking and read consistency would be difficult to achieve without these solutions. VOLTDB is the only data platform that allows businesses to lock in and read consistency on a scale.
Here’s why it’s so hard to do — and how VOLTDB does it.
2 Why is scaling OLTP difficult?
To give you a sense of why extending OLTP is difficult, let’s look at the typical life cycle of a simple whiteboard transaction:
- Insert a row in table “A”
- Update rows in table ‘B’
- Update rows in table “C”
- Do external activities
- Update rows in table ‘A’
- crime
At first glance, it may be hard to see how this extends. But let’s look at an actual implementation using an older RDBMS:
In this picture, a few things become obvious:
1. The operation cannot be completed immediately
You need 12 network runs, each of which takes quite a bit of time. At any given time, the “real-world device” shuts down and does whatever needs to be done. In short: Even if everything works, this transaction will take milliseconds.
2. Long running data exchange will be a challenge for the database server
Each time you change the content in the database server, you need to do more work, because all other ongoing data exchanges need to see the “old” version of the table until it is committed. For practical purposes, each incomplete transaction requires its own version of the database, which consists of existing data and its uncommitted changes. This means that if you run a thousand transactions per second and each transaction takes 10 milliseconds end-to-end (that is, less than 1 millisecond per network trip), at least 100 different versions of the database will exist at any time, and any new transaction must be carefully checked to make sure it doesn’t conflict with someone else’s changes. Whether you use SELECT FOR UPDATE, MVCC, or any other mechanism, this overhead still exists.
3. The law of diminishing returns kicks in When you increase the number of CPU cores As the workload increases, the conventional solution is to add more CPU cores and spread the work among them. While this helps in the short term, it presents another problem: when you have only one CPU kernel, you can be sure that the other 100 live versions of the database won’t change when trying to handle session requests. And that’s exactly what we’re doing. However, after the second CPU kernel is added, the databases need to coordinate their activities. This introduces a whole new layer of overhead, and every time you add another CPU core to the help, the problem gets worse at a geometric rate. The end result is a vicious circle in which CPU cores are added to improve TPS, but each new kernel consumes all the other cores in association, ultimately consuming the CPU capacity you gain by adding additional cores. If the extra CPU capacity comes from another node in the cluster, things will go wrong. Because what the CPU cores were arguing with each other was now a network access to another database node.
4. Performance becomes more volatile as capacity increases Practical experience has taught us that even if you do everything at your best, you will still encounter locking problems in a real-world environment where actual data usage patterns can be very different from test scenarios. A typical example is the impatience of a web site visitor when adding a shopping cart or basket and pressing reload, which can result in an old request locking the record and a new request notifies the user that “someone else” has locked it. Internet of Things (IoT) and telecom applications are particularly vulnerable to this situation because the default behavior of many apis is to automatically retry when no immediate response is received. This can lead to the completely counterintuitive situation that reducing the number of requests will greatly increase the number of transactions that are successfully completed because there is less chance of the transaction getting in the way of the other party. What happens in real life is that any single transaction that prevents more other transactions from completing can lead to a spike in activity, especially when the application starts blindly retrying.
5. Application servers or microservers become weak links in systems Almost every database server on the market has some form of high availability, but application servers and microservers are often considered “stateless” because the database server is responsible for managing state. But what if all your customers are routed to a single component, and that component has about 100 outstanding transactions, then what if it crashes? The database server views the world from the perspective of connected sessions, some of which are locked. In a world where the session of a terminated component holds hundreds of row-level locks, you can expect the database server to comply with the lock for several minutes, until it finally becomes clear that the component is terminated and closes the sessions involved, releasing their locked state. This means that even if you have another application server or container ready to take over its finished workload immediately, otherwise it won’t be able to make any changes to any records that have been locked for a few minutes, which means that “valid” sets of data will freeze for a few minutes, during which time it won’t be able to make changes.
6. There is no obvious solution to this problem. The easiest way to try to extend OLTP is to switch to NoSQL storage, which requires clients to send proof that a particular version of the record has been read before making changes. This will give you faster performance until people start competing for data. The most common implementation is to send the hash value of the value back to the client along with the value itself. The hash is then sent over the network as a password to prove that the change is a legitimate change to the previous state. If the hash is wrong, it means that someone else changed the value at the same time, and you need to start over. This is an unsatisfactory solution because when multiple people start changing the same record at the same time, it leads to erratic performance under the same load as a traditional system. This also means that you may need to manipulate two or even three key-value pairs in the above situations. In effect, all you need to do is reduce the transaction complexity to the client layer. Obviously, you need another solution.
3 VOLTDB How does it do it?
VoltDB’s creators, including Turing prize winner Michael Stonebraker, have taken this particular issue into account in developing VoltDB’s data platform, and effectively tackled it. VoltDB’s data platform does three things differently:
1.IT partitions distribute workloads to each partition, which is the exclusive responsibility of the single physical thread that controls the CPU core. Yes, many modern data platforms divide workloads. However, we can simply align the partition with a single thread running on a single CPU kernel, which means that kernel doesn’t have to worry about what the other kernel is doing, so VoltDB immediately eliminates the geometric scalability issues mentioned above.
2. It allows any number of SQL statements and every TRIP logic to be associated with VOLTDB, and while you can happily use JDBC with VOLTDB, when you try to pass story names and the parameters you use to VOLTDB’s server-side logic, You can reduce the number of web visits and the number of intermediate states VoltDB has to track.
3. It shows that every access ends in a commit. This may seem drastic, but it has a significant impact on performance. The VoltDB partition processes only one transaction at any time, because it only has a single thread “owning” all the data in it. By insisting that all transactions are “committed” or “returned” states, VoltDB doesn’t have to keep track of any additional “copies” of the database storing states from the client’s point of view. So, in the above example, the VoltDB implementation doesn’t have to track 100 versions of the database, using only one active copy per partition.
Taken together, these changes give you the functionality of a traditional RDBMS with great scalability and approximately nine times the performance of the same hardware. Now, let’s see how that same deal plays out in VoltDB.
This can be done by calling VoltDB twice. The first call performs the first three changes and adds the session ID/expiration date to the other two soft-lock columns. This allows other interactions to view ongoing transactions and decide for themselves what to do. When the external task completes, the second call fires and clears the soft lock column.
Let’s compare the statistics for two methods: As you can see, VoltDB’s real business is done with fewer network trips, fewer client API calls, and a clear way to avoid losing application server nodes. But that doesn’t mean there aren’t other scenarios to consider. Let’s take a look at some oft-asked questions about how VoltDB locks and reads consistently.
4 Q & A
1. What if the database server fails? What we don’t show in the sequence diagram is that each time a partition receives a request, it immediately synchronously forwards that request to one or more “backup” partitions located on another physical server. All partitions will then start working on the same task at the same time. This means that if a node dies, viable and up-to-date copies of the partition will exist on other nodes in the cluster, and the database will be restarted with minimal loss of time and on-board transactions. 2. What if the application server fails? As long as the customer can find us using the correct lock identifier, our processing will continue as usual. In a traditional RDBMS, when it comes to locking, state will effectively remain on both the client and the server, because the server has marked the row with an identifier unique to the client session. However, if the client logs out, the session is invalid. This means that you need to wait for the server to mark the database connection as past state and terminate it before someone else can modify the record. In VoltDB’s system, we “design” most scenarios by allowing multiple SQL statements and associated logic to run on the server. If the logical transaction cannot complete before the associated transaction event completes, you can use simple SQL to lock the logic yourself to regain control of the situation and satisfy your SLAs. 3. Will VoltDB do this automatically? No, but it adds two more columns to the database table and about a dozen lines of code. This is entirely reasonable compared to the developer time required to process traditional RDBMS or NoSQL transactions and locking behavior.
4. Can we still use JDBC?
Yes, much of our application code is JDBC-based. In most applications, 20% of the developer’s time is spent writing 80% of the SQL that is friendly or straightforward. The other 20 per cent involve complex transactions, which is what makes them so valuable. 5. Why is “one thread per partition per kernel” faster than multi-threading and multi-kernel sharing workloads? At first glance, it might seem that any core that can handle any problem is the best choice. However, as we discussed above, as you add multiple kernels linearly, the effort required to coordinate the activities of multiple kernels escalates geometrically. Instead, force transactions onto virtual queues and make each queue run on a single thread. This process is much more efficient.
5 conclusion
Locking and read consistency are two important areas in today’s century, and neither RDBMS nor newer NoSQL systems can meet their needs to provide reasonable answers. At VoltDB, our mission is to focus on predictable, large-scale deals that meet stringent criteria. While we understand that some of our design decisions may seem unconventional, they are informed by years of practical experience. If you have other questions, or want to learn more about How VoltDB can support modern apps while keeping latency low, feel free to contact us!
About VoltDB VoltDB supports strong ACID and real-time intelligent decision making apps to enable connected worlds. No other database product like VoltDB can fuel an app that demands a combination of low latency, massive scale, high concurrency and accuracy at the same time. Founded by 2014 Turing Prize winner Dr Mike Stonebraker, VoltDB has redesigned relational databases to address today’s growing real-time manipulation and machine learning challenges. Dr. Stonebraker has been researching database technology for more than 40 years and has brought many innovations in fast data, streaming data and in-memory databases. During VoltDB’s development, he realized the full potential of using in-memory transaction database technology to mine streaming data, not only to meet the latency and concurrency requirements of processing data, but also to provide real-time analysis and decision-making. VoltDB is a trusted name in the industry and has worked with leading organisations such as Nokia, Financial Times, Mitsubishi Electric, HPE, Barclays and Huawei.
VoltDB China: www.voltdb-china.cn/