<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="http://www.martinkysel.com/feed.xml" rel="self" type="application/atom+xml" /><link href="http://www.martinkysel.com/" rel="alternate" type="text/html" /><updated>2026-07-08T18:52:55+00:00</updated><id>http://www.martinkysel.com/feed.xml</id><title type="html">Martin Kysel</title><subtitle>Coding Challenges and More</subtitle><author><name>Martin Kysel</name></author><entry><title type="html">The Third Durable Surface</title><link href="http://www.martinkysel.com/the-third-durable-surface/" rel="alternate" type="text/html" title="The Third Durable Surface" /><published>2026-07-08T00:00:00+00:00</published><updated>2026-07-08T00:00:00+00:00</updated><id>http://www.martinkysel.com/the-third-durable-surface</id><content type="html" xml:base="http://www.martinkysel.com/the-third-durable-surface/"><![CDATA[<p>“Find me the best waffle maker under $100.” The agent starts working. It surfaces
a $75 model, weighs it against a $90 one with a better plate, and is composing its
recommendation when a deploy reschedules the container out from under it. The
runtime does what runtimes do: it redelivers the input and runs the turn again.
The agent comes back with no memory that it ever spoke. It either re-sends
everything it already said, or it reasons afresh and lands on a different answer.</p>

<p>The crash did not lose a paragraph. It gave the agent a personality disorder.</p>

<p>As I argued in <a href="https://www.martinkysel.com/the-missing-exactly-once-layer-under-ai-agents/">a previous post</a>,
a crash mid-turn is the normal operating condition for an agent that acts, not an
edge case. Vendors have answered by selling “durable” and “stateful” agent
runtimes. Most of them made the agent retryable. Almost none made it continuable.
The waffle-maker amnesia is the symptom that tells the two apart.</p>

<ul>
  <li><strong>Retryable</strong>: you can re-run the whole turn from the beginning and get a
correct result.</li>
  <li><strong>Continuable</strong>: you can resume the turn from where it died.</li>
</ul>

<p>The relationship is exact: continuable = retryable + durable intermediate state.
The only added ingredient is durability of the in-flight computation. Everything
below is about the price of that one ingredient.</p>

<h2 id="where-you-paid-for-durability">Where you paid for durability</h2>

<p>The usual way to frame this trade is latency versus correctness. That is the
wrong axis. The right one is <em>where in the computation you paid for durability</em>:
at the ends, or in the middle.</p>

<p><strong>Retryable needs durability only at the ends.</strong> Two things must survive a crash:
the input, and the effect. A durable input and an idempotent sink. Everything
between them can be as unreliable as you like. The container can lose all its RAM
and vanish, because a retryable turn is all-or-nothing: nothing in the middle was
ever externalised, so throwing the half-finished run away and restarting from the
durable input is not a compromise, it is correct. This is why you can bolt
retryability onto any disposable executor: put a queue in front, make the
consumer idempotent, treat workers as cattle. The cost is paid in latency and
pacing. You cannot stream a result you might have to retract, so you buffer
everything until the turn commits and release it at once.</p>

<p><strong>Continuable needs durability in the middle</strong>, a journal of in-flight progress
written before the crash, not after. You cannot throw the run away, because you
have already externalised part of it: a message the user has seen, the first half
of a recommendation. To resume instead of restart, you must have written down
what you did as you did it. There is no queue you can put in front to get this for
free. You change what the executor records while it runs.</p>

<h2 id="why-the-cheap-trick-does-not-work-on-an-llm">Why the cheap trick does not work on an LLM</h2>

<p>Durable execution is not new. Temporal, Restate, DBOS, and Cloudflare Workflows
all make the middle of a computation durable, and they do it with the same trick:
journaled replay. The workflow records the result of each step as it completes.
After a crash it re-runs the workflow code from the top, but every step that
already has a journal entry returns its recorded result instead of executing
again. Replay re-derives the program’s state cheaply, because the code between
steps is deterministic: given the same journal, it walks the same path.</p>

<p>An LLM is not deterministic. You cannot replay the prompt and trust it to
re-derive the same generation, and that non-determinism is the whole reason you
reached for a model in the first place. So the cheap half of the trick, replaying
the recorded steps and re-executing the deterministic glue between them, breaks the
moment the glue is a model call.</p>

<p>The fix is one the durable-execution world already knows: model each LLM call as
an <strong>activity</strong>. An activity is journaled once when it completes and never
re-executed on replay; its recorded output is authoritative. For a deterministic
workflow the journal is cheap, because most of the state can be re-derived and
only a handful of external results need storing. For an LLM you have no choice but
to store the actual generations, every token the model produced, because there
is no code path that re-derives them. The black-box, non-replayable executor is
precisely what makes continuability cost real durability instead of cheap replay.</p>

<p>And that journal, the record of every decision the model committed to during the
turn, is exactly the memory the amnesiac agent was missing. The waffle-maker bug
is not a separate failure. It is what ends-only durability looks like from the
user’s chair: the model’s accumulated decisions lived in container RAM, the
container went away, and there was nothing on disk to continue from, only the
input to redo.</p>

<h2 id="it-is-not-the-delivery-guarantee">It is not the delivery guarantee</h2>

<p>One objection worth heading off. Both models deliver effects the same way:
at-least-once delivery into an idempotent sink, which nets out to
effectively-once. The delivery guarantee is not what separates them.</p>

<p>The difference is <em>when</em> you are allowed to externalise an effect. Retryable
buffers every effect to the end of the turn and releases them together, so a crash
before the commit point erases a run that never touched the outside world.
Continuable externalises incrementally as the turn proceeds, which is what makes
streaming and mid-turn actions possible, and pays for that by journaling each
decision before it acts, so a crash leaves a record to resume from instead of a
void to re-guess.</p>

<h2 id="the-question-to-ask-any-substrate">The question to ask any substrate</h2>

<p>You do not shop for continuability as a checkbox on a framework’s feature page. It
is a property of the storage sitting under the loop, so the only useful thing to
do when you evaluate an agentic LLM substrate is ask one question: when the model
commits a decision in the middle of a turn, does that decision land on storage
that outlives the container before the next crash? Put it more bluntly. Is my disk
continuable?</p>

<p>That question is unkind, because a continuable disk is one of the least pleasant
things an ops team has to operate. The journal sits on the hot path of every turn:
each decision is written before it acts, so the write latency is added to every
step the agent takes. To be worth trusting it has to be genuinely durable, with
POSIX fsync semantics, where a write that reports success is actually on the
medium and not in a buffer the crash eats. You want it colocated with the compute,
ideally a local mount, so a journal write is not a network round-trip bolted onto
every decision. And it still has to survive the node it is colocated with going
away.</p>

<p>Fast, POSIX-durable, colocated, and crash-surviving, all at once: that is
nightmare territory. Network-attached block storage gives you durability and a
detach latency you feel on every write. Local NVMe gives you speed and dies with
the instance. A distributed POSIX filesystem gives you all of it and a pager that
never sleeps. Persistent disks are the bane of every ops team for exactly this
reason, and continuability puts one on the critical path of your agent loop.</p>

<p>So the real recommendation is not “make your agents continuable.” It is: decide
whether you are willing to run that storage. If you are not, you are choosing
retryable, and that is a legitimate choice with its own bill: buffer every effect
to the end of the turn, give up streaming and pacing, re-run from the input on
every crash. Neither option is free. Retryable pays in latency and pacing;
continuable pays in storage operations. You can have retryability on unreliable
execution. You cannot have continuability without durable execution.</p>

<h2 id="two-durable-surfaces-instead-of-three">Two durable surfaces instead of three</h2>

<p>When I first started building agents, I used a substrate that runs on unreliable disks. 
It throws RAM away on a whim and promises me nothing like a fast, colocated, crash-durable journal, which
is the one thing continuability cannot do without. So I did not get to choose
continuability. I built the retryable system on purpose, and spent the design
effort on making it need as few durable surfaces as possible: two, not three.</p>

<p>Here is the shape. During a turn the agent is not allowed to send anything. It can
only <em>propose</em> messages: accumulate the set of outbound messages it intends to
send. When the turn completes, that whole set is sealed into a Durable Sink in a
single transaction, and the same transaction advances the inbound message’s
lifecycle out of <code class="language-plaintext highlighter-rouge">processing</code>. From then on the Durable Sink owns delivery: it
sends each message, and it marks the inbound message <code class="language-plaintext highlighter-rouge">replied</code> only once every
outbound message is confirmed out.</p>

<p>Count the durable surfaces. The inbound message that arrived is one, the durable
input. The Durable Sink that holds the sealed set and drives delivery is the
other. The middle, every decision the model made during the
turn, is never written down. It lives on local disk and dies with the container, and that
is fine: a crash before the seal strands the inbound message in <code class="language-plaintext highlighter-rouge">processing</code>,
where a sweep picks it up and re-runs the turn from the input. Nothing was
externalised, so re-running is correct. That is the retryable bargain paid in
full: two durable surfaces, an unreliable middle, and a re-run whenever the middle
is lost.</p>

<p>A continuable version would add the third durable surface, the journal in the
middle, and with it the fast, colocated, crash-durable disk I do not have. I
traded that away for the retryable tradeoffs: no streaming, buffer to the seal,
re-run on crash. Let us see how it does in the real world.</p>]]></content><author><name>Martin Kysel</name></author><category term="distributed-systems" /><category term="ai-agents" /><category term="durable-execution" /><summary type="html"><![CDATA[A crash mid-turn brings the agent back with no memory that it ever spoke. That amnesia is not a bug. It is the symptom that tells retryable runtimes apart from continuable ones, and the difference is where you paid for durability.]]></summary></entry><entry><title type="html">The Missing Exactly-Once Layer Under AI Agents</title><link href="http://www.martinkysel.com/the-missing-exactly-once-layer-under-ai-agents/" rel="alternate" type="text/html" title="The Missing Exactly-Once Layer Under AI Agents" /><published>2026-06-22T00:00:00+00:00</published><updated>2026-06-22T00:00:00+00:00</updated><id>http://www.martinkysel.com/the-missing-exactly-once-layer-under-ai-agents</id><content type="html" xml:base="http://www.martinkysel.com/the-missing-exactly-once-layer-under-ai-agents/"><![CDATA[<p>Let us imagine an agent booking a flight. It calls the Amadeus API, the ticket
is reserved, and then — before the response comes back — the process crashes.
The runtime does what runtimes do: it restarts the turn and tries again. Now
there are two tickets.</p>

<p>For a chat assistant, a crash mid-turn is an annoyance. You lose a paragraph and
the user retypes their question. For an agent that takes actions in the world, a
crash mid-turn is the normal operating condition, not an edge case. The moment an
agent charges a card, sends money, or books a seat, “just run it again” stops
being free.</p>

<p>The mechanism that prevents the second ticket has a name: idempotency. An
idempotent operation can be applied many times and produce the same effect as
applying it once. The uncomfortable part is that, across the integrations agents
actually touch, most of this does not exist yet.</p>

<h2 id="why-retries-are-not-optional">Why retries are not optional</h2>

<p>Agent runtimes retry by design. A turn is a long chain of model calls and tool
calls, and any link can fail: the model times out, a tool returns a 503, the
container is rescheduled, the orchestrator redelivers a queue message it is not
sure was processed. Every one of these ends in the same place — the runtime runs
the turn again to make progress.</p>

<p>That is fine when the tool call is a read. Fetch the weather twice and you have
wasted a few milliseconds. It is not fine when the tool call has a side effect on
a third party you do not control. The runtime cannot see inside Stripe or Gmail.
It only knows that it sent a request and did not get an answer. It has no way, on
its own, to tell “the charge did not happen” apart from “the charge happened and
the acknowledgement was lost.”</p>

<p>This is the classic exactly-once problem, and distributed systems people will
recognise it immediately. What is new is where it has surfaced: not between two
services you own, but between an autonomous agent and an open-ended set of APIs
you did not write.</p>

<h2 id="the-matrix-nobody-wants-to-fill-in">The matrix nobody wants to fill in</h2>

<p>The shape of the problem is a grid. Down one axis, the integrations: Stripe,
Gmail, Amadeus, Twilio, your CRM, every API an agent can reach. Across the other,
the operations: charge, refund, send, book, cancel, post. Each cell — every
(integration, operation) pair — is a separate exactly-once problem, and each has
to be solved on its own terms.</p>

<p>For any given cell, three questions decide how hard it is:</p>

<ul>
  <li><strong>Does the partner give you an idempotency key?</strong> If you can attach a
client-generated key to the request and the partner promises to deduplicate on
it, the cell is close to solved.</li>
  <li><strong>Can you ask whether the action already happened?</strong> If not, you can query
after a failure and reconcile instead of guessing.</li>
  <li><strong>Does it need a human in the loop anyway?</strong> Some actions are high-stakes
enough that automatic retry is never acceptable.</li>
</ul>

<p>A few illustrative cells make the spread obvious.</p>

<p><strong>Stripe, charge.</strong> This is the good case. Stripe lets you pass an
<code class="language-plaintext highlighter-rouge">Idempotency-Key</code> header, holds the result of the first request against that key,
and replays it on retry. Send the same charge twice with the same key and you get
one charge and two identical responses. Solved — because someone at Stripe did the
work.</p>

<p><strong>Gmail, send.</strong> Harder. There is no first-class idempotency key for “send this
message.” You can lean on the <code class="language-plaintext highlighter-rouge">Message-Id</code> header and dedupe on the receiving
side, or check Sent before retrying, but now you are reconciling against state
that may not have settled yet. The cell is reachable, but you are building the
guarantee yourself.</p>

<p><strong>Amadeus, book.</strong> Harder still, and the one from the opening. Booking touches
inventory and money, the confirmation may arrive seconds after the reservation is
made, and a naive retry double-books. Here you are stitching together query-then-act
with whatever idempotency the API offers, and getting the failure modes wrong
costs a real ticket.</p>

<p>The grid is not small, and it grows every time a new API ships. Most cells are
unsolved.</p>

<h2 id="why-this-stays-unsolved">Why this stays unsolved</h2>

<p>The reason is not that any single cell is intellectually hard. It is that there
are thousands of them, and each one needs expert, per-API failure-mode analysis to
get right. What does this partner do on a duplicate? Does the idempotency key
expire? Is the “already exists” error safe to swallow, or does it sometimes mean
something else? This is careful, unglamorous work, and it does not generalise from
one integration to the next.</p>

<p>It is also work you cannot hand to the model. You cannot have an agent decide, at
runtime, whether sending $500 twice is safe. The whole point of the exactly-once
layer is to be the deterministic floor the probabilistic system stands on. A
guarantee that holds “usually” is not a guarantee.</p>

<p>So in practice teams pick one of three options, none of them satisfying:</p>

<ol>
  <li><strong>Accept duplicates.</strong> The default, because it requires building nothing. Fine
for idempotent-by-nature actions, quietly dangerous for anything financial.</li>
  <li><strong>Require human confirmation.</strong> Safe, and it kills the autonomy that made the
agent worth building.</li>
  <li><strong>Build the exactly-once infrastructure.</strong> Correct, expensive, and a one-time
cost paid per cell.</li>
</ol>

<h2 id="the-market-is-telling-on-itself">The market is telling on itself</h2>

<p>There is a tell worth noticing. Integration platforms have started marketing
idempotency as a feature — Composio, for instance, talks about it — well ahead of
shipping it as a real, per-cell guarantee in the API. When the marketing runs
ahead of the product, it usually means demand has arrived before the capability
has. That is exactly where this is: everyone building agents that act has hit this
wall, and the layer that would fix it has not been built.</p>

<p>Someone is going to build it properly — a per-integration, per-operation
exactly-once layer that an agent runtime can lean on the way it leans on Stripe’s
idempotency key today. Until then, the answer to “what happens if the agent
crashes mid-booking” is, for most cells, two tickets.</p>]]></content><author><name>Martin Kysel</name></author><category term="distributed-systems" /><category term="ai-agents" /><category term="idempotency" /><summary type="html"><![CDATA[The moment an agent charges a card, sends money, or books a seat, "just run it again" stops being free. The mechanism that prevents the duplicate has a name — idempotency — and across the integrations agents actually touch, most of it does not exist yet.]]></summary></entry><entry><title type="html">Mentoring Software Engineers While Living on the Road</title><link href="http://www.martinkysel.com/elevating-your-tech-journey/" rel="alternate" type="text/html" title="Mentoring Software Engineers While Living on the Road" /><published>2023-08-15T00:00:00+00:00</published><updated>2023-08-15T00:00:00+00:00</updated><id>http://www.martinkysel.com/elevating-your-tech-journey</id><content type="html" xml:base="http://www.martinkysel.com/elevating-your-tech-journey/"><![CDATA[<p>I’m a software engineer and a digital nomad.
I write code from wherever I happen to be, and I mentor other engineers who want to do the same.
This post is about what that mentorship actually looks like.</p>

<h2 id="what-i-can-help-with">What I can help with</h2>
<p>I’ve kept a real engineering job while moving between time zones and bad WiFi, so I know where this breaks down.
Mentoring sessions usually cover one of a few things:</p>

<ul>
  <li><strong>Staying productive while moving.</strong> Time zones, unreliable connectivity, and the discipline of shipping when your day job is in another country. The hard part isn’t the travel; it’s keeping output steady when nothing about your setup is.</li>
  <li><strong>The engineering work itself.</strong> Algorithm and system design, working through a problem you’re stuck on, or a code review of something real you’re building.</li>
  <li><strong>Career questions.</strong> What to learn next, how to read the job market, whether the role you’re in is the one you should stay in.</li>
</ul>

<p>I don’t do generic pep talks. Bring a concrete problem and we’ll work on it.</p>

<h2 id="why-take-advice-from-me">Why take advice from me</h2>
<p>I do this for real, not in theory.
Over three years and ~60,000 miles we drove the entire Pan-American Highway, from Ushuaia at the bottom of Argentina to Tuktoyaktuk on the Arctic coast of Canada — the whole length of two continents.
The whole time I was the maintainer of <a href="https://securedna.org/">SecureDNA</a>.
So when I say you can hold a serious engineering job from a truck with bad WiFi, I’ve done exactly that.
You can follow the travel side at <a href="https://eltruckito.com">ElTruckito.com</a>.</p>

<h2 id="booking-a-session">Booking a session</h2>
<p>If any of this is useful to you, book a session with me on <a href="https://adplist.org/mentors/martin-kysel">ADPList.org</a>.
Tell me what you’re working on beforehand so we don’t spend the call figuring out what to talk about.</p>]]></content><author><name>Martin Kysel</name></author><category term="digital nomad" /><category term="mentorship" /><summary type="html"><![CDATA[I'm a software engineer and a digital nomad. I write code from wherever I happen to be, and I mentor other engineers who want to do the same. This post is about what that mentorship actually looks like.]]></summary></entry><entry><title type="html">From Ugly to Beautiful: The Transformation of Martinkysel.com</title><link href="http://www.martinkysel.com/from-ugly-to-beautiful/" rel="alternate" type="text/html" title="From Ugly to Beautiful: The Transformation of Martinkysel.com" /><published>2023-02-25T00:00:00+00:00</published><updated>2023-02-25T00:00:00+00:00</updated><id>http://www.martinkysel.com/from-ugly-to-beautiful</id><content type="html" xml:base="http://www.martinkysel.com/from-ugly-to-beautiful/"><![CDATA[<p>Migrating a website from one platform to another can be a daunting task, but with the right tools and techniques, it doesn’t have to be a nightmare. In my case, I recently migrated my blog from WordPress to Jekyll, and I’m happy to report that the process was relatively smooth and painless.</p>

<h2 id="the-initial-problem-hosting-on-a-basement-server">The Initial Problem: Hosting on a Basement Server</h2>

<p>When I first started my blog on WordPress, I had a rather unusual setup - the site was hosted on a server in a friend’s basement. While it may sound like a bit of a “ghetto” arrangement, it seemed like a cost-effective solution at the time. However, it soon became apparent that this setup came with its fair share of problems.</p>

<p>One of the biggest issues was the server’s reliability. For reasons that were never quite clear, the server seemed to go down regularly, without any good explanation. This meant that my site was often inaccessible for hours or even days at a time, frustrating both myself and my readers.</p>

<p>To make matters worse, the site’s loading times were notoriously slow. This was likely due in part to the server’s less-than-optimal location and setup, but it also meant that visitors to my site had to endure lengthy wait times just to access my content. And as we all know, in the world of online content, every second counts.</p>

<p>As my blog began to grow and attract more readers, the maintenance of the site became an increasingly daunting task. With the server regularly going down and loading times being so slow, I found myself spending more and more time just trying to keep the site running smoothly. This detracted from the time and energy I wanted to devote to creating new content and engaging with my readers.</p>

<p>Eventually, in 2020, I began to investigate the possibility of moving my site to a proper hosting solution, such as AWS. However, as I quickly discovered, this option came with a hefty price tag. The cost of a properly hosted server, combined with the need for a distributed database, made this option simply unfeasible for me at the time.</p>

<p>It’s not just about hosting, maintaining WordPress can be a headache. While it’s an amazing system, opting for a static website can offer several advantages. It’s faster, easier to maintain, and more secure, making it a smart choice for those who value efficiency and security.</p>

<p>In the end, I realized that something had to be done to address the ongoing issues with my site’s performance and reliability. After careful consideration and research, I made the decision to migrate my site to Jekyll, a static site generator that promised faster load times and a more streamlined maintenance process. And while the process of migrating my site was not without its challenges, I can now say that I am thrilled with the improved performance and ease of use that Jekyll has brought to my blog.</p>

<p>I chose GitHub Pages as my hosting solution, as I regularly use Git and GitHub in my daily work, and the added bonus of open-sourcing the content was a nice benefit for the community.</p>

<h2 id="the-long-and-winding-road-of-migrating-to-markdown---according-to-the-internet">The Long and Winding Road of Migrating to Markdown - According to the Internet</h2>

<p>When I stumbled upon Swizec’s <a href="https://swizec.com/blog/how-to-export-a-large-wordpress-site-to-markdown/">article</a> on migrating from WordPress to Markdown, I was initially excited. His straightforward breakdown of the process made it seem like a simple task that could be completed in an afternoon. “Pfft, an afternoon of work at worst,” he wrote, listing off the steps like they were nothing: export from WordPress, find a script, sip margaritas.</p>

<p>It all sounded so easy and straightforward, and I couldn’t help but agree with Swizec’s assessment. “That sounds about right,” I thought to myself, feeling confident that I could tackle this migration with ease.</p>

<p>But then, Swizec hit me with a dose of reality. “Suddenly it’s 6 months later and you’re losing your mind,” he wrote. His words were a stark reminder that even the simplest tasks can often become complex and time-consuming.</p>

<p>As an optimist, however, I refused to be discouraged. Sure, the process might not be as straightforward as I initially thought, but surely it couldn’t be that difficult, right?</p>

<p>So, being the lazy optimist that I am, I decided to explore my options. I turned to Fiverr, hoping to find someone who could handle the migration for me. I was shocked to discover that most of the quotes I received ranged from $1500 to $8000. That seemed like an exorbitant amount of money for something that sounded like it should only take a few hours.</p>

<p>One freelancer even warned me that it could take 2-3 months to complete the migration, although he optimistically suggested that it might only take a month.</p>

<p>The whole experience left me feeling a bit frustrated and overwhelmed. But despite the initial setbacks, I remained determined to find a solution that would allow me to migrate my site without breaking the bank or losing my mind in the process. And while it might take a bit more time and effort than I initially anticipated, I’m confident that I’ll be able to find a way to make it work.</p>

<h2 id="what-made-this-blog-different">What Made This Blog Different</h2>

<p>Perhaps I was a bit fortunate that I had recently teamed up with <a href="https://github.com/spello2287">Juraj</a> to create a brand new website for <a href="https://nomadicworkplace.com/">Nomadic Workplace</a>, my umbrella company that enables me to pursue my digital nomad lifestyle while remaining legally employed in the US.</p>

<p>When it comes to martinkysel.com, I can confidently say that it boasts two significant advantages over other blogs out there. Firstly, the vast majority of its content follows a similar pattern and covers similar topics. This consistency makes it easier to script a migration without having to deal with a lot of edge cases.</p>

<p>Secondly, all of the comments on the blog are saved in Disqus. This means that they can be easily transferred and integrated into a new platform, without the risk of losing valuable feedback and engagement from readers.</p>

<p>Finally, let’s be honest - the old blog design was pretty unappealing. So, any improvement in this area would be a massive gain for both myself and my readers. With the new Jekyll-based site, I was able to create a much cleaner, more streamlined design that not only looks better but also makes it easier for readers to navigate and engage with the content.</p>

<h2 id="the-steps-of-the-actual-migration-process">The Steps of the Actual Migration Process</h2>

<p>So, how did the whole migration process actually go? Well, to start with, I discovered a migration tool developed by Lonekorean over on <a href="https://github.com/lonekorean/wordpress-export-to-markdown">Github</a>, which was almost perfect for my needs. However, there were a couple of essential components that it was missing.</p>

<p>Firstly, it didn’t have the ability to deal with <code class="language-plaintext highlighter-rouge">[code]</code> blocks, which seemed to be a non-standard feature of my old Wordpress site. This was a bit of a headache, but as is often the case with internet problems, I was able to find someone who had already struggled with and solved the issue in the past. In this case, it was a user called mxro, who had written some incredibly simple <a href="https://github.com/lonekorean/wordpress-export-to-markdown/issues/86#issuecomment-1304870098">Typescript</a> code to handle the preprocessing.</p>

<p>The second issue I encountered was with images. Thankfully, there were only a few scattered throughout the entire blog, so I was able to handle them all manually. While this was a bit time-consuming, it ultimately wasn’t a huge deal in the grand scheme of things.</p>

<p>Of course, the migration process wasn’t just about transferring content from one platform to another. I also had to select a new theme for the site, add some new icons, turn the banner into an avatar, and reset DNS entries. While these tasks weren’t necessarily difficult, they did require some careful attention to detail in order to ensure that everything was working smoothly and looking great.</p>

<h2 id="a-surprisingly-short-migration-process">A Surprisingly Short Migration Process</h2>

<p>The entire process took only <em>four hours</em> - no joke. I started around 8PM and got so absorbed in it that I barely noticed the time passing. I remember making a fresh batch of argentinean mate while working away. By around 11PM, I decided the website was good enough and made the move to switch the DNS entries over to the new website. Of course, there may be some kinks to iron out over the next few days as I discover any issues that may have gone wrong or missing, but overall, it was nowhere near the month or six months I was anticipating.
And if you don’t believe me, you can check the git history.
The blog’s source is open on <a href="https://github.com/mkysel/mkysel.github.io">GitHub Pages</a>.</p>

<h2 id="lessons-learned-be-skeptical">Lessons Learned: Be Skeptical</h2>

<p>Reflecting on this experience, I have come to realize that there are a few key takeaways that I believe are worth sharing with others.</p>

<p>Firstly, when it comes to using standard tools, the integration with existing systems can be seamless. In my case, because I was using widely accepted tools for the migration process, such as WordPress and Markdown, the transition was relatively smooth. However, the process could have been complicated if I had relied on more obscure or specialized tools.</p>

<p>Secondly, keep it simple stupid. Pick a system that requires the least maintenance.</p>

<p>Thirdly, it is important to approach time estimates with a healthy dose of skepticism. I was initially quoted a range of 1-3 months for the migration process by one service provider, which turned out to be completely off-base. It is essential to use common sense and T-shirt sizing estimates.</p>

<p>Lastly, be wary if your customer is another software engineer. Trying to “bullshit” your way through a negotiation will only lead to frustration and disappointment for both parties. Other engineers are highly skilled professionals who understand the complexities of building and maintaining software systems. They know what is feasible and what is not, and inaccurate estimates should alarm them to sketchy behavior.</p>]]></content><author><name>Martin Kysel</name></author><category term="migration" /><summary type="html"><![CDATA[Migrating a website from one platform to another can be a daunting task, but with the right tools and techniques, it doesn't have to be a nightmare. In my case, I recently migrated my blog from WordPress to Jekyll, and I'm happy to report that the process was relatively smooth and painless.]]></summary></entry><entry><title type="html">Migration of MartinKysel.com to Jekyll</title><link href="http://www.martinkysel.com/martinkysel-migration/" rel="alternate" type="text/html" title="Migration of MartinKysel.com to Jekyll" /><published>2023-02-24T00:00:00+00:00</published><updated>2023-02-24T00:00:00+00:00</updated><id>http://www.martinkysel.com/martinkysel-migration</id><content type="html" xml:base="http://www.martinkysel.com/martinkysel-migration/"><![CDATA[<p>I am happy to announce that the page has been migrated from <code class="language-plaintext highlighter-rouge">Wordpress</code> to <code class="language-plaintext highlighter-rouge">Jekyll</code> and <code class="language-plaintext highlighter-rouge">Github pages</code>.</p>

<h2 id="the-benefits-of-jekyll">The Benefits of Jekyll</h2>

<p>There are several benefits to this migration:
1) Faster load times:
Jekyll generates static pages, which means that there is no need to query a database or run server-side scripts to serve up content.
This has resulted in much faster page load times and a better user experience for you, the readers.
2) Improved security:
As Jekyll doesn’t require a database or server-side scripting, there is less potential for security vulnerabilities, which makes my life much easier.
3) Simpler design:
Jekyll is based on templates, which has hopefully resulted in a more consistent and visually appealing design.
This should make it easier for readers to navigate the site and find the information they are looking for.
4) Easier updates: 
Jekyll makes it easier to update the content on a website since it separates content from presentation.</p>

<p>Overall, the migration to Jekyll has resulted in a faster, more secure, and more user-friendly website, which should improve the overall experience for readers of martinkysel.com.</p>

<h2 id="no-more-ads">No More Ads!</h2>

<p>I hope that the decision to remove ads from this blog will be a positive move for everyone involved.
For readers, the absence of ads can result in a more enjoyable reading experience, free from distractions and slow loading times caused by ad content.
Maybe this improved experience can encourage readers to spend more time on the site, engaging with content and potentially sharing it with others.</p>

<p>If you still wanna buy me a coffee, you can click the sponsorship button on GitHub!</p>

<p>The ads sucked anyway…</p>

<h2 id="simplified-looks">Simplified Looks</h2>

<p>Simpler pages are typically easier to navigate because they present information in a clear and concise manner, with fewer distractions or unnecessary elements.
When a page is cluttered or overly complex, users may struggle to find the information they are looking for, leading to frustration and potentially causing them to leave the site.
The WordPress site was an old mess of fully of crappy elements from 2015.</p>

<p>By contrast, simpler pages tend to have a clear visual hierarchy that makes it easier for users to scan and locate the information they need.
This was achieved through the use of white space, consistent typography, and clear navigation menus that now guide users to the most important content.</p>

<p>And man, this page really needed to be simplified!</p>

<h2 id="ability-to-file-issues">Ability to File Issues</h2>

<p>If you see a bug in any of the pages, just head over to <a href="https://github.com/mkysel/mkysel.github.io">Github</a> and file an issue.
I am happy to incorporate any and all feedback.</p>

<h2 id="breakage">Breakage</h2>

<p>If anything broke, please let me know! Either in the Disqus system or on GitHub.</p>

<h2 id="where-to-learn-more">Where to Learn More?</h2>

<p>You can read more about the migration in my post <a href="https://martinkysel.com/from-ugly-to-beautiful">From Ugly to Beautiful: The Transformation of Martinkysel.com</a>.</p>]]></content><author><name>Martin Kysel</name></author><category term="migration" /><summary type="html"><![CDATA[I am happy to announce that the page has been migrated from Wordpress to Jekyll and Github pages. Read more about the various improvements done...]]></summary></entry><entry><title type="html">Why and When You Need Transactional DDL in Your Database</title><link href="http://www.martinkysel.com/why-and-when-you-need-transactional-ddl-in-your-database/" rel="alternate" type="text/html" title="Why and When You Need Transactional DDL in Your Database" /><published>2020-04-06T00:00:00+00:00</published><updated>2020-04-06T00:00:00+00:00</updated><id>http://www.martinkysel.com/why-and-when-you-need-transactional-ddl-in-your-database</id><content type="html" xml:base="http://www.martinkysel.com/why-and-when-you-need-transactional-ddl-in-your-database/"><![CDATA[<p>We typically talk about transactions in the context of Data Manipulation Language (DML), but the same principles apply when we talk about Data Definition Language (DDL). As databases increasingly include transactional DDL, we should stop and think about the history of transactional DDL. Transactional DDL can help with application availability by allowing you perform multiple modifications in a single operation, making software upgrades simpler. You’re less likely to find yourself dealing with a partially upgraded system that requires your database administrator (DBA) to go in and fix everything by hand, losing hours of their time and slowing your software delivery down.</p>

<h2 id="why-do-you-care">WHY DO YOU CARE?</h2>

<p>If you make a change to application code and something doesn’t work, you don’t want to have to deal with a complicated recovery. You want the database to be able to roll it back automatically so you get back to a working state very rapidly. Today, very often people don’t write code for databases, they have frameworks that do it (Hibernate, for example). This makes it impossible for a software engineer to write the code properly, or roll it back, because they don’t work on that level. When you make changes using rolling application upgrades, it is simpler, less likely to fail, and more obvious what to do when you do experience a failure.</p>

<p>With transactional DDL, it’s far less likely that you will have to deal with a partially upgraded system that has essentially ground your application to a stop. Partial upgrades like that may require your database administrator (DBA) to go in and fix everything by hand, losing hours of their time and slowing your software delivery down. With transactional DDL, you can roll back to the last working upgrade and resolve the issues rapidly, without taking your software delivery system or your application offline.</p>

<h2 id="a-short-explanation-of-dml-and-ddl">A SHORT EXPLANATION OF DML AND DDL</h2>

<p>Essentially, DML statements are structured query language (SQL) statements that we use to manipulate data — as you might have guessed. Specifically, the DML class includes the INSERT, UPDATE, and DELETE SQL statements. Sometimes, we refer to these three statements as WRITE DML, and we call the SELECT statement READ DML. The standard does not differentiate between read and write, but for this article, it is an important distinction.</p>

<p>On the other hand, DDL is a family of SQL language elements used to define the database structure, particularly database schemas. The CREATE, ALTER, and DROP commands are common examples of DDL SQL statements, but DDL language elements may include operations with databases, tables, columns, indexes, views, stored procedures, and constraints.</p>

<p>Next, let’s start by defining a transaction as a sequence of commands collected together into a single logical unit, and a transaction is then executed as a single step. With this definition, if the execution of a transaction is interrupted, the transaction isn’t executed. Because a transaction must be ACID — Atomic, Consistent, Isolated, and Durable, that means that when a transaction executes several statements, some of which are DDL, it treats them as a single operation that can either be rolled back or committed. This means that you will never leave the database in a temporary, non-consistent state. Historically, databases haven’t provided the functionality of transactional DDL statements, but even today not all databases provide the functionality of truly transactional DDL. In most cases, this functionality comes with limitations.</p>

<p>Now, what does true “transactional DDL” mean? It means that all statements should be ACID, regardless of whether they are DML or DDL statements. In practice, with most databases, DDL statements break the transactionality of the enclosing transaction and cause anomalies.</p>

<h2 id="a-brief-history-of-ddl">A BRIEF HISTORY OF DDL</h2>

<p>Originally, the idea of a data definition language was introduced as part of the Codasyl database model. CODASYL is the Conference/Committee on Data Systems Languages, and was formed as a consortium in 1959 to guide development of a standard programming language, which resulted in COBOL, as well as a number of technical standards. CODASYL also worked to standardize database interfaces, all part of a goal from its members to promote more effective data systems analysis, design, and implementation.</p>

<p>In 1969 CODASYL’s Data Base Task Group (DBTG) published its first language specifications for their data model: a data definition language for defining the database schema, another DDL to define application views of the database, and (you guessed it) a data manipulation language that defined verbs to request and update data in the database. Later DDL was used to refer to a subset of SQL to declare tables, columns, data types, and constraints, and SQL-92 introduced a schema manipulation language and schema information tables to query schemas. In SQL:2003 these information tables were specified as SQL/Schemata.</p>

<p>Transactionality of DDL, however, is not part of the ANSI SQL standard. Section 17.1 of <a href="https://webstore.ansi.org/Standards/ISO/ISOIEC90752016-1646101?source=blog">ANSI SQL 2016</a> () only specifies the grammar and the supported isolation levels. It does not specify how a transaction should behave or what ‘transactional’ means.</p>

<h2 id="why-isnt-transactional-ddl-universally-provided">WHY ISN’T TRANSACTIONAL DDL UNIVERSALLY PROVIDED?</h2>

<p>There’s no reason why DDL statements shouldn’t be transactional, but in the past, databases haven’t provided this functionality. In part that’s because transactional DDL implies that DDL must happen in isolation from other transactions that happen concurrently. That means that the metadata of the modified table must be versioned. To correctly process metadata changes, we need to be able to roll back DDL changes that were aborted due to a transaction rollback. That’s not easy — in fact it’s a complex algorithmic task that requires the database to support metadata delta (diff), which corresponds to DDL changes within the current transaction of each connection to the database. This delta exists before the transaction is closed, and so it could be rolled back as a single transaction, or in parts in RDBMSs that support multi-level transactions or savepoints. Essentially, it’s not universally provided because it’s hard to do correctly.</p>

<blockquote>
  <p>For organizations moving to microservices, DevOps, and CI/CD, they have an essential new requirement — a database that supports online transactional DDL.</p>
</blockquote>

<p>Let’s return to our concept of WRITE DML (update, delete, insert) vs. READ DML. You might ask yourself how do these statements collide in a system that supports multiple concurrent transactions and a DDL transaction is ongoing? Ideally the set of transactions that collide is as small as possible. A SELECT statement does not collide with an INSERT statement. There is no reason why this should be any different in the context of DDL. A DDL statement ALTER TABLE should not prevent a SELECT statement from executing concurrently. This is a common pattern in database design.</p>

<p>For DDL to be transactional you need to support multiple versions concurrently. Similar to multiversion concurrency control (MVCC), readers don’t block writers and writers don’t block readers. Without MVCC it’s hard to have transactional DDL. Traditionally, databases started with a locking system instead of MVCC. That implementation wasn’t suited to transactional DDL, which is why around 2005 there was a big shift towards MVCC — to provide concurrent access to the database, and to implement transactional memory in programming languages.</p>

<p>MVCC provides the semantics we might naturally desire. Read DML can proceed while conflicting writes (write DML and DDL) are executed concurrently.</p>

<h2 id="write-dml-and-ddl-in-a-live-system">WRITE DML AND DDL IN A LIVE SYSTEM</h2>

<p>We have established that Read DML (SELECT) can happily proceed regardless of what else is executing concurrently in the system. Write DML (INSERT, UPDATE, DELETE) is not allowed to execute on a table that is being concurrently modified by DDL. Explaining the semantics of the conflicts expected behavior based on the Isolation Levels of all concurrent transactions is beyond the scope of this article.</p>

<p>To simplify the discussion, we state that both write DML and DDL are mutually exclusive if executed on the same resource. This results in operations blocking each other.  If you have a long-running DDL transaction, such as a rolling upgrade of your application, write DML will be prevented for a long period of time.</p>

<p>So even though the DDL is transactional, it can still lead to database downtime and maintenance windows. Or does it?</p>

<h2 id="always-online-always-available">ALWAYS ONLINE, ALWAYS AVAILABLE</h2>

<p>The database industry is moving towards an always online, always available model. Earlier databases resulted in a message saying that something wasn’t available — that was essentially because you grabbed a lock in a database for a long period of time. That isn’t an option in an always online, always available model.</p>

<p>Customers, and therefore organizations, require applications to be online and available all the time. That means that transactional DDL is mandatory for the new world, and not only for the applications to run the way customers require them to. It’s also mandatory for organizations adopting DevOps and continuous integration and continuous delivery models (CI/CD). Specifically, that’s because without transactional DDL, applications developers cannot safely and easily make database schema changes (along with their app changes) online. That means that for organizations moving to microservices, DevOps, and CI/CD, they have an essential new requirement — a database that supports online transactional DDL.</p>

<p>I personally consider the term ONLINE misleading. The database is not offline while it holds a lock on a resource. A more appropriate term would have been LOCK FREE DDL. That is, metadata modification can happen without locking out concurrent DML.</p>

<h2 id="the-availability-vs-simplicity-tradeoff">THE AVAILABILITY VS. SIMPLICITY TRADEOFF</h2>

<p>We said that write DML cannot happen concurrently with DDL to avoid ACID violations. Now, what happens to a system that has to be always up and needs to execute long-running DDL statements? Luckily enough, most DDL statements do not take a long time. Adding or removing columns from a table takes a constant amount of time, regardless of how long the table is. If the set of changes is small enough, it is OK to lock DML out for a short period of time.</p>

<p>But there are some DDL statements that need to process every row in the table and hence it can take a long time to process large tables. CREATE INDEX is a prime example of a long-running statement. Given that index creation can take multiple hours, it is not an acceptable option for an always online, always available application.</p>

<p>Specifically, for index creation, NuoDB and other databases implement an ONLINE or CONCURRENT version (I would have preferred to call it a LOCK FREE version). This version allows DBAs to create indexes without locking the table or requiring a maintenance window — an extremely important capability in a 24×7 availability world. However, these capabilities do not come for free. Online versions of common DDL statements tend to be slightly slower than their LOCKING versions, have complicated failure modes, and hard to understand ACID semantics. They also cannot be part of a larger multistatement DDL transaction.</p>

<p>Interestingly enough, sometimes the speed of execution is not the primary concern. In which case you may not want to use the online version. You might have an application that requires complex changes to a database schema and some LOCKING is a viable tradeoff for a much simpler upgrade procedure.</p>

<p>Atomicity, one of the four guarantees of ACID, states that: <em>“Each transaction is treated as a single ‘unit,’ which either succeeds completely or fails completely.”</em></p>

<p>This becomes a very desirable quality if we think of transactions as a set of many DDL statements. An example would be: alter a table; create a log table with a similar name; insert a few rows to other tables. We already know that if DDL is not treated transactionally, you could end up with new rows in the other tables, but neither the CREATE nor the ALTER succeeded. Or you could end up with just the CREATE and no ALTER.</p>

<p>So, if you have an application that assumes that if there is a log table (the CREATE) it can also assume that the ALTER has happened, you might run into subtle bugs in production if the upgrade did not fully complete. Transactional DDL gives database administrators the ability to perform multiple modifications (such as the example above) in a single operation.</p>

<p>For developers, the strong Isolation guarantees of transactional DDL makes the development of applications easier. An application can only observe the database in state A (before the upgrade) or in-state B (after the upgrade) and will never see partial results. This reduces the required test matrix and increases confidence in the rolling upgrade procedure. Now that is easy to code against.</p>

<p>The tradeoff between simplicity of rolling upgrades that is LOCKING and the always available, always online that is NOT TRANSACTIONAL has been known to the industry since InterBase introduced MVCC to the commercial market.</p>

<h2 id="choose-transactional-ddl">CHOOSE TRANSACTIONAL DDL</h2>

<p>Databases have changed a lot since 1959, and there have been many changes in customer expectations for user experience and application availability since then. Transactional DDL helps you avoid a scenario in which your application is no longer available, and gives your DBAs some peace of mind, knowing they won’t have to painstakingly repair the database to bring your software delivery back up to speed. Today, many databases offer transactional DDL, which will help you resolve immediate issues quickly by rolling back to the last working upgrade. In order to meet the always available requirements of today, choose a database that offers transactional DDL. But keep in mind that modern always-available, always-online applications require a database that not only simplifies upgrade scenarios, but also limits downtime due to long-running metadata modifications.</p>

<p><em><a href="https://thenewstack.io/why-and-when-you-need-transactional-ddl-in-your-database/">This article was originally published in The New Stack.</a></em></p>]]></content><author><name>Martin Kysel</name></author><category term="nuodb" /><summary type="html"><![CDATA[We typically talk about transactions in the context of Data Manipulation Language (DML), but the same principles apply when we talk about Data Definition Language (DDL). As databases increasingly include transactional DDL, we should stop and think about the history of transactional DDL. Transactional DDL can help with application availability by allowing you perform multiple modifications in a single operation, making software upgrades simpler. You’re less likely to find yourself dealing with a partially upgraded system that requires your database administrator (DBA) to go in and fix everything by hand, losing hours of their time and slowing your software delivery down.]]></summary></entry><entry><title type="html">Top 10 FAQs from KubeCon 2019 in San Diego</title><link href="http://www.martinkysel.com/top-10-faqs-from-kubecon-2019-in-san-diego/" rel="alternate" type="text/html" title="Top 10 FAQs from KubeCon 2019 in San Diego" /><published>2020-03-30T00:00:00+00:00</published><updated>2020-03-30T00:00:00+00:00</updated><id>http://www.martinkysel.com/top-10-faqs-from-kubecon-2019-in-san-diego</id><content type="html" xml:base="http://www.martinkysel.com/top-10-faqs-from-kubecon-2019-in-san-diego/"><![CDATA[<h2 id="what-does-nuodb-do">WHAT DOES NUODB DO?</h2>

<p>TL;DR: NuoDB is a <a href="https://www.nuodb.com/digging-distributed-sql">distributed SQL database</a>.</p>

<p>NuoDB is a SQL database, it is fully transactional, fully ACID, and fully consistent. This is a stark contrast to NoSQL solutions that have emerged in the last decade.</p>

<p>NuoDB is distributed, meaning that it is able to scale horizontally and automatically keeps multiple replicas in sync. Having multiple replicas of a database is a strict requirement for any service having 99.99% or better availability guarantees.</p>

<h2 id="do-you-run-in-the-cloud">DO YOU RUN IN THE CLOUD?</h2>

<p>NuoDB runs on all public clouds (AWS, Azure, GCP, etc.), on private clouds, and on-prem. We run in <a href="https://www.nuodb.com/techblog/nuodb-golang-operator-now-available-delivering-automated-day-2-operations">Kubernetes</a>, <a href="https://www.nuodb.com/techblog/deploy-nuodb-database-docker-containers-pt1">Docker</a>, VMs, bare metal, you name it. NuoDB allows you full flexibility to install the product anywhere you want while avoiding vendor lock-in with any of the cloud providers. I call our ability to run anywhere cloud-agnostic. Which is different from the next buzz word… multi-cloud.</p>

<h2 id="do-you-run-in-multiple-clouds">DO YOU RUN IN MULTIPLE CLOUDS?</h2>

<p>Being cloud-agnostic, we run in any of the clouds, but we also run in <a href="https://zoom.us/webinar/register/1815737622276/WN_m5tD0WPhRx6GOqK9bmcX5g">multi-cloud</a>. Given that multi-cloud is a loaded buzz word, let me explain what multi-cloud means to us. We give our customers the ability to run one logical NuoDB database across multiple clouds, such as AWS and Azure, at the same time. Read about the <a href="https://www.nuodb.com/company/press-releases/nuodb-partners-rancher-labs-deliver-cloud-native-sql-database-across-multi">KubeCon partnership announcement with Rancher</a>.</p>

<p>The ability to run in multiple clouds pushes the boundaries of zero-downtime even further. Having a single logical database that spans two or more clouds allows your service to continue running even in the case of serious cloud provider failures.</p>

<h2 id="what-are-your-consistency-guarantees">WHAT ARE YOUR CONSISTENCY GUARANTEES?</h2>

<p>Using the computer science term <a href="https://en.wikipedia.org/wiki/CAP_theorem">CAP</a>, NuoDB is a CP database, meaning that we prioritize consistency over availability. Once NuoDB acknowledges a transaction, it is guaranteed to be stored in the cluster following all <a href="https://en.wikipedia.org/wiki/ACID">ACID</a> principles. NuoDB is well suited for high-value data.</p>

<h2 id="are-you-built-on-top-of-another-database">ARE YOU BUILT ON TOP OF ANOTHER DATABASE?</h2>

<p>NuoDB is not build on top of another (open source) database such as <a href="https://www.mysql.com/">MySQL</a> or <a href="https://www.postgresql.org/">PostgreSQL</a>. We have our own client, SQL engine, query planner, and query optimizer. As such, we have a slightly different SQL dialect from other SQL databases. We are compliant with the ANSI SQL standard. NuoDB has been around since 2010 and has had a chance to build our own custom SQL layer that is tuned to modern distributed environments.</p>

<h2 id="do-you-use-consensusraft">DO YOU USE CONSENSUS/RAFT?</h2>

<p>The short answer is no. The longer answer is: yes, but only for configuration management as part of the administration tier. Consensus for data changes does not scale well, which is why databases that are based on it combine it with sharding. Even with sharding, performance suffers due to serializing writes (and reads) through each shard’s leader and synchronizing with multiple leaders for cross-shard transactions.</p>

<h2 id="are-you-open-source">ARE YOU OPEN SOURCE?</h2>

<p>No. NuoDB is not open source. We do provide a <a href="https://www.nuodb.com/dev-center/community-edition-download">Community Edition</a> (CE) of our product that you can download today. To make things even easier, you can download our open source <a href="https://github.com/nuodb/nuodb-helm-charts">Helm Charts</a> or <a href="https://github.com/nuodb/nuodb-operator">Go Operator</a> and get started in Kubernetes. You can also find our operator in <a href="https://quay.io/repository/nuodb/nuodb-operator">Quay.io</a>, <a href="https://aws.amazon.com/marketplace/pp/B07Z8D86BF?qid=1574450512463&amp;sr=0-1&amp;ref_=srh_res_product_title">AWS Marketplace</a>, <a href="https://console.cloud.google.com/marketplace/details/nuodb/nuodb-operator?supportedpurview=project">Google Cloud Platform</a>, <a href="https://access.redhat.com/containers/?tab=overview#/registry.connect.redhat.com/nuodb/nuodb-operator">Red Hat Catalog</a>, or <a href="https://operatorhub.io/operator/nuodb-operator-bundle">OperatorHub.io</a>. The CE is fully functional, but limits the scale-out to three Transaction Engines (TEs) and one Storage Manager (SM).</p>

<h2 id="how-easy-is-it-to-migrate-to-nuodb">HOW EASY IS IT TO MIGRATE TO NUODB?</h2>

<p>Any database migration requires work. NuoDB is not a fork of another database and as such, we implement our own SQL dialect. While we have added SQL that is compatible to Oracle and SQL Server dialect, you may be using certain vendor-specific extensions that may need to be modified.</p>

<p>More importantly, migrating existing applications to NuoDB might be easier than migrating to other distributed SQL databases because we abstract the complexity of sharding away and make the initial transition into the cloud and/or into Kubernetes easier. What does that mean? Existing applications that have been written for traditional single-node SQL databases generally are not easily partitionable or shardable. As a result, migrating to a distributed SQL database that requires partitioning or sharding may be very difficult  for an existing application. NuoDB does support <a href="https://www.nuodb.com/techblog/table-partitioning-and-storage-groups">sharding</a>, but you won’t need it from day 0. NuoDB <a href="https://www.nuodb.com/techblog/quick-dive-nuodb-architecture">Transaction Engines</a> act as a form of LRU cache that dynamically adapts to the application access patterns without the need for large-scale application rewrites. If you have a monolithic application that is running against an enterprise database today, you can migrate to the cloud first and start breaking the monolith down second.</p>

<h2 id="how-do-you-compare-to-cockroachdbyugabyte">HOW DO YOU COMPARE TO COCKROACHDB/YUGABYTE?</h2>

<p>While we are all distributed SQL databases, our architectural approach to achieve distribution is significantly different from the others, which results in different addressable use cases.</p>

<p>CockroachDB and Yugabyte both leverage automatic partitioning and a consensus algorithm to achieve distribution. In contrast, NuoDB’s architecture splits the compute and storage layers of a standard database into two different processes: Transaction Engines and Storage Managers. The Transaction Engines provide a form of LRU in-memory cache, which is coupled with Storage Managers for data persistence. Each layer can be scaled independently.</p>

<p>Our architectural approach allows our customers to migrate existing enterprise critical applications off Oracle, SQL Server, or DB2 more easily. As noted above, we don’t require a partitionable or shardable workload. Also, we don’t use a consensus algorithm for data management. As a result, we can address applications requiring very low latency and high transactional throughput. This was demonstrated in the <a href="https://www.nuodb.com/company/press-releases/temenos-benchmarks-its-cloud-native-digital-banking-software-aws-and-proves">Temenos benchmark</a>, where we were able to deliver over 50K TPS for core banking transactions.</p>

<h2 id="how-do-i-get-started-with-nuodb">HOW DO I GET STARTED WITH NUODB?</h2>

<p>Check out this straightforward tutorial, which will get you <a href="https://www.nuodb.com/techblog/scale-out-nuodb-community-edition">up and running with NuoDB Community Edition</a>. If you have more questions, <a href="https://www.nuodb.com/company/contact-us">please contact us</a>.</p>

<p>This article first appeared on the NuoDB <a href="https://www.nuodb.com/techblog/top-10-faqs-kubecon-2019-san-diego">technical blog</a>.</p>]]></content><author><name>Martin Kysel</name></author><category term="nuodb" /><category term="featured" /><summary type="html"><![CDATA[WHAT DOES NUODB DO?]]></summary></entry><entry><title type="html">What Does Distributed SQL Really Mean?</title><link href="http://www.martinkysel.com/what-does-distributed-sql-really-mean/" rel="alternate" type="text/html" title="What Does Distributed SQL Really Mean?" /><published>2020-03-23T00:00:00+00:00</published><updated>2020-03-23T00:00:00+00:00</updated><id>http://www.martinkysel.com/what-does-distributed-sql-really-mean</id><content type="html" xml:base="http://www.martinkysel.com/what-does-distributed-sql-really-mean/"><![CDATA[<p>The world is moving to the cloud and various post-monolithic SQL databases are emerging. The term “NewSQL” was coined by 451 Research analyst Matt Aslett in 2011, and in 2016 Aslett and Professor Andrew Pavlo of Carnegie Mellon University published a paper titled, “<a href="https://sigmodrecord.org/publications/sigmodRecord/1606/pdfs/07_forum_Pavlo.pdf">What’s Really New with NewSQL</a>,” describing NewSQL as a new class of database management systems that “want to achieve the same scalability of NoSQL DBMSs from the 2000s, but still keep the relational model (with SQL) and transaction support of the legacy DBMSs from the 1970-80s.” NuoDB was founded in 2010 based on this idea, and has been an important player in the distributed relational database space since then. For a while, this concept was referred to as “scalable SQL,” and we’ve also seen reference to “elastic SQL.” More recently, we’ve seen a new term emerge: “distributed SQL.”</p>

<p>Let me explain why all of these terms refer to essentially the same thing, although the ways that different databases achieve that scalability while maintaining consistency varies. As more and more companies started providing SaaS offerings that had no downtime, a pattern of pain points emerged:</p>

<ul>
  <li>A monolithic database cannot provide the resiliency and high availability guarantees required by modern always-up, always-available applications.</li>
  <li>Scaling up is no longer viable. Machines big enough to run these types of workloads become too expensive, too quickly.</li>
  <li>NoSQL is not well suited for applications that require strong transactional and ACID guarantees.</li>
  <li>Explicit sharding is too complex and diverts engineering resources from what matters most: the business.</li>
</ul>

<p>We’ve seen technologies come and go, but the same four fundamental motivations that are aligned with the shift to the cloud remain unchanged. NuoDB has been here since the beginning, and we continue to help our customers alleviate these pains.</p>

<h2 id="managing-consistency--isolation">MANAGING CONSISTENCY &amp; ISOLATION</h2>

<p>In ensuring that our database will meet the requirements of you, our customers, and the demands that your customers place on it, we’ve put a lot of thought into how we manage consistency and isolation and the isolation options that we provide. Our engineering team explored implementing a serializable isolation level but decided that the performance impact for our customers would be unacceptable. Serializable isolation is not useful for OLTP applications and is not widely required in the industry.</p>

<p>Serializable as an isolation level is a very useful academic concept, but the real-world OLTP applications that we are supporting use either Consistent Read (referred to as Repeatable Read in some literature) or predominantly Read Committed. The majority of well-known enterprise databases choose Read Committed as their default. Even MySQL, the biggest database that uses Repeatable Read as their default, requires configuration changes to use the serializable isolation level.</p>

<p>Solutions that are a thin sharding layer on top of another open-source database, such as PostgreSQL or MySQL, usually use the underlying Isolation Level of said database. Neither of these two databases offers serializable isolation by default. Since serializability is a niche feature, NuoDB decided to focus on pushing our performance to the limit while maintaining transactional and ACID guarantees.</p>

<h2 id="focused-on-performance">FOCUSED ON PERFORMANCE</h2>

<p>This focus on performance has paid off. NuoDB and Temenos recently reported a world record-breaking benchmark for core banking financial transactions. The <a href="https://www.temenos.com/us/news/2019/11/21/temenos-benchmarks-its-cloud-native-digital-banking-software-on-the-aws-cloud/">benchmark</a> in AWS demonstrated the ability to handle over half the world’s financial transactions in a single instance of Temenos running on NuoDB. During the benchmark, both Temenos and NuoDB were able to scale out to meet increasing load and then scale back down dynamically, demonstrating that financial customers can reduce TCO by using only the resources they need.</p>

<h2 id="handling-fault-tolerance--high-availability-requirements">HANDLING FAULT TOLERANCE &amp; HIGH AVAILABILITY REQUIREMENTS</h2>

<p>NuoDB is a strongly consistent database, using replication between a user defined set of replicas. We recommend a replication factor of two to four, depending on the use case and deployment topology. In general, a system cannot be failure tolerant and highly available without some form of replication. By default, NuoDB allows the creation of databases without explicit sharding because our customers were already going through a lot of pain in the process of pursuing digital transformation goals and moving into the cloud. If needed, NuoDB can be explicitly sharded to improve performance, but more on that later. NuoDB delivers a scale-out and highly available  database, without the additional complexities involved in adopting NoSQL for transactional applications or requiring sharding. These distributed SQL solutions enable companies to focus on what matters most: their business.</p>

<h2 id="adaptable-scale-out-options">ADAPTABLE SCALE OUT OPTIONS</h2>

<p>NuoDB has a two-tier system of Transaction Engines (TEs) and Storage Managers (SMs) to allow you to fine tune your environment to your particular needs. TEs act as a form of a data cache that dynamically adapts to the queries that are being executed on that TE. No complex, explicit, or manual sharding is required. TEs can be dynamically scale out or in to address changes in application demands. SMs, on the other hand, store all the data in their Storage Group on disk and guarantee durability. A user can decide how many SMs should serve which Storage Groups and hence decide on both the replication factor and the Availability vs. Persistence guarantees that their system requires. Storage Groups also allow users to partition the data across SMs, increasing IO throughput.</p>

<p>Our third tier, responsible for the administrative duties of the database, has been simplified over the years. This includes removing what was previously referred to as “Brokers” with  a RAFT based <a href="https://www.nuodb.com/blog/cloud-native-cloud-agnostic-distributed-sql-database-nuodb-40">Admin tier</a>. The management of a distributed system is extremely complex and we provide a way to hide this complexity away behind an Admin API. This system works equally well in bare-metal and in orchestration platforms such as Kubernetes.</p>

<h2 id="deploying-in-multi-cloud-multi-cluster-environments">DEPLOYING IN MULTI-CLOUD, MULTI-CLUSTER ENVIRONMENTS</h2>

<p>As more and more companies start their journey into the cloud, NuoDB is here to guide them and help them embrace an always-up, always-available mindset. At Kubecon 2019 in San Diego, we demonstrated a <a href="https://www.nuodb.com/company/press-releases/nuodb-rancher-labs">multi-cloud, multi-cluster deployment</a> on Rancher Kubernetes Engine. This unique capability allows you to deploy a single logical database across multiple public or private clouds. Moving into production soon, Hong Kong FinTech leader WeLab is revolutionizing the banking experience for Hong Kong customers. (Stay tuned to learn more about how it works and why it is an important step for companies in their goal to avoid cloud vendor lock-in.)</p>

<p>To facilitate flexibility in deploying in hybrid environments and across multiple clouds, it’s essential that our database is fully functioning on whichever Cloud Service Provider (CSP) you choose. This is a key part of why NuoDB is cloud agnostic; to enable choice and flexibility, our distributed SQL database runs in all available public clouds, private clouds, and in hybrid cloud environments. Our continuous integration pipelines test and validate the product in Amazon, Azure, and Google Cloud Platform. We also work with AKS, EKS, GKE, and Rancher. Of course not everyone is using us with a CSP or in Kubernetes, so we also work on bare metal and any major VM infrastructure. Deployment in a public cloud is not required and you can easily deploy NuoDB on-prem and in your private homegrown clouds, which allows you the choice to deploy when, where, and how you want.</p>

<h2 id="delivering-a-scalable-resilient-sql-database">DELIVERING A SCALABLE, RESILIENT SQL DATABASE</h2>

<p>The concept behind NuoDB has been around since 2008, based on Jim Starkey’s view that traditional SQL databases don’t scale well beyond a single system. This was well before the term NewSQL was coined. In 2020, we have 12 years of experience with building a resilient and ACID compliant database. And as cloud computing adoption has accelerated, our focus hasn’t needed to change. We’ve been building a database that thrives in distributed deployment environments since day one. Naturally, as technology evolves, we continually work to make sure that NuoDB is cloud native, works with microservices, containers, and container orchestration platforms. We explored Docker Swarm and Mesos when they were still a competing option, but decided to focus purely on Kubernetes once it became the leading player. We support <a href="https://github.com/nuodb/nuodb-helm-charts">Kubernetes Helm Charts</a> and are also actively working on a <a href="https://github.com/nuodb/nuodb-operator">Kubernetes Operator</a>, which is currently available in our <a href="https://www.nuodb.com/dev-center/community-edition-download">Community Edition</a>, freely available for you to try on the Kubernetes Marketplace of your choice.</p>

<p>Many of the other  NewSQL solutions took a shortcut and simply used the SQL layer and storage engines of other open source products. These are fundamentally limited in how far they can grow and how optimized they can become. NuoDB has been working on its own SQL and storage solutions for 12 years, which are highly optimized for our particular architecture running in the cloud. Our SQL engine is not limited by a 3rd party upstream product and has virtually unlimited growth potential that allows us to adapt to the dynamic and ever changing environment we are in.</p>

<p>NuoDB has come a long way since our 1.0 release seven years ago. We have been battle-hardened in production and we are very proud of the achievements we have made since then. We believe in our multi-tiered SM/TE architecture, which is adaptable for the various workloads that our customers require. We believe in our caching mechanism that allows TEs to only access a subset of the data, dynamically adapting to their current workload without the need to shard their data and workloads manually. We believe in our mission to make the use of distributed SQL easier and to support you in your journey from a monolithic database into the cloud. We believe that an important feature of any modern database is that it must be always up and always available. Resilience to failure has been a fundamental design principle in our architecture and day-to-day development. The statement also validates what we have been observing: the core of NuoDB was designed right and is well suited for the shift to the cloud. This means that we have an incredible head start with a proven solution.</p>

<p>This article first appeared on the NuoDB <a href="https://www.nuodb.com/techblog/what-does-distributed-sql-really-mean">technical blog</a>.</p>]]></content><author><name>Martin Kysel</name></author><category term="nuodb" /><summary type="html"><![CDATA[The world is moving to the cloud and various post-monolithic SQL databases are emerging. The term “NewSQL” was coined by 451 Research analyst Matt Aslett in 2011, and in 2016 Aslett and Professor Andrew Pavlo of Carnegie Mellon University published a paper titled, “What’s Really New with NewSQL,” describing NewSQL as a new class of database management systems that “want to achieve the same scalability of NoSQL DBMSs from the 2000s, but still keep the relational model (with SQL) and transaction support of the legacy DBMSs from the 1970-80s.” NuoDB was founded in 2010 based on this idea, and has been an important player in the distributed relational database space since then. For a while, this concept was referred to as “scalable SQL,” and we’ve also seen reference to “elastic SQL.” More recently, we’ve seen a new term emerge: “distributed SQL.”]]></summary></entry><entry><title type="html">Distributed Transactional Locks</title><link href="http://www.martinkysel.com/distributed-transactional-locks/" rel="alternate" type="text/html" title="Distributed Transactional Locks" /><published>2019-04-03T00:00:00+00:00</published><updated>2019-04-03T00:00:00+00:00</updated><id>http://www.martinkysel.com/distributed-transactional-locks</id><content type="html" xml:base="http://www.martinkysel.com/distributed-transactional-locks/"><![CDATA[<p>As I explained in a previous blog post, sometimes MVCC is not sufficient and an operation needs to block out all other concurrent modifications. NuoDB is able to lock three types of lockable resources: tables, schemas, and sequences. A resource can either be locked in SHARED mode (which still allows record modification, but no metadata modification) or EXCLUSIVE which prevents any concurrent modification.</p>

<p>EXCLUSIVE access is required for DDL that visits all records (various index operations for example) and distributed concurrent access is not possible. Exclusive access can also be used by operations that need to work around MVCC write skew anomalies.</p>

<p>SHARED locks need to be fast, consume as little memory as possible, involve no additional nodes in the cluster, and cause no additional messaging.</p>

<p>EXCLUSIVE locks, on the other hand, need to pay the cost.</p>

<p>MVCC uses row locks to serialise updates to a single record. Both transactional locks and row locks participate in the same deadlock detection process, but are otherwise independent. The following table explains the interaction between transactional locks and MVCC row locks. If you are interested in how row locks work, I recommend reading our <a href="https://www.nuodb.com/techblog/mvcc-part-1-overview">MVCC blog series</a>.</p>

<table>
  <thead>
    <tr>
      <th>Row Locks (DML) / Transactional Locks</th>
      <th>Shared</th>
      <th>Exclusive</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>select</td>
      <td>No Conflict</td>
      <td>No Conflict</td>
    </tr>
    <tr>
      <td>insert, update, delete, select for update</td>
      <td>No Conflict</td>
      <td>Conflict</td>
    </tr>
  </tbody>
</table>

<h3 id="use-of-transactional-locks">USE OF TRANSACTIONAL LOCKS</h3>

<p>Transactional locks are tied to the lifetime of a transaction. A lock can not exist without a transaction and it can not be released while the transaction still exists. The only way to release a transactional lock, is to resolve the transaction. There are currently three ways to resolve a transaction: commit, rollback, and failure (local or cluster wide).</p>

<p>The lock is held until all effects of the transaction have been made visible to another node. If a transaction TX is connected to TE T, it does not need to wait for the resolution of the lock if it does not modify any locked resource.</p>

<p>Similarly to a programming language mutex, once a SHARED or EXCLUSIVE lock has been acquired, the transaction needs to verify that no change happened since the beginning of the transaction. This is simple for READ COMMITTED transactions, since they do not guarantee a consistent snapshot across statements. An RC transaction will acquire all required SHARED locks, wait for any EXCLUSIVE locks that might have been acquired in the past and their effects; only then does it freeze it’s visibility snapshot. This ordering guarantees that the statement will see the newest, correct, and consistent snapshot of the database.</p>

<p>But what about CONSISTENT READ transactions? When using CR, the snapshot is frozen in time and can not be updated. This means that if a CR encounters an EXCLUSIVE lock, it might need to abort. If the EXCLUSIVE operation committed, this might mean that the view of the database is no longer compatible with the CR transaction. If it rolled back or failed, the CR can continue. If a CR can not continue you will see the exception ‘Table has been changed’. NuoDB only aborts transactions that have been proven to contain conflicting updates.</p>

<p>As I explained above, a transactional lock is similar to a mutex and should be treated that way. When using them, we recommend the check;lock;check pattern. Due to the tricky nature of snapshot visibility, NuoDB prohibits the use of the LOCK statement in CONSISTENT READ transactions. Since both check statements in the check;lock;check pattern would be executed with the same snapshot, they are guaranteed to return the same results. Any update that happened strictly before the EXCLUSIVE access was granted to the resource would not be reflected in the second check. To protect the application developer from such a mistake, NuoDB does not allow the LOCK statement in consistent read isolation level.</p>

<h3 id="using-locks-to-prevent-write-skew">USING LOCKS TO PREVENT WRITE SKEW</h3>

<p>Write skew is a well known anomaly in MVCC that we might cover in future articles. For a quick primer…</p>

<p>A table contains three employees Bob, Mary, and Sue with their respective salaries:</p>

<table>
  <thead>
    <tr>
      <th>Employee</th>
      <th>Salary</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Bob</td>
      <td>100</td>
    </tr>
    <tr>
      <td>Mary</td>
      <td>150</td>
    </tr>
    <tr>
      <td>Sue</td>
      <td>70</td>
    </tr>
  </tbody>
</table>

<p>Since the company had a good quarter, the CEO now opens a new req AND approves a salary increase for all the existing employees. The total cost can not be higher than 500.</p>

<p>The department head of department D1 looks at the total salary, calculates how much more the employees can be payed, and divides the difference equally. In SQL, that would look like:</p>

<p>SQL<strong>&gt;</strong> <strong>select</strong> <strong>sum</strong><strong>(</strong>salary<strong>)</strong> <strong>as</strong> “Existing Salaries” from employees;</p>

<p>Existing Salaries<br />
 ——————</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    320    SQL**\&gt;** update employees **set** salary = salary + **(****select** **(**500-sum**(**salary**)****)****/**count**(**salary**)** from employees**)** ; SQL**\&gt;** **select** **\*** from employees;
</code></pre></div></div>

<p>NAME  SALARY<br />
 —– ——-</p>

<p>Bob     160 <br />
 Mary    210 <br />
 Sue     130</p>

<p>SQL<strong>&gt;</strong> <strong>select</strong> <strong>sum</strong><strong>(</strong>salary<strong>)</strong> from employees;</p>

<p>SUM<br />
 —-</p>

<p>500</p>

<p>Concurrently, the department head of D2 adds a new employee:</p>

<p>SQL<strong>&gt;</strong> <strong>select</strong> <strong>sum</strong><strong>(</strong>salary<strong>)</strong> from employees;</p>

<p>SUM<br />
 —-</p>

<p>320</p>

<p>SQL<strong>&gt;</strong> insert into employees values<strong>(</strong>‘Chung’, 500-<strong>(</strong><strong>select</strong> <strong>sum</strong><strong>(</strong>salary<strong>)</strong> from employees<strong>)</strong><strong>)</strong>;
SQL<strong>&gt;</strong> <strong>select</strong> <strong>*</strong> from employees;</p>

<p>NAME  SALARY<br />
 —– ——-</p>

<p>Bob     100 <br />
 Mary    150 <br />
 Sue      70 <br />
 Chung   180</p>

<p>SQL<strong>&gt;</strong> <strong>select</strong> <strong>sum</strong><strong>(</strong>salary<strong>)</strong> from employees;</p>

<p>SUM<br />
 —-</p>

<p>500</p>

<p>As we can see, these two transactions do not conflict in MVCC. Once both transactions commit, the CEOs limit is violated.</p>

<p>SQL<strong>&gt;</strong> <strong>select</strong> <strong>sum</strong><strong>(</strong>salary<strong>)</strong> from employees;</p>

<p>SUM<br />
 —-</p>

<p>680</p>

<p>To prevent this from happening, one of the transactions can acquire an EXCLUSIVE lock. Let us look at the second transaction with locking. We will be using the check;lock;check pattern as explained in the introduction.</p>

<p>SQL<strong>&gt;</strong> start transaction isolation level <strong>read</strong> committed;
SQL<strong>&gt;</strong> <strong>select</strong> <strong>sum</strong><strong>(</strong>salary<strong>)</strong> from employees;</p>

<p>SUM<br />
 —-</p>

<p>320</p>

<p>SQL<strong>&gt;</strong> lock table employees; <strong>//</strong> blocks <strong>until</strong> T1 resolves
SQL<strong>&gt;</strong> <strong>select</strong> <strong>sum</strong><strong>(</strong>salary<strong>)</strong> from employees;</p>

<p>SUM<br />
 —-</p>

<p>500<br />
SQL<strong>&gt;</strong> <strong>//</strong> Chung can not be hired</p>

<h3 id="under-the-hood">UNDER THE HOOD</h3>

<p>So how is this logic implemented? NuoDB does not use majority consensus algorithms, such as Paxos or Raft; instead, NuoDB depends on <a href="https://www.nuodb.com/techblog/why-chairman-aint-master-replica">Chairmanship</a>. All EXCLUSIVE requests will need to be granted by the chairman to ensure strict ordering. If an EXCLUSIVE request gets denied, the transaction will have to wait for the current holder to resolve before it can retry.</p>

<p>EXCLUSIVE locks use a form of INTENT. The chairman broadcasts an INTENT to acquire an EXCLUSIVE lock. All other engines will reply with a collection of all current SHARED locks.</p>

<p>Once all SHARED locks have been resolved, the INTENT is promoted to an EXCLUSIVE lock. Once an INTENT has been placed, no further SHARED or EXCLUSIVE locks can be placed. The promotion from INTENT to EXCLUSIVE is done without any additional messaging.</p>

<p><img src="images/distributed-lock-techblog_fig1.png" alt="Figure 1. Lifecycle and messaging involved in Transactional Locks" /></p>

<p><em>Figure 1. Lifecycle and messaging involved in Transactional Locks</em></p>

<p>The reliable broadcast protocol that NuoDB uses guarantees that the INTENT is either placed everywhere or nowhere. If the chairman dies during the locking protocol, the requestor will wait for the election of a new chairman before retrying.</p>

<p>Due to the use of INTENT-like locks, it is impossible to starve an EXCLUSIVE requestor. On the other hand, an incomplete EXCLUSIVE request will block future SHARED locks long before the requestor can take advantage of the lock. NuoDB assumes that an EXCLUSIVE lock is a rare operation and that application developers understand the cost of a distributed cluster-wide exclusive access. Long running SHARED lock owners can lock out everybody else from the resource for a long period of time. If you notice that taking an EXCLUSIVE lock takes a long period of time, consider consulting NuoDB pseudo table system.transactionallocks for debugging information.</p>

<p><img src="images/distributed-lock-techblog_fig2.png" alt="Figure 2. Long running SHARED lock prevents any action on the table" /></p>

<p><em>Figure 2. Long running SHARED lock prevents any action on the table</em></p>

<p>In <strong>Figure 2</strong> above we can see a situation when a long running analytical query by USER 1 owns a SHARED lock on table T1. While that transaction is in progress, no EXCLUSIVE lock on that resource can be acquired. When a DBA attempts to alter table T1 (which requires EXCLUSIVE access), her transaction will place an INTENT and block on the existing long running transaction. Once an INTENT has been placed, no further SHARED locks can be acquired. All transactions that already own a lock are allowed to proceed, but no new transactions can acquire the lock until the INTENT has been resolved. In this scenario, we can see that USER 2 is unable to insert into the table.</p>

<p>Here is the information that you can acquire from system tables in the situation described in <strong>Figure 2</strong>.</p>

<p>SQL<strong>&gt;</strong> <strong>select</strong> <strong>*</strong> from system.transactionallocks;</p>

<p>OBJECTID  TRANSID  NODEID  LOCKTYPE  SOURCENODE<br />
 ——— ——– ——- ——— ———–</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>72       1410      2    Exclusive      2      
72       1026      2    Shared         2       SQL**\&gt;** **select** **id**,state, blockedby from system.transactions;
</code></pre></div></div>

<p>ID  STATE  BLOCKEDBY<br />
 —- —— ———-</p>

<p>1026 Active      -1  <br />
 1410 Active    1026  <br />
 1666 Active    1410</p>

<p>To let the system proceed, one of the actors in the dependency graph will need to resolve their transaction (commit, roll back, or fail).</p>

<h3 id="what-is-the-cost-of-a-lock">WHAT IS THE COST OF A LOCK?</h3>

<p>The following section assumes that there are no conflicts - that is none of the requests hit a conflicting lock that is already in place. If there is a conflict, the lock request will have to wait for the resolution of the lock, and hence the transaction that owns that lock. Since the lifetime of any arbitrary transaction is outside the control of NuoDB, we will take that out of the equation.</p>

<p>Acquiring a SHARED lock (done automatically by NuoDB) is zero overhead. We have verified this by various in-house performance benchmarks, <a href="http://www.tpc.org/tpcc/default.asp">TPC-C</a>, and <a href="https://github.com/brianfrankcooper/YCSB">YCSB</a>.</p>

<p>The cost of acquiring an EXCLUSIVE lock is three times the network latency.</p>

<ul>
  <li>Requestor -&gt; Chairman (network latency in ms)</li>
  <li>Chairman -&gt; all other nodes (network latency in ms)</li>
  <li>All other nodes -&gt; requestor (latency in ms)</li>
</ul>

<p>Since the requestor needs to receive a grant from every single TE in the system, the network latency of TEs located in remote data centers can be the major decisive component.</p>

<p><img src="images/distributed-lock-techblog_fig3.png" alt="Figure 3. Network latency and cost of a lock" /></p>

<p><em>Figure 3. Network latency and cost of a lock</em></p>

<p>Each lock is held until the end of its transaction. If a transaction contains multiple statements working on different resources, all those resources will be locked. Keep this in mind when you are performing large schema changes.</p>

<h3 id="summary">SUMMARY</h3>

<p>We have learned that expensive EXCLUSIVE transactional locks are not being used for normal CRUD operations. A CUD operation can operate without explicit approval from all nodes in the cluster by using a SHARED lock. An EXCLUSIVE lock is only required for certain metadata modifications and for special application-level use cases.</p>

<p>You can acquire an EXCLUSIVE lock for any type of operation that requires exclusive access to your table. It is possible to use EXCLUSIVE lock to work around write skew anomalies, but the recommended approach is to cause a write-write conflict by adding an additional void update on a well known record.</p>

<p>NuoDB does not use consensus algorithm, but instead depends on chairmanship for lock resolution.</p>

<p>This article first appeared at the <a href="https://www.nuodb.com/techblog/quick-dive-nuodb-architecture">NuoDB Tech Blog</a> under the name <a href="https://www.nuodb.com/techblog/distributed-transactional-locks">Distributed Transactional Locks</a></p>]]></content><author><name>Martin Kysel</name></author><category term="nuodb" /><summary type="html"><![CDATA[As I explained in a previous blog post, sometimes MVCC is not sufficient and an operation needs to block out all other concurrent modifications. NuoDB is able to lock three types of lockable resources: tables, schemas, and sequences. A resource can either be locked in SHARED mode (which still allows record modification, but no metadata modification) or EXCLUSIVE which prevents any concurrent modification.]]></summary></entry><entry><title type="html">How Transaction Locks support Zero Overhead Distributed DML</title><link href="http://www.martinkysel.com/how-transaction-locks-support-zero-overhead-distributed-dml/" rel="alternate" type="text/html" title="How Transaction Locks support Zero Overhead Distributed DML" /><published>2019-04-03T00:00:00+00:00</published><updated>2019-04-03T00:00:00+00:00</updated><id>http://www.martinkysel.com/how-transaction-locks-support-zero-overhead-distributed-dml</id><content type="html" xml:base="http://www.martinkysel.com/how-transaction-locks-support-zero-overhead-distributed-dml/"><![CDATA[<p>Let us imagine a scenario that needs to prevent MVCC write skews…</p>

<p>One transaction increases the salary of everyone in a department by 10%; another transaction inserts a new employee with a salary X. Since the two transactions do not conflict, MVCC does not prevent either of them from committing. After both resolve, the overall salary in the department could be above the budget. To prevent a similar situation, the application developer might want to have exclusive access to the table.</p>

<p>NuoDB 3.2.2 exposes a new type of lock that guarantees exclusive access to a resource across the distributed cluster. We call them Transactional Locks and they are the underlying mechanism powering the new NuoDB <a href="https://doc.nuodb.com/Latest/Content/LOCK.htm">LOCK statement</a>.</p>

<h2 id="zero-normal-case-overhead">ZERO NORMAL CASE OVERHEAD</h2>

<p>NuoDB is a distributed database. When we were designing Transactional Locks, our primary concern was the happy path - the DML that you execute thousands of times a second, does not pay the cost of a distributed operation.</p>

<p>Read DML transactions (select) will never acquire any lock. The consistency is guaranteed by <a href="https://www.nuodb.com/techblog/mvcc-part-1-overview">Multi Version Concurrency Control</a>. A Consistent Read transaction containing multiple select statements keeps a consistent metadata model of the database regardless of concurrent schema modifications.</p>

<p>Write DML transactions (update, insert, delete, select for update) acquire SHARED locks. These locks are local to the Transaction Engine that is running the transaction. Unless there is an EXCLUSIVE lock already acquired, acquiring this lock will always succeed and does not conflict with any other read or write DML operation. These SHARED locks are not distributed, serialized, communicated, or replicated throughout the cluster. Truly zero overhead.</p>

<h2 id="paying-the-cost-transactions-that-require-unique-access">PAYING THE COST: TRANSACTIONS THAT REQUIRE UNIQUE ACCESS</h2>

<p>Nothing in life comes for free, and neither does distributed consistency. Since SHARED locks are not known throughout the cluster, any operation that needs EXCLUSIVE access to a resource needs to pay the cost.</p>

<p>A operation, which requires EXCLUSIVE access to the altered resource, needs to wait for all transactions on all Transaction Engines with SHARED locks to finish. Once all transactions have been resolved (committed or rolled back), the requestor has exclusive access.</p>

<p>Transactional Locks make sure that the requesting operation eventually acquires the EXCLUSIVE lock, avoiding any starvation. As a NuoDB application developer, you should make sure that there are no long running write DML statements in flight. The exclusive requestor will have to wait for any long running transactions, possibly locking out other writers. Long running analytical SELECT queries will not conflict with transactional locks.</p>

<h2 id="lock-sql-statement">LOCK SQL STATEMENT</h2>

<p>All write DML acquires SHARED locks automatically and without any user intervention. As of 3.2.2, no EXCLUSIVE locks are acquired automatically.</p>

<p>As described in the introduction of this article, there might be situations when your application wants to have unique access to a resource. We offer you the <a href="http://doc.nuodb.com/Latest/Content/LOCK.htm">LOCK statement</a>that does exactly that. Just keep in mind that anything that is exclusive and/or unique in a distributed system can have impact on the whole cluster.</p>

<p>When using Transactional Locks, NuoDB recommends the following:</p>

<ul>
  <li>Make sure you have <a href="http://doc.nuodb.com/Latest/Content/About-Explicit-Transactions.htm">AUTOCOMMIT OFF</a> or that you started a new transaction via <a href="http://doc.nuodb.com/Latest/Content/START-TRANSACTION.htm">START TRANSACTION</a>.</li>
  <li>Your transaction uses <a href="http://doc.nuodb.com/Latest/Content/Description-of-NuoDB-Transaction-Isolation-Levels.htm">READ COMMITTED</a>. Consistent read transactions can not see all changes that happened after a snapshot was taken. This can result in lots of update conflicts on the locking transaction that will prevent you from changing the metadata.</li>
  <li>Do not have long running DML transactions.</li>
</ul>

<p>We do not offer the ability to manually lock a resource in SHARED mode. All write DML acquires a SHARED lock. To prevent the acquisition of a EXCLUSIVE LOCK on a table, NuoDB recommends executing a dummy update <em>update t set i = i where 0 = 1;</em></p>

<h2 id="there-is-no-unlock">THERE IS NO UNLOCK</h2>

<p>Transactional locks cannot be released voluntarily. The only way to unlock a resource is to commit or roll back the transaction.</p>

<p>Once obtained, the lock is held for the remainder of the current transaction. There is no UNLOCK TABLE command; locks are always released at the transaction end.</p>

<h2 id="more-reading">MORE READING</h2>

<p>We will explore the technical fundamentals of transactional locks in <a href="https://www.martinkysel.com/distributed-transactional-locks/">future articles</a>.</p>

<p>This article first appeared at the <a href="https://www.nuodb.com/techblog/quick-dive-nuodb-architecture">NuoDB Tech Blog</a> under the name <a href="https://www.nuodb.com/techblog/how-transaction-locks-support-zero-overhead-distributed-dml">How Transaction Locks support Zero Overhead Distributed DML</a></p>]]></content><author><name>Martin Kysel</name></author><category term="nuodb" /><summary type="html"><![CDATA[Let us imagine a scenario that needs to prevent MVCC write skews…]]></summary></entry></feed>