<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Microservices on IT Comparison</title><link>https://comparison.metacog.co.kr/tags/microservices/</link><description>Recent content in Microservices on IT Comparison</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Sun, 06 Sep 2026 09:57:51 +0900</lastBuildDate><atom:link href="https://comparison.metacog.co.kr/tags/microservices/index.xml" rel="self" type="application/rss+xml"/><item><title>2PC vs Saga: Atomic Commit vs Compensating Transactions</title><link>https://comparison.metacog.co.kr/posts/2026-09-06-2pc-vs-saga-atomic-commit-vs-compensating-transactions/</link><pubDate>Sun, 06 Sep 2026 09:57:51 +0900</pubDate><guid>https://comparison.metacog.co.kr/posts/2026-09-06-2pc-vs-saga-atomic-commit-vs-compensating-transactions/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;Both patterns coordinate a transaction that spans multiple services or databases, but they resolve the coordination problem in opposite ways. &lt;strong class="kw"&gt;2PC&lt;/strong&gt; locks every participant until a coordinator confirms all can commit, guaranteeing atomicity at the cost of blocking; &lt;strong class="kw"&gt;Saga&lt;/strong&gt; lets each step commit immediately and unwinds failures afterward with compensating actions, trading strict atomicity for availability and throughput.&lt;/p&gt;
&lt;h2 id="comparison-diagram"&gt;Comparison Diagram&lt;/h2&gt;
&lt;div class="compare-diagram"&gt;
&lt;svg viewBox="0 0 640 360" xmlns="http://www.w3.org/2000/svg"&gt;&lt;defs&gt;&lt;marker id="arrowA" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse"&gt;&lt;path d="M0,0L10,5L0,10z" style="fill:var(--compare-a)"/&gt;&lt;/marker&gt;&lt;marker id="arrowB" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse"&gt;&lt;path d="M0,0L10,5L0,10z" style="fill:var(--compare-b)"/&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;text x="160" y="28" text-anchor="middle" font-size="20" font-weight="bold" style="fill:var(--primary)"&gt;2PC&lt;/text&gt;&lt;text x="480" y="28" text-anchor="middle" font-size="20" font-weight="bold" style="fill:var(--primary)"&gt;Saga&lt;/text&gt;&lt;line x1="320" y1="40" x2="320" y2="340" stroke-width="1.5" stroke-dasharray="4,4" style="stroke:var(--border)"/&gt;&lt;rect x="90" y="50" width="140" height="36" rx="4" stroke-width="1.5" style="fill:var(--compare-a-soft);stroke:var(--compare-a)"/&gt;&lt;text x="160" y="73" text-anchor="middle" font-size="13" style="fill:var(--content)"&gt;Coordinator&lt;/text&gt;&lt;rect x="40" y="190" width="70" height="40" rx="4" stroke-width="1.5" style="fill:var(--compare-a-soft);stroke:var(--compare-a)"/&gt;&lt;text x="75" y="214" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;P1&lt;/text&gt;&lt;rect x="130" y="190" width="70" height="40" rx="4" stroke-width="1.5" style="fill:var(--compare-a-soft);stroke:var(--compare-a)"/&gt;&lt;text x="165" y="214" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;P2&lt;/text&gt;&lt;rect x="220" y="190" width="70" height="40" rx="4" stroke-width="1.5" style="fill:var(--compare-a-soft);stroke:var(--compare-a)"/&gt;&lt;text x="255" y="214" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;P3&lt;/text&gt;&lt;line x1="140" y1="86" x2="80" y2="190" stroke-width="1.5" marker-start="url(#arrowA)" marker-end="url(#arrowA)" style="stroke:var(--compare-a)"/&gt;&lt;line x1="160" y1="86" x2="165" y2="190" stroke-width="1.5" marker-start="url(#arrowA)" marker-end="url(#arrowA)" style="stroke:var(--compare-a)"/&gt;&lt;line x1="180" y1="86" x2="250" y2="190" stroke-width="1.5" marker-start="url(#arrowA)" marker-end="url(#arrowA)" style="stroke:var(--compare-a)"/&gt;&lt;text x="160" y="135" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;prepare / vote / commit&lt;/text&gt;&lt;rect x="50" y="245" width="50" height="18" rx="3" stroke-width="1" style="fill:none;stroke:var(--border)"/&gt;&lt;text x="75" y="258" text-anchor="middle" font-size="9" style="fill:var(--secondary)"&gt;locked&lt;/text&gt;&lt;rect x="140" y="245" width="50" height="18" rx="3" stroke-width="1" style="fill:none;stroke:var(--border)"/&gt;&lt;text x="165" y="258" text-anchor="middle" font-size="9" style="fill:var(--secondary)"&gt;locked&lt;/text&gt;&lt;rect x="230" y="245" width="50" height="18" rx="3" stroke-width="1" style="fill:none;stroke:var(--border)"/&gt;&lt;text x="255" y="258" text-anchor="middle" font-size="9" style="fill:var(--secondary)"&gt;locked&lt;/text&gt;&lt;text x="160" y="300" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;all-or-nothing, blocking until ack&lt;/text&gt;&lt;rect x="350" y="140" width="70" height="40" rx="4" stroke-width="1.5" style="fill:var(--compare-b-soft);stroke:var(--compare-b)"/&gt;&lt;text x="385" y="164" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;T1&lt;/text&gt;&lt;rect x="440" y="140" width="70" height="40" rx="4" stroke-width="1.5" style="fill:var(--compare-b-soft);stroke:var(--compare-b)"/&gt;&lt;text x="475" y="164" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;T2&lt;/text&gt;&lt;rect x="530" y="140" width="70" height="40" rx="4" stroke-width="1.5" style="fill:var(--compare-b-soft);stroke:var(--compare-b)"/&gt;&lt;text x="565" y="164" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;T3&lt;/text&gt;&lt;line x1="420" y1="160" x2="440" y2="160" stroke-width="1.5" marker-end="url(#arrowB)" style="stroke:var(--compare-b)"/&gt;&lt;line x1="510" y1="160" x2="530" y2="160" stroke-width="1.5" marker-end="url(#arrowB)" style="stroke:var(--compare-b)"/&gt;&lt;text x="480" y="130" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;local commit, local commit&lt;/text&gt;&lt;line x1="530" y1="220" x2="440" y2="220" stroke-width="1.5" stroke-dasharray="5,4" marker-end="url(#arrowB)" style="stroke:var(--compare-b)"/&gt;&lt;line x1="440" y1="240" x2="350" y2="240" stroke-width="1.5" stroke-dasharray="5,4" marker-end="url(#arrowB)" style="stroke:var(--compare-b)"/&gt;&lt;text x="480" y="212" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;compensate&lt;/text&gt;&lt;text x="395" y="257" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;compensate&lt;/text&gt;&lt;text x="480" y="300" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;independent commits, compensating rollbacks&lt;/text&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;h2 id="comparison-table"&gt;Comparison Table&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;2PC&lt;/th&gt;
&lt;th&gt;Saga&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Initiation&lt;/td&gt;
&lt;td&gt;Coordinator sends a prepare request to all participants at once&lt;/td&gt;
&lt;td&gt;First service runs its local transaction and triggers the next step&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commit decision&lt;/td&gt;
&lt;td&gt;Coordinator waits for every vote, then issues a single atomic commit or abort&lt;/td&gt;
&lt;td&gt;No central decision; each step commits independently as it finishes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resource locking&lt;/td&gt;
&lt;td&gt;Participants hold locks from prepare until the commit acknowledgment arrives&lt;/td&gt;
&lt;td&gt;No cross-step locks; each local transaction commits and releases immediately&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failure handling&lt;/td&gt;
&lt;td&gt;Coordinator aborts and tells all participants to roll back the uncommitted work&lt;/td&gt;
&lt;td&gt;Already-committed steps are undone via explicit compensating transactions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Atomicity guarantee&lt;/td&gt;
&lt;td&gt;True all-or-nothing atomicity across every participant&lt;/td&gt;
&lt;td&gt;No real atomicity; intermediate states are visible until compensations finish&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coordination dependency&lt;/td&gt;
&lt;td&gt;Single coordinator is a synchronous, blocking point of failure&lt;/td&gt;
&lt;td&gt;Runs via choreography or a lightweight orchestrator that doesn&amp;rsquo;t hold locks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latency and throughput&lt;/td&gt;
&lt;td&gt;Higher latency and lower throughput from synchronous cross-service locking&lt;/td&gt;
&lt;td&gt;Lower per-step latency and higher throughput since nothing blocks across services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Implementation effort&lt;/td&gt;
&lt;td&gt;Relies on XA-compliant resources and a transaction manager&lt;/td&gt;
&lt;td&gt;Requires custom compensating logic and step/state tracking per operation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="key-differences"&gt;Key Differences&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;2PC provides true &lt;strong class="kw"&gt;atomicity&lt;/strong&gt; across services, while Saga only approximates it through compensations after the fact&lt;/li&gt;
&lt;li&gt;2PC holds &lt;strong class="kw"&gt;locks&lt;/strong&gt; on every participant until the coordinator commits; Saga commits each step locally with no cross-service locking&lt;/li&gt;
&lt;li&gt;Saga failures require explicit &lt;strong class="kw"&gt;compensating transactions&lt;/strong&gt;; 2PC failures simply abort the still-uncommitted transaction&lt;/li&gt;
&lt;li&gt;2PC depends on a synchronous &lt;strong class="kw"&gt;coordinator&lt;/strong&gt; that all participants must trust and wait on; Saga can run via choreography or a non-blocking orchestrator&lt;/li&gt;
&lt;li&gt;2PC trades throughput for consistency, while Saga trades strict consistency for &lt;strong class="kw"&gt;availability&lt;/strong&gt; at scale&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="when-to-use-each"&gt;When to Use Each&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;2PC&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Choreography vs Orchestration: Who Drives the Workflow</title><link>https://comparison.metacog.co.kr/posts/2026-09-06-choreography-vs-orchestration-who-drives-the-workflow/</link><pubDate>Sun, 06 Sep 2026 09:56:16 +0900</pubDate><guid>https://comparison.metacog.co.kr/posts/2026-09-06-choreography-vs-orchestration-who-drives-the-workflow/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;Both patterns coordinate a multi-step business process across independent services, but they differ in where the coordination logic lives. In &lt;strong class="kw"&gt;choreography&lt;/strong&gt;, each service reacts to events and decides its own next move with no central brain; in &lt;strong class="kw"&gt;orchestration&lt;/strong&gt;, a dedicated controller tells every service what to do and in what order.&lt;/p&gt;
&lt;h2 id="comparison-diagram"&gt;Comparison Diagram&lt;/h2&gt;
&lt;div class="compare-diagram"&gt;
&lt;svg viewBox="0 0 640 360" xmlns="http://www.w3.org/2000/svg"&gt;&lt;defs&gt;&lt;marker id="arrowA" markerWidth="8" markerHeight="8" refX="6" refY="4" orient="auto"&gt;&lt;path d="M0,0 L8,4 L0,8 Z" style="fill:var(--compare-a)"/&gt;&lt;/marker&gt;&lt;marker id="arrowB" markerWidth="8" markerHeight="8" refX="6" refY="4" orient="auto"&gt;&lt;path d="M0,0 L8,4 L0,8 Z" style="fill:var(--compare-b)"/&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;line x1="320" y1="20" x2="320" y2="340" style="stroke:var(--border)" stroke-width="1" stroke-dasharray="4,4"/&gt;&lt;text x="150" y="30" text-anchor="middle" font-size="16" style="fill:var(--primary)"&gt;Choreography&lt;/text&gt;&lt;text x="480" y="30" text-anchor="middle" font-size="16" style="fill:var(--primary)"&gt;Orchestration&lt;/text&gt;&lt;rect x="50" y="140" width="90" height="40" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="95" y="164" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;Order Svc&lt;/text&gt;&lt;rect x="150" y="60" width="90" height="40" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="195" y="84" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;Payment Svc&lt;/text&gt;&lt;rect x="150" y="220" width="90" height="40" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="195" y="244" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;Shipping Svc&lt;/text&gt;&lt;path d="M108,140 C125,112 138,100 150,90" fill="none" style="stroke:var(--compare-a)" stroke-width="1.5" marker-end="url(#arrowA)"/&gt;&lt;text x="140" y="105" font-size="9" style="fill:var(--secondary)"&gt;event&lt;/text&gt;&lt;path d="M235,100 C262,150 262,180 235,222" fill="none" style="stroke:var(--compare-a)" stroke-width="1.5" marker-end="url(#arrowA)"/&gt;&lt;text x="248" y="165" font-size="9" style="fill:var(--secondary)"&gt;event&lt;/text&gt;&lt;path d="M150,238 C110,220 90,200 95,180" fill="none" style="stroke:var(--compare-a)" stroke-width="1.5" marker-end="url(#arrowA)"/&gt;&lt;text x="90" y="215" font-size="9" style="fill:var(--secondary)"&gt;event&lt;/text&gt;&lt;rect x="400" y="150" width="120" height="40" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="2"/&gt;&lt;text x="460" y="174" text-anchor="middle" font-size="11" style="fill:var(--primary)"&gt;Orchestrator&lt;/text&gt;&lt;rect x="400" y="50" width="120" height="40" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="460" y="74" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;Payment Svc&lt;/text&gt;&lt;rect x="340" y="230" width="100" height="40" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="390" y="254" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;Order Svc&lt;/text&gt;&lt;rect x="480" y="230" width="100" height="40" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="530" y="254" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;Shipping Svc&lt;/text&gt;&lt;line x1="450" y1="150" x2="450" y2="92" style="stroke:var(--compare-b)" stroke-width="1.5" marker-end="url(#arrowB)"/&gt;&lt;line x1="472" y1="92" x2="472" y2="150" style="stroke:var(--compare-b)" stroke-width="1" stroke-dasharray="3,3"/&gt;&lt;line x1="420" y1="190" x2="400" y2="228" style="stroke:var(--compare-b)" stroke-width="1.5" marker-end="url(#arrowB)"/&gt;&lt;line x1="438" y1="228" x2="445" y2="192" style="stroke:var(--compare-b)" stroke-width="1" stroke-dasharray="3,3"/&gt;&lt;line x1="500" y1="190" x2="520" y2="228" style="stroke:var(--compare-b)" stroke-width="1.5" marker-end="url(#arrowB)"/&gt;&lt;line x1="540" y1="228" x2="525" y2="192" style="stroke:var(--compare-b)" stroke-width="1" stroke-dasharray="3,3"/&gt;&lt;text x="150" y="340" text-anchor="middle" font-size="10" style="fill:var(--secondary)"&gt;no central controller&lt;/text&gt;&lt;text x="480" y="340" text-anchor="middle" font-size="10" style="fill:var(--secondary)"&gt;commands out, responses back&lt;/text&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;h2 id="comparison-table"&gt;Comparison Table&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Choreography&lt;/th&gt;
&lt;th&gt;Orchestration&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Trigger&lt;/td&gt;
&lt;td&gt;Any service publishes an event when something happens&lt;/td&gt;
&lt;td&gt;A client or event calls the orchestrator to start the process&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coordination logic&lt;/td&gt;
&lt;td&gt;Distributed across each service&amp;rsquo;s event handlers&lt;/td&gt;
&lt;td&gt;Centralized in one orchestrator component&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Communication style&lt;/td&gt;
&lt;td&gt;Asynchronous events broadcast to whoever is listening&lt;/td&gt;
&lt;td&gt;Explicit commands and replies directed at specific services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Step sequencing&lt;/td&gt;
&lt;td&gt;Emergent from chained event subscriptions&lt;/td&gt;
&lt;td&gt;Explicitly defined as a workflow or state machine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failure handling&lt;/td&gt;
&lt;td&gt;Each service listens for failure events and compensates locally&lt;/td&gt;
&lt;td&gt;Orchestrator detects failure and drives compensating transactions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adding a new step&lt;/td&gt;
&lt;td&gt;Add a listener; no existing service needs to change&lt;/td&gt;
&lt;td&gt;Update the orchestrator&amp;rsquo;s workflow definition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Observability&lt;/td&gt;
&lt;td&gt;Hard to see the full process; requires distributed tracing&lt;/td&gt;
&lt;td&gt;Process state is visible in one place, easy to audit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coupling&lt;/td&gt;
&lt;td&gt;Low coupling between services, higher coupling to event schema&lt;/td&gt;
&lt;td&gt;Services decoupled from each other, but coupled to the orchestrator&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="key-differences"&gt;Key Differences&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Choreography spreads decision-making across services via &lt;strong class="kw"&gt;events&lt;/strong&gt;; orchestration centralizes it in a single &lt;strong class="kw"&gt;controller&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Choreography scales extensibility easily but makes the overall process hard to &lt;strong class="kw"&gt;trace&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Orchestration makes the workflow explicit and easy to &lt;strong class="kw"&gt;audit&lt;/strong&gt;, at the cost of a single point of coordination.&lt;/li&gt;
&lt;li&gt;Compensation logic lives in each service under choreography, but is driven centrally under &lt;strong class="kw"&gt;orchestration&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Orchestration introduces a dependency on the &lt;strong class="kw"&gt;orchestrator&lt;/strong&gt; itself as new coupling, even as it decouples the services from each other.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="when-to-use-each"&gt;When to Use Each&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Choreography&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Shared Database vs Database Per Service: Data Ownership in Microservices</title><link>https://comparison.metacog.co.kr/posts/2026-09-06-shared-database-vs-database-per-service-data-ownership-in-mi/</link><pubDate>Sun, 06 Sep 2026 09:52:35 +0900</pubDate><guid>https://comparison.metacog.co.kr/posts/2026-09-06-shared-database-vs-database-per-service-data-ownership-in-mi/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;This compares two data architecture patterns for microservices: a &lt;strong class="kw"&gt;shared database&lt;/strong&gt; where multiple services read and write the same schema, versus &lt;strong class="kw"&gt;database per service&lt;/strong&gt; where each service owns an isolated data store. The choice determines how tightly services are coupled, how transactions and queries span service boundaries, and how independently teams can deploy and scale.&lt;/p&gt;
&lt;h2 id="comparison-diagram"&gt;Comparison Diagram&lt;/h2&gt;
&lt;div class="compare-diagram"&gt;
&lt;svg viewBox="0 0 640 360" xmlns="http://www.w3.org/2000/svg"&gt;&lt;text x="160" y="30" text-anchor="middle" font-size="18" font-weight="bold" style="fill:var(--primary)"&gt;Shared Database&lt;/text&gt;&lt;text x="480" y="30" text-anchor="middle" font-size="18" font-weight="bold" style="fill:var(--primary)"&gt;Database Per Service&lt;/text&gt;&lt;line x1="320" y1="50" x2="320" y2="330" stroke-width="1" stroke-dasharray="4,4" style="stroke:var(--border)"/&gt;&lt;rect x="30" y="70" width="110" height="44" rx="6" style="fill:var(--compare-a-soft);stroke:var(--compare-a)"/&gt;&lt;text x="85" y="97" text-anchor="middle" font-size="13" style="fill:var(--content)"&gt;Service A&lt;/text&gt;&lt;rect x="30" y="155" width="110" height="44" rx="6" style="fill:var(--compare-a-soft);stroke:var(--compare-a)"/&gt;&lt;text x="85" y="182" text-anchor="middle" font-size="13" style="fill:var(--content)"&gt;Service B&lt;/text&gt;&lt;rect x="30" y="240" width="110" height="44" rx="6" style="fill:var(--compare-a-soft);stroke:var(--compare-a)"/&gt;&lt;text x="85" y="267" text-anchor="middle" font-size="13" style="fill:var(--content)"&gt;Service C&lt;/text&gt;&lt;rect x="210" y="110" width="90" height="150" rx="8" stroke-width="2" style="fill:var(--compare-a-soft);stroke:var(--compare-a)"/&gt;&lt;text x="255" y="180" text-anchor="middle" font-size="13" style="fill:var(--content)"&gt;Shared&lt;/text&gt;&lt;text x="255" y="198" text-anchor="middle" font-size="13" style="fill:var(--content)"&gt;DB&lt;/text&gt;&lt;line x1="140" y1="92" x2="210" y2="145" stroke-width="1.5" style="stroke:var(--compare-a)"/&gt;&lt;line x1="140" y1="177" x2="210" y2="185" stroke-width="1.5" style="stroke:var(--compare-a)"/&gt;&lt;line x1="140" y1="262" x2="210" y2="225" stroke-width="1.5" style="stroke:var(--compare-a)"/&gt;&lt;rect x="350" y="70" width="100" height="44" rx="6" style="fill:var(--compare-b-soft);stroke:var(--compare-b)"/&gt;&lt;text x="400" y="97" text-anchor="middle" font-size="13" style="fill:var(--content)"&gt;Service A&lt;/text&gt;&lt;rect x="480" y="70" width="90" height="44" rx="6" style="fill:var(--compare-b-soft);stroke:var(--compare-b)"/&gt;&lt;text x="525" y="97" text-anchor="middle" font-size="13" style="fill:var(--content)"&gt;DB A&lt;/text&gt;&lt;line x1="450" y1="92" x2="480" y2="92" stroke-width="1.5" style="stroke:var(--compare-b)"/&gt;&lt;rect x="350" y="155" width="100" height="44" rx="6" style="fill:var(--compare-b-soft);stroke:var(--compare-b)"/&gt;&lt;text x="400" y="182" text-anchor="middle" font-size="13" style="fill:var(--content)"&gt;Service B&lt;/text&gt;&lt;rect x="480" y="155" width="90" height="44" rx="6" style="fill:var(--compare-b-soft);stroke:var(--compare-b)"/&gt;&lt;text x="525" y="182" text-anchor="middle" font-size="13" style="fill:var(--content)"&gt;DB B&lt;/text&gt;&lt;line x1="450" y1="177" x2="480" y2="177" stroke-width="1.5" style="stroke:var(--compare-b)"/&gt;&lt;rect x="350" y="240" width="100" height="44" rx="6" style="fill:var(--compare-b-soft);stroke:var(--compare-b)"/&gt;&lt;text x="400" y="267" text-anchor="middle" font-size="13" style="fill:var(--content)"&gt;Service C&lt;/text&gt;&lt;rect x="480" y="240" width="90" height="44" rx="6" style="fill:var(--compare-b-soft);stroke:var(--compare-b)"/&gt;&lt;text x="525" y="267" text-anchor="middle" font-size="13" style="fill:var(--content)"&gt;DB C&lt;/text&gt;&lt;line x1="450" y1="262" x2="480" y2="262" stroke-width="1.5" style="stroke:var(--compare-b)"/&gt;&lt;text x="160" y="345" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;Single point of coupling &amp;amp; contention&lt;/text&gt;&lt;text x="480" y="345" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;Isolated data, independent scaling&lt;/text&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;h2 id="comparison-table"&gt;Comparison Table&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Shared Database&lt;/th&gt;
&lt;th&gt;Database Per Service&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Schema ownership&lt;/td&gt;
&lt;td&gt;One schema shared and often co-owned by multiple teams&lt;/td&gt;
&lt;td&gt;Each service exclusively owns and evolves its own schema&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Write path&lt;/td&gt;
&lt;td&gt;Any service can write directly to shared tables&lt;/td&gt;
&lt;td&gt;Writes go only through the owning service&amp;rsquo;s API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cross-service queries&lt;/td&gt;
&lt;td&gt;Simple SQL joins across tables in one database&lt;/td&gt;
&lt;td&gt;Requires API calls, data replication, or an aggregation layer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Distributed transactions&lt;/td&gt;
&lt;td&gt;Native ACID transactions across affected tables&lt;/td&gt;
&lt;td&gt;Needs sagas or eventual consistency to span services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Schema migrations&lt;/td&gt;
&lt;td&gt;Any change risks breaking other services using the table&lt;/td&gt;
&lt;td&gt;Migrations are local and safe to run independently&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Independent scaling&lt;/td&gt;
&lt;td&gt;Database becomes a shared bottleneck under load&lt;/td&gt;
&lt;td&gt;Each store can be scaled or tuned to its own service&amp;rsquo;s needs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Technology choice&lt;/td&gt;
&lt;td&gt;All services locked into one database engine&lt;/td&gt;
&lt;td&gt;Each service can pick the best-fit database technology&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failure isolation&lt;/td&gt;
&lt;td&gt;A database outage or lock contention affects every service&lt;/td&gt;
&lt;td&gt;An outage is contained to the owning service&amp;rsquo;s data&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="key-differences"&gt;Key Differences&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Shared database allows cheap &lt;strong class="kw"&gt;cross-table joins&lt;/strong&gt; but couples every consuming service to one schema&lt;/li&gt;
&lt;li&gt;Database per service enforces &lt;strong class="kw"&gt;service autonomy&lt;/strong&gt; at the cost of needing sagas for cross-service transactions&lt;/li&gt;
&lt;li&gt;Schema changes in a shared database require coordinating &lt;strong class="kw"&gt;multiple teams&lt;/strong&gt;, while per-service schemas change independently&lt;/li&gt;
&lt;li&gt;A shared database creates a single &lt;strong class="kw"&gt;failure domain&lt;/strong&gt;; per-service databases contain outages to one service&lt;/li&gt;
&lt;li&gt;Polyglot persistence — choosing different database engines per need — is only possible with &lt;strong class="kw"&gt;database per service&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="when-to-use-each"&gt;When to Use Each&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Shared Database&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Monolith vs Microservices: One Deployable vs Many</title><link>https://comparison.metacog.co.kr/posts/2026-09-06-monolith-vs-microservices-one-deployable-vs-many/</link><pubDate>Sun, 06 Sep 2026 09:51:18 +0900</pubDate><guid>https://comparison.metacog.co.kr/posts/2026-09-06-monolith-vs-microservices-one-deployable-vs-many/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;A &lt;strong class="kw"&gt;monolith&lt;/strong&gt; packages an application&amp;rsquo;s entire codebase and functionality into a single deployable unit running as one process, while &lt;strong class="kw"&gt;microservices&lt;/strong&gt; split that same functionality into independently deployable services that communicate over a network. The choice shapes how teams build, deploy, scale, and recover from failures, so it matters far beyond just code organization.&lt;/p&gt;
&lt;h2 id="comparison-diagram"&gt;Comparison Diagram&lt;/h2&gt;
&lt;div class="compare-diagram"&gt;
&lt;svg viewBox="0 0 640 360" xmlns="http://www.w3.org/2000/svg"&gt;&lt;text x="160" y="36" text-anchor="middle" font-size="16" font-weight="bold" style="fill:var(--primary)"&gt;Monolith&lt;/text&gt;&lt;rect x="40" y="60" width="240" height="260" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="2"/&gt;&lt;line x1="160" y1="60" x2="160" y2="320" style="stroke:var(--border)" stroke-width="1" stroke-dasharray="4 3"/&gt;&lt;line x1="40" y1="190" x2="280" y2="190" style="stroke:var(--border)" stroke-width="1" stroke-dasharray="4 3"/&gt;&lt;text x="100" y="128" text-anchor="middle" font-size="13" style="fill:var(--content)"&gt;Auth&lt;/text&gt;&lt;text x="220" y="128" text-anchor="middle" font-size="13" style="fill:var(--content)"&gt;Orders&lt;/text&gt;&lt;text x="100" y="258" text-anchor="middle" font-size="13" style="fill:var(--content)"&gt;Inventory&lt;/text&gt;&lt;text x="220" y="258" text-anchor="middle" font-size="13" style="fill:var(--content)"&gt;Payments&lt;/text&gt;&lt;text x="160" y="338" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;Single process&lt;/text&gt;&lt;text x="160" y="352" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;Single deploy&lt;/text&gt;&lt;text x="480" y="36" text-anchor="middle" font-size="16" font-weight="bold" style="fill:var(--primary)"&gt;Microservices&lt;/text&gt;&lt;rect x="395" y="60" width="110" height="36" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="2"/&gt;&lt;text x="450" y="83" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;API Gateway&lt;/text&gt;&lt;line x1="420" y1="96" x2="375" y2="150" style="stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;line x1="445" y1="96" x2="445" y2="150" style="stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;line x1="455" y1="96" x2="515" y2="150" style="stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;line x1="480" y1="96" x2="575" y2="150" style="stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;rect x="345" y="150" width="60" height="50" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="2"/&gt;&lt;text x="375" y="180" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;Auth&lt;/text&gt;&lt;rect x="415" y="150" width="60" height="50" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="2"/&gt;&lt;text x="445" y="180" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;Orders&lt;/text&gt;&lt;rect x="485" y="150" width="60" height="50" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="2"/&gt;&lt;text x="515" y="180" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;Inventory&lt;/text&gt;&lt;rect x="545" y="150" width="60" height="50" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="2"/&gt;&lt;text x="575" y="180" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;Payments&lt;/text&gt;&lt;line x1="375" y1="215" x2="375" y2="245" style="stroke:var(--border)" stroke-width="1" stroke-dasharray="3 3"/&gt;&lt;line x1="445" y1="215" x2="445" y2="245" style="stroke:var(--border)" stroke-width="1" stroke-dasharray="3 3"/&gt;&lt;line x1="515" y1="215" x2="515" y2="245" style="stroke:var(--border)" stroke-width="1" stroke-dasharray="3 3"/&gt;&lt;line x1="575" y1="215" x2="575" y2="245" style="stroke:var(--border)" stroke-width="1" stroke-dasharray="3 3"/&gt;&lt;rect x="345" y="245" width="260" height="30" rx="3" style="fill:none;stroke:var(--border)" stroke-width="1" stroke-dasharray="3 3"/&gt;&lt;text x="475" y="264" text-anchor="middle" font-size="10" style="fill:var(--secondary)"&gt;separate databases&lt;/text&gt;&lt;text x="475" y="338" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;Independent services&lt;/text&gt;&lt;text x="475" y="352" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;Independent deploys&lt;/text&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;h2 id="comparison-table"&gt;Comparison Table&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Monolith&lt;/th&gt;
&lt;th&gt;Microservices&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Codebase structure&lt;/td&gt;
&lt;td&gt;Single repository, one shared codebase for all functionality&lt;/td&gt;
&lt;td&gt;Multiple repositories, one per service with its own codebase&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment unit&lt;/td&gt;
&lt;td&gt;Whole application built and shipped as one artifact&lt;/td&gt;
&lt;td&gt;Each service built, versioned, and shipped independently&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inter-module communication&lt;/td&gt;
&lt;td&gt;In-process function calls within the same runtime&lt;/td&gt;
&lt;td&gt;Network calls via HTTP, gRPC, or messaging between services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data storage&lt;/td&gt;
&lt;td&gt;Typically one shared database for the whole app&lt;/td&gt;
&lt;td&gt;Each service usually owns its own database or schema&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scaling&lt;/td&gt;
&lt;td&gt;Scale the entire application even if only one part is hot&lt;/td&gt;
&lt;td&gt;Scale only the specific services that need more capacity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fault isolation&lt;/td&gt;
&lt;td&gt;A crash or memory leak in one module can take down the app&lt;/td&gt;
&lt;td&gt;A failing service degrades its own function without necessarily crashing others&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Technology stack&lt;/td&gt;
&lt;td&gt;One language and framework across the whole application&lt;/td&gt;
&lt;td&gt;Each service can use the language/framework best suited to it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Team ownership and releases&lt;/td&gt;
&lt;td&gt;One team or a coordinated release train ships the whole app together&lt;/td&gt;
&lt;td&gt;Independent teams own and release their services on their own schedules&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="key-differences"&gt;Key Differences&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A monolith runs as a &lt;strong class="kw"&gt;single process&lt;/strong&gt;, while microservices are &lt;strong class="kw"&gt;distributed processes&lt;/strong&gt; talking over the network&lt;/li&gt;
&lt;li&gt;Microservices trade in-process call reliability for &lt;strong class="kw"&gt;network latency&lt;/strong&gt; and partial failure handling&lt;/li&gt;
&lt;li&gt;Independent deployability lets microservices teams ship on &lt;strong class="kw"&gt;separate release cadences&lt;/strong&gt;, which a monolith can&amp;rsquo;t offer&lt;/li&gt;
&lt;li&gt;Splitting services adds real &lt;strong class="kw"&gt;operational overhead&lt;/strong&gt; — service discovery, monitoring, and distributed tracing&lt;/li&gt;
&lt;li&gt;Data ownership per service enables &lt;strong class="kw"&gt;polyglot persistence&lt;/strong&gt; but sacrifices easy cross-entity transactions&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="when-to-use-each"&gt;When to Use Each&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Monolith&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>SOA vs Microservices: Enterprise Integration vs Independent Deployability</title><link>https://comparison.metacog.co.kr/posts/2026-08-04-soa-vs-microservices-enterprise-integration-vs-independent-d/</link><pubDate>Tue, 04 Aug 2026 05:17:08 +0900</pubDate><guid>https://comparison.metacog.co.kr/posts/2026-08-04-soa-vs-microservices-enterprise-integration-vs-independent-d/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;SOA and microservices are both approaches to composing systems from independently callable services, but they differ sharply in scope and philosophy. &lt;strong class="kw"&gt;SOA&lt;/strong&gt; centralizes communication and governance through an enterprise service bus to integrate large, often legacy systems, while &lt;strong class="kw"&gt;microservices&lt;/strong&gt; decentralize communication, data, and deployment into small, independently shippable units. The distinction matters because it drives very different tooling, team structures, and failure characteristics.&lt;/p&gt;
&lt;h2 id="comparison-diagram"&gt;Comparison Diagram&lt;/h2&gt;
&lt;div class="compare-diagram"&gt;
&lt;svg viewBox="0 0 640 360" xmlns="http://www.w3.org/2000/svg"&gt;&lt;text x="150" y="30" text-anchor="middle" font-size="20" font-weight="bold" style="fill:var(--primary)"&gt;SOA&lt;/text&gt;&lt;text x="480" y="30" text-anchor="middle" font-size="20" font-weight="bold" style="fill:var(--primary)"&gt;Microservices&lt;/text&gt;&lt;line x1="320" y1="50" x2="320" y2="340" style="stroke:var(--border)" stroke-width="1.5" stroke-dasharray="4 4"/&gt;&lt;circle cx="70" cy="90" r="20" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="70" y="94" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;S1&lt;/text&gt;&lt;circle cx="230" cy="90" r="20" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="230" y="94" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;S2&lt;/text&gt;&lt;circle cx="70" cy="230" r="20" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="70" y="234" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;S3&lt;/text&gt;&lt;circle cx="230" cy="230" r="20" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="230" y="234" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;S4&lt;/text&gt;&lt;line x1="70" y1="90" x2="150" y2="160" style="stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;line x1="230" y1="90" x2="150" y2="160" style="stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;line x1="70" y1="230" x2="150" y2="160" style="stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;line x1="230" y1="230" x2="150" y2="160" style="stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;rect x="95" y="140" width="110" height="40" rx="6" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="150" y="164" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;ESB&lt;/text&gt;&lt;line x1="150" y1="180" x2="150" y2="290" style="stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;rect x="95" y="290" width="110" height="36" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="150" y="313" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;Shared DB&lt;/text&gt;&lt;text x="150" y="345" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;Central bus + shared data&lt;/text&gt;&lt;circle cx="400" cy="90" r="20" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="400" y="94" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;M1&lt;/text&gt;&lt;circle cx="560" cy="90" r="20" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="560" y="94" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;M2&lt;/text&gt;&lt;circle cx="400" cy="230" r="20" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="400" y="234" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;M3&lt;/text&gt;&lt;circle cx="560" cy="230" r="20" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="560" y="234" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;M4&lt;/text&gt;&lt;line x1="400" y1="90" x2="560" y2="90" style="stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;line x1="400" y1="90" x2="400" y2="230" style="stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;line x1="560" y1="90" x2="560" y2="230" style="stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;line x1="400" y1="230" x2="560" y2="230" style="stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;rect x="330" y="55" width="40" height="18" rx="3" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.2"/&gt;&lt;text x="350" y="68" text-anchor="middle" font-size="9" style="fill:var(--content)"&gt;db&lt;/text&gt;&lt;rect x="590" y="55" width="40" height="18" rx="3" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.2"/&gt;&lt;text x="610" y="68" text-anchor="middle" font-size="9" style="fill:var(--content)"&gt;db&lt;/text&gt;&lt;rect x="330" y="252" width="40" height="18" rx="3" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.2"/&gt;&lt;text x="350" y="265" text-anchor="middle" font-size="9" style="fill:var(--content)"&gt;db&lt;/text&gt;&lt;rect x="590" y="252" width="40" height="18" rx="3" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.2"/&gt;&lt;text x="610" y="265" text-anchor="middle" font-size="9" style="fill:var(--content)"&gt;db&lt;/text&gt;&lt;text x="480" y="345" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;Direct calls, DB per service&lt;/text&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;h2 id="comparison-table"&gt;Comparison Table&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;SOA&lt;/th&gt;
&lt;th&gt;Microservices&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Communication mechanism&lt;/td&gt;
&lt;td&gt;Services talk through a central Enterprise Service Bus using protocols like SOAP/WS-*&lt;/td&gt;
&lt;td&gt;Services talk directly via lightweight REST/gRPC calls or message brokers, no mandatory central bus&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Service granularity&lt;/td&gt;
&lt;td&gt;Coarse-grained, often modeling whole business processes&lt;/td&gt;
&lt;td&gt;Fine-grained, each service owns a single business capability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data ownership&lt;/td&gt;
&lt;td&gt;Services frequently share a common database or canonical data model&lt;/td&gt;
&lt;td&gt;Each service owns and manages its own private database&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment unit&lt;/td&gt;
&lt;td&gt;Services often share application servers or deployment packages&lt;/td&gt;
&lt;td&gt;Each service is deployed and scaled independently, typically in its own container&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Technology stack&lt;/td&gt;
&lt;td&gt;Standardized enterprise-wide on common platforms and protocols&lt;/td&gt;
&lt;td&gt;Polyglot — each team chooses its own language, framework, and datastore&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fault isolation&lt;/td&gt;
&lt;td&gt;The ESB is a potential single point of failure affecting many services&lt;/td&gt;
&lt;td&gt;Failures are isolated to individual services, limiting blast radius&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Governance &amp;amp; teams&lt;/td&gt;
&lt;td&gt;Centralized architecture review board and IT governance&lt;/td&gt;
&lt;td&gt;Decentralized ownership by small, autonomous teams per service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical origin&lt;/td&gt;
&lt;td&gt;Emerged from large-scale enterprise integration needs in the 2000s&lt;/td&gt;
&lt;td&gt;Emerged from cloud-native, DevOps-driven practices in the 2010s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="key-differences"&gt;Key Differences&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;SOA centralizes routing and transformation logic in an &lt;strong class="kw"&gt;ESB&lt;/strong&gt;, while microservices push that logic into the endpoints themselves.&lt;/li&gt;
&lt;li&gt;Microservices mandate &lt;strong class="kw"&gt;database per service&lt;/strong&gt;, whereas SOA services commonly share a data layer.&lt;/li&gt;
&lt;li&gt;SOA favors &lt;strong class="kw"&gt;reusable coarse-grained services&lt;/strong&gt; across the enterprise; microservices favor small, single-purpose services.&lt;/li&gt;
&lt;li&gt;Microservices deploy and scale via &lt;strong class="kw"&gt;independent containers&lt;/strong&gt;, while SOA services often share application servers.&lt;/li&gt;
&lt;li&gt;SOA relies on heavyweight standards like &lt;strong class="kw"&gt;SOAP/WS-*&lt;/strong&gt;; microservices typically use lightweight REST or gRPC.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="when-to-use-each"&gt;When to Use Each&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;SOA&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Shared Database vs Database per Service: Data Ownership in Microservices</title><link>https://comparison.metacog.co.kr/posts/2026-08-04-shared-database-vs-database-per-service-data-ownership-in-mi/</link><pubDate>Tue, 04 Aug 2026 05:14:24 +0900</pubDate><guid>https://comparison.metacog.co.kr/posts/2026-08-04-shared-database-vs-database-per-service-data-ownership-in-mi/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;A &lt;strong class="kw"&gt;shared database&lt;/strong&gt; lets multiple services read and write the same tables through one common schema, while &lt;strong class="kw"&gt;database per service&lt;/strong&gt; gives each service its own private data store that only it can touch directly. The choice determines how tightly services are coupled at the data layer, how independently teams can deploy, and how much work cross-service queries and transactions require.&lt;/p&gt;
&lt;h2 id="comparison-diagram"&gt;Comparison Diagram&lt;/h2&gt;
&lt;div class="compare-diagram"&gt;
&lt;svg viewBox="0 0 640 360" xmlns="http://www.w3.org/2000/svg"&gt;&lt;line x1="320" y1="20" x2="320" y2="340" style="stroke:var(--border)" stroke-width="1" stroke-dasharray="4 4"/&gt;&lt;text x="160" y="32" text-anchor="middle" style="fill:var(--primary)" font-size="16" font-weight="bold"&gt;Shared Database&lt;/text&gt;&lt;text x="480" y="32" text-anchor="middle" style="fill:var(--primary)" font-size="16" font-weight="bold"&gt;Database per Service&lt;/text&gt;&lt;rect x="30" y="55" width="70" height="35" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="65" y="77" text-anchor="middle" style="fill:var(--content)" font-size="11"&gt;Service A&lt;/text&gt;&lt;rect x="125" y="55" width="70" height="35" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="160" y="77" text-anchor="middle" style="fill:var(--content)" font-size="11"&gt;Service B&lt;/text&gt;&lt;rect x="220" y="55" width="70" height="35" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="255" y="77" text-anchor="middle" style="fill:var(--content)" font-size="11"&gt;Service C&lt;/text&gt;&lt;line x1="65" y1="90" x2="140" y2="168" style="stroke:var(--secondary)" stroke-width="1.5"/&gt;&lt;line x1="160" y1="90" x2="160" y2="168" style="stroke:var(--secondary)" stroke-width="1.5"/&gt;&lt;line x1="255" y1="90" x2="180" y2="168" style="stroke:var(--secondary)" stroke-width="1.5"/&gt;&lt;rect x="115" y="170" width="90" height="55" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;ellipse cx="160" cy="170" rx="45" ry="12" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;ellipse cx="160" cy="225" rx="45" ry="12" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="160" y="204" text-anchor="middle" style="fill:var(--content)" font-size="12" font-weight="bold"&gt;Shared DB&lt;/text&gt;&lt;text x="160" y="300" text-anchor="middle" style="fill:var(--secondary)" font-size="11"&gt;one schema, every service reads/writes it directly&lt;/text&gt;&lt;rect x="355" y="48" width="100" height="180" rx="6" style="fill:none;stroke:var(--border)" stroke-width="1" stroke-dasharray="4 3"/&gt;&lt;rect x="450" y="48" width="100" height="180" rx="6" style="fill:none;stroke:var(--border)" stroke-width="1" stroke-dasharray="4 3"/&gt;&lt;rect x="545" y="48" width="90" height="180" rx="6" style="fill:none;stroke:var(--border)" stroke-width="1" stroke-dasharray="4 3"/&gt;&lt;rect x="370" y="55" width="70" height="35" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="405" y="77" text-anchor="middle" style="fill:var(--content)" font-size="11"&gt;Service X&lt;/text&gt;&lt;rect x="465" y="55" width="70" height="35" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="500" y="77" text-anchor="middle" style="fill:var(--content)" font-size="11"&gt;Service Y&lt;/text&gt;&lt;rect x="560" y="55" width="70" height="35" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="595" y="77" text-anchor="middle" style="fill:var(--content)" font-size="11"&gt;Service Z&lt;/text&gt;&lt;line x1="405" y1="90" x2="405" y2="150" style="stroke:var(--secondary)" stroke-width="1.5"/&gt;&lt;line x1="500" y1="90" x2="500" y2="150" style="stroke:var(--secondary)" stroke-width="1.5"/&gt;&lt;line x1="595" y1="90" x2="595" y2="150" style="stroke:var(--secondary)" stroke-width="1.5"/&gt;&lt;rect x="375" y="150" width="60" height="42" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;ellipse cx="405" cy="150" rx="30" ry="8" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;ellipse cx="405" cy="192" rx="30" ry="8" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="405" y="175" text-anchor="middle" style="fill:var(--content)" font-size="10"&gt;DB X&lt;/text&gt;&lt;rect x="470" y="150" width="60" height="42" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;ellipse cx="500" cy="150" rx="30" ry="8" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;ellipse cx="500" cy="192" rx="30" ry="8" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="500" y="175" text-anchor="middle" style="fill:var(--content)" font-size="10"&gt;DB Y&lt;/text&gt;&lt;rect x="565" y="150" width="60" height="42" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;ellipse cx="595" cy="150" rx="30" ry="8" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;ellipse cx="595" cy="192" rx="30" ry="8" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="595" y="175" text-anchor="middle" style="fill:var(--content)" font-size="10"&gt;DB Z&lt;/text&gt;&lt;text x="480" y="300" text-anchor="middle" style="fill:var(--secondary)" font-size="11"&gt;each service owns a private schema, accessed only via its API&lt;/text&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;h2 id="comparison-table"&gt;Comparison Table&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Shared Database&lt;/th&gt;
&lt;th&gt;Database per Service&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Data ownership&lt;/td&gt;
&lt;td&gt;No single owner — all services see and can modify the same tables&lt;/td&gt;
&lt;td&gt;Each service exclusively owns its schema; no one else can touch it directly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Access path&lt;/td&gt;
&lt;td&gt;Services query the database directly, often with raw SQL against shared tables&lt;/td&gt;
&lt;td&gt;Other services only get data through the owning service&amp;rsquo;s API or published events&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cross-service transactions&lt;/td&gt;
&lt;td&gt;Native ACID transactions and joins span all the data in one commit&lt;/td&gt;
&lt;td&gt;No shared transaction; consistency across services needs sagas or eventual consistency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cross-service queries&lt;/td&gt;
&lt;td&gt;Simple SQL joins pull data from any table in one query&lt;/td&gt;
&lt;td&gt;Requires API composition, data replication, or a separate CQRS read model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Schema changes&lt;/td&gt;
&lt;td&gt;A column or table change can silently break unrelated services&lt;/td&gt;
&lt;td&gt;Schema changes are internal; only the public API contract must stay stable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Technology choice&lt;/td&gt;
&lt;td&gt;All services are locked into one database engine and schema&lt;/td&gt;
&lt;td&gt;Each service can pick the storage engine that fits its data (polyglot persistence)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failure isolation&lt;/td&gt;
&lt;td&gt;A database outage or lock contention affects every service at once&lt;/td&gt;
&lt;td&gt;An outage in one service&amp;rsquo;s database doesn&amp;rsquo;t directly take down the others&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operational overhead&lt;/td&gt;
&lt;td&gt;One database to provision, back up, and tune&lt;/td&gt;
&lt;td&gt;N databases to provision, monitor, back up, and scale independently&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="key-differences"&gt;Key Differences&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Shared database gives every service direct access to the same tables, so a change in one place can silently break another service&amp;rsquo;s queries — a form of &lt;strong class="kw"&gt;tight coupling&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Database per service forces all cross-service data access through an API, giving each service true &lt;strong class="kw"&gt;encapsulation&lt;/strong&gt; of its data.&lt;/li&gt;
&lt;li&gt;Cross-entity consistency is a native &lt;strong class="kw"&gt;ACID transaction&lt;/strong&gt; in a shared database, but needs a &lt;strong class="kw"&gt;saga pattern&lt;/strong&gt; or eventual consistency once data is split per service.&lt;/li&gt;
&lt;li&gt;Reporting and ad-hoc joins are trivial with a shared database&amp;rsquo;s SQL, while database per service usually needs a separate &lt;strong class="kw"&gt;CQRS read model&lt;/strong&gt; to answer cross-service queries.&lt;/li&gt;
&lt;li&gt;Database per service allows &lt;strong class="kw"&gt;polyglot persistence&lt;/strong&gt; — each service picks its own database engine — whereas shared database locks every service to one engine and schema.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="when-to-use-each"&gt;When to Use Each&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Shared Database&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Orchestration vs Choreography: Coordinating Distributed Workflows</title><link>https://comparison.metacog.co.kr/posts/2026-08-04-orchestration-vs-choreography-coordinating-distributed-workf/</link><pubDate>Tue, 04 Aug 2026 05:11:21 +0900</pubDate><guid>https://comparison.metacog.co.kr/posts/2026-08-04-orchestration-vs-choreography-coordinating-distributed-workf/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;Orchestration and choreography are two ways to coordinate multiple services in a distributed system or workflow. Orchestration relies on a &lt;strong class="kw"&gt;central controller&lt;/strong&gt; that explicitly directs each step, while choreography lets services independently respond to &lt;strong class="kw"&gt;event reactions&lt;/strong&gt; with no single component in charge. The choice shapes coupling, visibility, and how easily the workflow evolves over time.&lt;/p&gt;
&lt;h2 id="comparison-diagram"&gt;Comparison Diagram&lt;/h2&gt;
&lt;div class="compare-diagram"&gt;
&lt;svg viewBox="0 0 640 360" xmlns="http://www.w3.org/2000/svg"&gt;&lt;defs&gt;&lt;marker id="arrowA" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse"&gt;&lt;path d="M0,0 L10,5 L0,10 z" style="fill:var(--compare-a)"/&gt;&lt;/marker&gt;&lt;marker id="arrowB" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse"&gt;&lt;path d="M0,0 L10,5 L0,10 z" style="fill:var(--compare-b)"/&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;line x1="320" y1="10" x2="320" y2="350" style="stroke:var(--border)" stroke-width="1.5" stroke-dasharray="4,4"/&gt;&lt;text x="160" y="28" text-anchor="middle" style="fill:var(--primary)" font-size="16" font-weight="bold"&gt;Orchestration&lt;/text&gt;&lt;text x="480" y="28" text-anchor="middle" style="fill:var(--primary)" font-size="16" font-weight="bold"&gt;Choreography&lt;/text&gt;&lt;rect x="110" y="150" width="100" height="50" rx="6" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="160" y="180" text-anchor="middle" style="fill:var(--content)" font-size="12"&gt;Orchestrator&lt;/text&gt;&lt;rect x="20" y="55" width="80" height="40" rx="6" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="60" y="80" text-anchor="middle" style="fill:var(--content)" font-size="11"&gt;Service A&lt;/text&gt;&lt;rect x="220" y="55" width="80" height="40" rx="6" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="260" y="80" text-anchor="middle" style="fill:var(--content)" font-size="11"&gt;Service B&lt;/text&gt;&lt;rect x="120" y="265" width="80" height="40" rx="6" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="160" y="290" text-anchor="middle" style="fill:var(--content)" font-size="11"&gt;Service C&lt;/text&gt;&lt;line x1="130" y1="150" x2="75" y2="97" style="stroke:var(--compare-a)" stroke-width="1.5" marker-end="url(#arrowA)"/&gt;&lt;line x1="190" y1="150" x2="245" y2="97" style="stroke:var(--compare-a)" stroke-width="1.5" marker-end="url(#arrowA)"/&gt;&lt;line x1="160" y1="200" x2="160" y2="263" style="stroke:var(--compare-a)" stroke-width="1.5" marker-end="url(#arrowA)"/&gt;&lt;text x="160" y="330" text-anchor="middle" style="fill:var(--secondary)" font-size="10"&gt;Central controller directs each step&lt;/text&gt;&lt;rect x="440" y="55" width="90" height="40" rx="6" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="485" y="80" text-anchor="middle" style="fill:var(--content)" font-size="11"&gt;Service X&lt;/text&gt;&lt;rect x="350" y="220" width="90" height="40" rx="6" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="395" y="245" text-anchor="middle" style="fill:var(--content)" font-size="11"&gt;Service Y&lt;/text&gt;&lt;rect x="520" y="220" width="90" height="40" rx="6" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="565" y="245" text-anchor="middle" style="fill:var(--content)" font-size="11"&gt;Service Z&lt;/text&gt;&lt;line x1="510" y1="92" x2="555" y2="222" style="stroke:var(--compare-b)" stroke-width="1.5" marker-end="url(#arrowB)"/&gt;&lt;line x1="520" y1="240" x2="440" y2="240" style="stroke:var(--compare-b)" stroke-width="1.5" marker-end="url(#arrowB)"/&gt;&lt;line x1="410" y1="222" x2="465" y2="92" style="stroke:var(--compare-b)" stroke-width="1.5" marker-end="url(#arrowB)"/&gt;&lt;text x="545" y="155" text-anchor="middle" style="fill:var(--secondary)" font-size="9"&gt;event&lt;/text&gt;&lt;text x="480" y="255" text-anchor="middle" style="fill:var(--secondary)" font-size="9"&gt;event&lt;/text&gt;&lt;text x="420" y="155" text-anchor="middle" style="fill:var(--secondary)" font-size="9"&gt;event&lt;/text&gt;&lt;text x="480" y="330" text-anchor="middle" style="fill:var(--secondary)" font-size="10"&gt;Services react to each other's events&lt;/text&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;h2 id="comparison-table"&gt;Comparison Table&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Orchestration&lt;/th&gt;
&lt;th&gt;Choreography&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Control flow&lt;/td&gt;
&lt;td&gt;A central orchestrator explicitly invokes and sequences each step&lt;/td&gt;
&lt;td&gt;Each service reacts to events independently; no component sequences the whole flow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coupling&lt;/td&gt;
&lt;td&gt;Services couple to the orchestrator&amp;rsquo;s contract, not to each other&lt;/td&gt;
&lt;td&gt;Services couple to shared event schemas rather than a controller&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workflow knowledge&lt;/td&gt;
&lt;td&gt;Orchestrator holds the full picture; services only know their own task&lt;/td&gt;
&lt;td&gt;No single component knows the entire workflow, only its trigger and reaction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failure handling&lt;/td&gt;
&lt;td&gt;Retries and compensation logic live centrally in the orchestrator&lt;/td&gt;
&lt;td&gt;Compensation is distributed, with services reacting to failure events themselves&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adding new steps&lt;/td&gt;
&lt;td&gt;Requires modifying the orchestrator to include the new call&lt;/td&gt;
&lt;td&gt;A new service just subscribes to existing events with no central change&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Observability&lt;/td&gt;
&lt;td&gt;Single place to trace and inspect current workflow state&lt;/td&gt;
&lt;td&gt;Requires aggregating distributed logs and traces across services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failure/scaling risk&lt;/td&gt;
&lt;td&gt;Orchestrator can become a bottleneck or single point of failure&lt;/td&gt;
&lt;td&gt;Overall flow becomes hard to see, risking uncoordinated &amp;rsquo;event sprawl'&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical tooling&lt;/td&gt;
&lt;td&gt;BPMN engines, AWS Step Functions, Temporal, Camunda&lt;/td&gt;
&lt;td&gt;Message brokers and event buses like Kafka, SNS/SQS, domain events&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="key-differences"&gt;Key Differences&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Orchestration uses a &lt;strong class="kw"&gt;central controller&lt;/strong&gt;; choreography relies on services reacting to &lt;strong class="kw"&gt;events&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Orchestration couples services to the controller; choreography couples them to &lt;strong class="kw"&gt;event contracts&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Extending orchestration means &lt;strong class="kw"&gt;updating the orchestrator&lt;/strong&gt;; extending choreography just means subscribing to events&lt;/li&gt;
&lt;li&gt;Orchestration gives &lt;strong class="kw"&gt;centralized visibility&lt;/strong&gt;; choreography requires &lt;strong class="kw"&gt;distributed tracing&lt;/strong&gt; to see the full flow&lt;/li&gt;
&lt;li&gt;Orchestration risks a bottleneck at the controller; choreography risks &lt;strong class="kw"&gt;workflow sprawl&lt;/strong&gt; across services&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="when-to-use-each"&gt;When to Use Each&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Orchestration&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Monolith vs Microservices: Architecture Comparison</title><link>https://comparison.metacog.co.kr/posts/2026-08-04-monolith-vs-microservices-architecture-comparison/</link><pubDate>Tue, 04 Aug 2026 05:06:36 +0900</pubDate><guid>https://comparison.metacog.co.kr/posts/2026-08-04-monolith-vs-microservices-architecture-comparison/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;Monolithic architecture packages an entire application as a single &lt;strong class="kw"&gt;deployable unit&lt;/strong&gt;, while microservices architecture splits it into independently deployable &lt;strong class="kw"&gt;distributed services&lt;/strong&gt;. The choice shapes everything from how teams organize their work to how failures propagate and how the system scales under load.&lt;/p&gt;
&lt;h2 id="comparison-diagram"&gt;Comparison Diagram&lt;/h2&gt;
&lt;div class="compare-diagram"&gt;
&lt;svg viewBox="0 0 640 360" xmlns="http://www.w3.org/2000/svg"&gt;
&lt;text x="160" y="30" text-anchor="middle" font-size="18" font-weight="600" style="fill:var(--primary)"&gt;Monolith&lt;/text&gt;
&lt;text x="480" y="30" text-anchor="middle" font-size="18" font-weight="600" style="fill:var(--primary)"&gt;Microservices&lt;/text&gt;
&lt;rect x="60" y="55" width="200" height="205" rx="6" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;
&lt;line x1="60" y1="123" x2="260" y2="123" style="stroke:var(--border)" stroke-width="1" stroke-dasharray="4,3"/&gt;
&lt;line x1="60" y1="191" x2="260" y2="191" style="stroke:var(--border)" stroke-width="1" stroke-dasharray="4,3"/&gt;
&lt;text x="160" y="93" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;UI Layer&lt;/text&gt;
&lt;text x="160" y="161" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;Business Logic&lt;/text&gt;
&lt;text x="160" y="229" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;Data Access&lt;/text&gt;
&lt;line x1="160" y1="260" x2="160" y2="280" style="stroke:var(--compare-a)" stroke-width="1.5"/&gt;
&lt;rect x="110" y="280" width="100" height="36" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;
&lt;text x="160" y="302" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;Shared DB&lt;/text&gt;
&lt;text x="160" y="340" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;single deployable unit&lt;/text&gt;
&lt;rect x="430" y="55" width="100" height="30" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;
&lt;text x="480" y="75" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;API Gateway&lt;/text&gt;
&lt;line x1="480" y1="85" x2="420" y2="128" style="stroke:var(--compare-b)" stroke-width="1.5" stroke-dasharray="4,3"/&gt;
&lt;line x1="480" y1="85" x2="520" y2="128" style="stroke:var(--compare-b)" stroke-width="1.5" stroke-dasharray="4,3"/&gt;
&lt;rect x="380" y="128" width="80" height="50" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;
&lt;text x="420" y="157" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;Orders&lt;/text&gt;
&lt;rect x="480" y="128" width="80" height="50" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;
&lt;text x="520" y="157" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;Users&lt;/text&gt;
&lt;line x1="420" y1="178" x2="420" y2="212" style="stroke:var(--compare-b)" stroke-width="1.5" stroke-dasharray="4,3"/&gt;
&lt;line x1="520" y1="178" x2="520" y2="212" style="stroke:var(--compare-b)" stroke-width="1.5" stroke-dasharray="4,3"/&gt;
&lt;line x1="460" y1="153" x2="480" y2="153" style="stroke:var(--compare-b)" stroke-width="1.5" stroke-dasharray="4,3"/&gt;
&lt;rect x="380" y="212" width="80" height="50" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;
&lt;text x="420" y="241" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;Payments&lt;/text&gt;
&lt;rect x="480" y="212" width="80" height="50" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;
&lt;text x="520" y="241" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;Inventory&lt;/text&gt;
&lt;rect x="380" y="180" width="32" height="14" rx="2" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1"/&gt;
&lt;text x="396" y="190" text-anchor="middle" font-size="8" style="fill:var(--secondary)"&gt;db&lt;/text&gt;
&lt;rect x="528" y="180" width="32" height="14" rx="2" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1"/&gt;
&lt;text x="544" y="190" text-anchor="middle" font-size="8" style="fill:var(--secondary)"&gt;db&lt;/text&gt;
&lt;rect x="380" y="264" width="32" height="14" rx="2" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1"/&gt;
&lt;text x="396" y="274" text-anchor="middle" font-size="8" style="fill:var(--secondary)"&gt;db&lt;/text&gt;
&lt;rect x="528" y="264" width="32" height="14" rx="2" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1"/&gt;
&lt;text x="544" y="274" text-anchor="middle" font-size="8" style="fill:var(--secondary)"&gt;db&lt;/text&gt;
&lt;text x="480" y="340" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;independent, own datastores&lt;/text&gt;
&lt;/svg&gt;
&lt;/div&gt;
&lt;h2 id="comparison-table"&gt;Comparison Table&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Monolithic Architecture&lt;/th&gt;
&lt;th&gt;Microservices Architecture&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Deployment unit&lt;/td&gt;
&lt;td&gt;Single deployable artifact containing all modules&lt;/td&gt;
&lt;td&gt;Multiple independently deployable services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inter-component communication&lt;/td&gt;
&lt;td&gt;In-process function calls&lt;/td&gt;
&lt;td&gt;Network calls (REST, gRPC, or messaging)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data storage&lt;/td&gt;
&lt;td&gt;Typically one shared database&lt;/td&gt;
&lt;td&gt;Each service owns and manages its own database&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scaling approach&lt;/td&gt;
&lt;td&gt;Scale the entire application as one unit&lt;/td&gt;
&lt;td&gt;Scale individual services independently based on load&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fault isolation&lt;/td&gt;
&lt;td&gt;A bug or crash can bring down the whole application&lt;/td&gt;
&lt;td&gt;Failures can be isolated to a single service when designed well&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Release and deployment process&lt;/td&gt;
&lt;td&gt;Single build/deploy pipeline with coordinated releases&lt;/td&gt;
&lt;td&gt;Independent CI/CD pipeline per service, deployed on its own schedule&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Technology stack flexibility&lt;/td&gt;
&lt;td&gt;One language and framework for the entire app&lt;/td&gt;
&lt;td&gt;Polyglot — each service can pick its own stack&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operational overhead&lt;/td&gt;
&lt;td&gt;Low — one application to host and monitor&lt;/td&gt;
&lt;td&gt;High — requires service discovery, orchestration, and distributed tracing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="key-differences"&gt;Key Differences&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Monolith code runs as a single process; microservices communicate as &lt;strong class="kw"&gt;independent processes&lt;/strong&gt; over the network.&lt;/li&gt;
&lt;li&gt;A monolith centers on one &lt;strong class="kw"&gt;shared database&lt;/strong&gt;, while microservices decentralize data ownership per service.&lt;/li&gt;
&lt;li&gt;Microservices allow &lt;strong class="kw"&gt;granular scaling&lt;/strong&gt; of just the components under load, unlike a monolith that scales as a whole.&lt;/li&gt;
&lt;li&gt;Splitting into services buys better fault containment but introduces real &lt;strong class="kw"&gt;operational complexity&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Well-designed microservices offer stronger &lt;strong class="kw"&gt;fault isolation&lt;/strong&gt; than a monolith, where one bug can crash everything.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="when-to-use-each"&gt;When to Use Each&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Monolithic Architecture&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Sidecar Pattern vs Ambassador Pattern: General-Purpose Helper vs Network Proxy</title><link>https://comparison.metacog.co.kr/posts/2026-08-03-sidecar-pattern-vs-ambassador-pattern-general-purpose-helper/</link><pubDate>Mon, 03 Aug 2026 05:32:13 +0900</pubDate><guid>https://comparison.metacog.co.kr/posts/2026-08-03-sidecar-pattern-vs-ambassador-pattern-general-purpose-helper/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;The &lt;strong class="kw"&gt;Sidecar Pattern&lt;/strong&gt; is the general technique of running a helper container alongside your app in the same pod to add any cross-cutting capability — logging, metrics, config sync, or a mesh proxy. The &lt;strong class="kw"&gt;Ambassador Pattern&lt;/strong&gt; is a specific flavor of that sidecar dedicated to one job: sitting between the app and the network, so the app talks to localhost while the ambassador handles the real, often messy, connection to an external service.&lt;/p&gt;</description></item><item><title>Service Mesh vs API Gateway: North-South vs East-West Traffic</title><link>https://comparison.metacog.co.kr/posts/2026-08-03-service-mesh-vs-api-gateway-north-south-vs-east-west-traffic/</link><pubDate>Mon, 03 Aug 2026 05:19:35 +0900</pubDate><guid>https://comparison.metacog.co.kr/posts/2026-08-03-service-mesh-vs-api-gateway-north-south-vs-east-west-traffic/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;An &lt;strong class="kw"&gt;API gateway&lt;/strong&gt; sits at the edge of your system, managing traffic between external clients and your services. A &lt;strong class="kw"&gt;service mesh&lt;/strong&gt; operates inside the cluster, managing traffic between services themselves. Confusing the two leads teams to either duplicate cross-cutting concerns or push edge-only features into infrastructure that was never designed for public-facing traffic.&lt;/p&gt;
&lt;h2 id="comparison-diagram"&gt;Comparison Diagram&lt;/h2&gt;
&lt;div class="compare-diagram"&gt;
&lt;svg viewBox="0 0 640 360" xmlns="http://www.w3.org/2000/svg"&gt;&lt;text x="235" y="24" text-anchor="middle" font-size="16" font-weight="bold" style="fill:var(--compare-a)"&gt;API Gateway&lt;/text&gt;&lt;text x="480" y="24" text-anchor="middle" font-size="16" font-weight="bold" style="fill:var(--compare-b)"&gt;Service Mesh&lt;/text&gt;&lt;rect x="20" y="160" width="80" height="50" rx="6" style="fill:none;stroke:var(--content)" stroke-width="1.5"/&gt;&lt;text x="60" y="190" text-anchor="middle" font-size="13" style="fill:var(--content)"&gt;Client&lt;/text&gt;&lt;line x1="100" y1="185" x2="165" y2="185" style="stroke:var(--content)" stroke-width="1.5"/&gt;&lt;polygon points="165,180 175,185 165,190" style="fill:var(--content)"/&gt;&lt;rect x="175" y="130" width="120" height="110" rx="8" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="235" y="158" text-anchor="middle" font-size="12" font-weight="bold" style="fill:var(--compare-a)"&gt;API Gateway&lt;/text&gt;&lt;text x="235" y="178" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;authN · rate limit&lt;/text&gt;&lt;text x="235" y="194" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;routing · transform&lt;/text&gt;&lt;line x1="295" y1="185" x2="335" y2="185" style="stroke:var(--content)" stroke-width="1.5"/&gt;&lt;polygon points="335,180 345,185 335,190" style="fill:var(--content)"/&gt;&lt;rect x="345" y="45" width="270" height="280" rx="10" style="fill:none;stroke:var(--border)" stroke-width="1.5" stroke-dasharray="6,4"/&gt;&lt;text x="480" y="64" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;cluster&lt;/text&gt;&lt;rect x="380" y="85" width="90" height="45" rx="6" style="fill:none;stroke:var(--content)" stroke-width="1.5"/&gt;&lt;text x="425" y="111" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;Service A&lt;/text&gt;&lt;rect x="475" y="95" width="22" height="22" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;rect x="380" y="165" width="90" height="45" rx="6" style="fill:none;stroke:var(--content)" stroke-width="1.5"/&gt;&lt;text x="425" y="191" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;Service B&lt;/text&gt;&lt;rect x="475" y="175" width="22" height="22" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;rect x="380" y="245" width="90" height="45" rx="6" style="fill:none;stroke:var(--content)" stroke-width="1.5"/&gt;&lt;text x="425" y="271" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;Service C&lt;/text&gt;&lt;rect x="475" y="255" width="22" height="22" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;line x1="497" y1="106" x2="497" y2="186" style="stroke:var(--compare-b)" stroke-width="1.5" stroke-dasharray="4,3"/&gt;&lt;line x1="497" y1="186" x2="497" y2="266" style="stroke:var(--compare-b)" stroke-width="1.5" stroke-dasharray="4,3"/&gt;&lt;path d="M497,106 C560,150 560,220 497,266" style="fill:none;stroke:var(--compare-b)" stroke-width="1.5" stroke-dasharray="4,3"/&gt;&lt;text x="600" y="100" text-anchor="end" font-size="10" style="fill:var(--secondary)"&gt;sidecar proxy&lt;/text&gt;&lt;text x="600" y="196" text-anchor="end" font-size="10" style="fill:var(--secondary)"&gt;mTLS · retries&lt;/text&gt;&lt;text x="235" y="345" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;north–south: client-to-service&lt;/text&gt;&lt;text x="480" y="345" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;east–west: service-to-service&lt;/text&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;h2 id="comparison-table"&gt;Comparison Table&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;API Gateway&lt;/th&gt;
&lt;th&gt;Service Mesh&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Traffic direction&lt;/td&gt;
&lt;td&gt;North-south: external clients entering the system&lt;/td&gt;
&lt;td&gt;East-west: internal service-to-service calls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment topology&lt;/td&gt;
&lt;td&gt;Centralized cluster of edge instances fronting all traffic&lt;/td&gt;
&lt;td&gt;Sidecar proxy injected alongside every service instance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Primary concerns&lt;/td&gt;
&lt;td&gt;AuthN/authZ, rate limiting, request/response transformation, API versioning&lt;/td&gt;
&lt;td&gt;mTLS, load balancing, retries, circuit breaking between services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Routing basis&lt;/td&gt;
&lt;td&gt;Public API path, host, or version mapped to a backend service&lt;/td&gt;
&lt;td&gt;Service identity and destination within the internal network&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Observability scope&lt;/td&gt;
&lt;td&gt;Per-endpoint metrics: request volume, latency, errors by client&lt;/td&gt;
&lt;td&gt;Full service dependency graph: per-hop latency and error rates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failure containment&lt;/td&gt;
&lt;td&gt;Blocks or throttles bad traffic before it reaches any backend&lt;/td&gt;
&lt;td&gt;Isolates failures at individual hops so one bad service doesn&amp;rsquo;t cascade&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operational overhead&lt;/td&gt;
&lt;td&gt;Few instances to scale and configure centrally&lt;/td&gt;
&lt;td&gt;One proxy per workload, plus a control plane to manage them all&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="key-differences"&gt;Key Differences&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;An &lt;strong class="kw"&gt;API gateway&lt;/strong&gt; is the single entry point clients hit; a &lt;strong class="kw"&gt;service mesh&lt;/strong&gt; has no single entry point, it&amp;rsquo;s woven through every service.&lt;/li&gt;
&lt;li&gt;Gateways enforce policy once at the edge; meshes enforce policy per &lt;strong class="kw"&gt;sidecar&lt;/strong&gt; on every call.&lt;/li&gt;
&lt;li&gt;Gateways typically run as a small number of centralized instances; meshes scale linearly with your &lt;strong class="kw"&gt;service count&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Meshes give you &lt;strong class="kw"&gt;mTLS&lt;/strong&gt; and retries between internal services, something a gateway never sees because that traffic never reaches it.&lt;/li&gt;
&lt;li&gt;Many production systems run both together, not as alternatives, since they solve problems at different layers.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="when-to-use-each"&gt;When to Use Each&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;API Gateway&lt;/strong&gt;&lt;/p&gt;</description></item></channel></rss>