<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Stacked]]></title><description><![CDATA[In this blog, you will learn how Spring Boot simplifies Java backend development and helps you ship production-ready applications faster. You will understand co]]></description><link>https://stacked.hashnode.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1757660164754/3ab2bd42-adb5-4659-99dc-2f32b3932176.png</url><title>Stacked</title><link>https://stacked.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Thu, 29 Oct 2026 16:38:25 GMT</lastBuildDate><atom:link href="https://stacked.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Go vs Java Spring Boot: Benchmarking CPU Performance, Latency, Throughput, and Memory]]></title><description><![CDATA[An experimental comparison using Go, Spring Boot, k6, and a 12-core-CPU Ubuntu machine.]]></description><link>https://stacked.hashnode.dev/go-vs-java-spring-boot-benchmarking-cpu-performance-latency-throughput-and-memory</link><guid isPermaLink="true">https://stacked.hashnode.dev/go-vs-java-spring-boot-benchmarking-cpu-performance-latency-throughput-and-memory</guid><category><![CDATA[Java]]></category><category><![CDATA[Springboot]]></category><category><![CDATA[Grafana]]></category><category><![CDATA[Go Language]]></category><category><![CDATA[golang]]></category><dc:creator><![CDATA[Stacked]]></dc:creator><pubDate>Wed, 21 Oct 2026 15:37:30 GMT</pubDate><content:encoded><![CDATA[<h1>Go vs Java Spring Boot: Benchmarking CPU Performance, Latency, Throughput, and Memory</h1>
<h2>Introduction</h2>
<p>Go and Java are both widely used for building backend services, but they approach application development and runtime execution differently.</p>
<p>Go is known for its lightweight runtime, fast compilation, and straightforward concurrency model. Java, particularly with Spring Boot, offers a mature ecosystem, a powerful JVM, and extensive support for building production-grade backend applications.</p>
<p>I wanted to move beyond general opinions about which language is faster and run a small benchmark of my own.</p>
<p>The objective was to compare Go and Java Spring Boot under CPU-intensive workloads and observe how their response times, throughput, CPU consumption, and memory footprints behaved as concurrency increased.</p>
<p>This was not an attempt to prove that one language is universally better. It was an experiment to understand how two implementations behaved under a specific workload and testing environment.</p>
<h2>1. Benchmark Environment</h2>
<p>Both applications were tested on the same Ubuntu machine with 12 logical CPUs.</p>
<table>
<thead>
<tr>
<th>Component</th>
<th>Configuration</th>
</tr>
</thead>
<tbody><tr>
<td>Operating system</td>
<td>Ubuntu Linux</td>
</tr>
<tr>
<td>Available logical CPUs</td>
<td>12</td>
</tr>
<tr>
<td>Go API</td>
<td>Go HTTP server</td>
</tr>
<tr>
<td>Java API</td>
<td>Java Spring Boot</td>
</tr>
<tr>
<td>Load-testing tool</td>
<td>k6</td>
</tr>
<tr>
<td>Go endpoint</td>
<td><code>http://localhost:7000/compute?n=1000000</code></td>
</tr>
<tr>
<td>Java endpoint</td>
<td><code>http://localhost:8000/compute?n=1000000</code></td>
</tr>
<tr>
<td>Workload</td>
<td>CPU-intensive prime counting</td>
</tr>
<tr>
<td>Concurrency levels</td>
<td>10, 25, 50, and 100 virtual users</td>
</tr>
</tbody></table>
<p>Both APIs implemented the same prime-counting algorithm. The Go service ran on port 7000, while the Spring Boot service ran on port 8000.</p>
<p>An important limitation of this setup is that the load generator and both backend applications ran on the same machine. Consequently, the results reflect not only backend performance but also competition for CPU resources between k6 and the applications.</p>
<h2>2. The Workload: Counting Prime Numbers</h2>
<p>I chose a computational workload rather than a database-backed API because I wanted to examine CPU-intensive request processing without introducing database query performance, network latency, or external service dependencies.</p>
<p>The endpoint calculated the number of prime numbers up to 1,000,000 using trial division.</p>
<p>The implementation skipped even numbers and tested potential divisors up to the square root of each candidate number.</p>
<p>Both implementations returned the same expected result:</p>
<pre><code class="language-json">{
  "n": 1000000,
  "primeCount": 78498
}
</code></pre>
<p>This correctness check was important. A faster implementation would not be meaningful if it performed less work or returned an incorrect answer.</p>
<p>For an initial single-request test with a smaller input of 500,000, Go returned 41,538 primes in approximately 21.74 ms, while Java returned the same count in approximately 19.62 ms.</p>
<p>These initial timings were useful for validating the implementations, but the more interesting observations came from concurrent load testing.</p>
<h2>3. How I Tested the APIs</h2>
<p>I used k6 to simulate concurrent users sending requests to each service.</p>
<p>The test ran the Go scenario first and started the Java scenario approximately 35 seconds later. Each request checked the HTTP status, validated the JSON response, and verified the expected prime count.</p>
<p>The script also recorded two types of latency:</p>
<ul>
<li><p>HTTP request duration, which includes the overall request-response time.</p>
</li>
<li><p>Application-reported computation time, measured around the prime-counting operation.</p>
</li>
</ul>
<p>A short sleep of 100 milliseconds was included after each request.</p>
<p>The virtual-user counts were increased across separate test runs: 10, 25, 50, and 100.</p>
<p>The main metrics were average latency, median latency, p95 latency, request throughput, HTTP errors, and process resource usage.</p>
<p>The distinction between median and p95 matters. The median represents the middle request, while p95 indicates the latency below which 95% of measured requests completed. A system can have a reasonable median while still experiencing substantially slower requests in the tail.</p>
<h2>4. Results: CPU Computation Time</h2>
<p>The following table contains the application-reported computation times from the load tests.</p>
<table>
<thead>
<tr>
<th>Virtual users</th>
<th>Go average</th>
<th>Java average</th>
<th>Go p95</th>
<th>Java p95</th>
</tr>
</thead>
<tbody><tr>
<td>10</td>
<td>59.53 ms</td>
<td>55.24 ms</td>
<td>70.86 ms</td>
<td>64.15 ms</td>
</tr>
<tr>
<td>25</td>
<td>129.25 ms</td>
<td>123.96 ms</td>
<td>164.47 ms</td>
<td>186.77 ms</td>
</tr>
<tr>
<td>50</td>
<td>327.69 ms</td>
<td>327.85 ms</td>
<td>412.28 ms</td>
<td>563.69 ms</td>
</tr>
<tr>
<td>100</td>
<td>715.82 ms</td>
<td>752.11 ms</td>
<td>926.60 ms</td>
<td>1,369.85 ms</td>
</tr>
</tbody></table>
<h3>What I observed</h3>
<p>At 10 virtual users, Java had a lower average computation time than Go. The same was true at 25 virtual users, although Java's p95 was higher than Go's at that concurrency level.</p>
<p>At 50 virtual users, both implementations had nearly identical average computation times. However, Java showed a substantially higher p95.</p>
<p>At 100 virtual users, Go had a lower average computation time and a lower p95 than Java.</p>
<p>The 100-user test showed:</p>
<ul>
<li><p>Go average computation time: 715.82 ms</p>
</li>
<li><p>Java average computation time: 752.11 ms</p>
</li>
<li><p>Go p95 computation time: 926.60 ms</p>
</li>
<li><p>Java p95 computation time: 1,369.85 ms</p>
</li>
</ul>
<p>In this particular run, Go's average computation time was approximately 4.8% lower than Java's. Its p95 was approximately 32.3% lower.</p>
<p>However, these are observations from individual test runs, not statistically established performance differences. JVM warm-up, operating-system scheduling, garbage collection, and competition for CPU resources can affect results. Repeated, controlled experiments are necessary before drawing stronger conclusions.</p>
<h2>5. Results: HTTP Request Latency</h2>
<p>Application computation time does not capture the entire request lifecycle. I therefore compared the HTTP request durations reported by k6.</p>
<table>
<thead>
<tr>
<th>Virtual users</th>
<th>Go average</th>
<th>Java average</th>
<th>Go p95</th>
<th>Java p95</th>
</tr>
</thead>
<tbody><tr>
<td>10</td>
<td>59.75 ms</td>
<td>55.96 ms</td>
<td>71.09 ms</td>
<td>64.96 ms</td>
</tr>
<tr>
<td>25</td>
<td>135.16 ms</td>
<td>126.25 ms</td>
<td>172.81 ms</td>
<td>189.05 ms</td>
</tr>
<tr>
<td>50</td>
<td>372.34 ms</td>
<td>333.80 ms</td>
<td>458.71 ms</td>
<td>573.36 ms</td>
</tr>
<tr>
<td>100</td>
<td>839.44 ms</td>
<td>771.52 ms</td>
<td>Approximately 1.06 s</td>
<td>Approximately 1.40 s</td>
</tr>
</tbody></table>
<p>The pattern was not entirely consistent.</p>
<p>Java had lower average HTTP latency in all four runs. Go had a lower p95 at 25, 50, and 100 virtual users, while Java had a lower p95 at 10 virtual users.</p>
<p>This distinction is worth highlighting. A lower average does not necessarily mean better tail latency. Evaluate backend performance using multiple latency metrics rather than a single number.</p>
<p>At 100 virtual users, the results suggest that Go handled the tail of the observed workload better, while Java retained a lower average HTTP request duration.</p>
<p>Neither observation alone establishes a universal performance advantage.</p>
<h2>6. Results: Throughput</h2>
<p>Throughput indicates how many requests a service processes per second during the test.</p>
<table>
<thead>
<tr>
<th>Virtual users</th>
<th>Go requests/sec</th>
<th>Java requests/sec</th>
</tr>
</thead>
<tbody><tr>
<td>10</td>
<td>28.78</td>
<td>29.44</td>
</tr>
<tr>
<td>25</td>
<td>48.93</td>
<td>50.78</td>
</tr>
<tr>
<td>50</td>
<td>48.91</td>
<td>53.06</td>
</tr>
<tr>
<td>100</td>
<td>49.25</td>
<td>52.89</td>
</tr>
</tbody></table>
<p>Java recorded slightly higher throughput at every tested concurrency level.</p>
<p>At 100 virtual users, the measured rates were approximately 49.25 requests per second for Go and 52.89 requests per second for Java.</p>
<p>That is approximately 7.4% higher throughput for Java in this run.</p>
<p>However, throughput increased much less between 25 and 100 virtual users than it did between 10 and 25. This suggests that the test setup was approaching a resource or execution bottleneck.</p>
<p>The combined throughput of both sequential scenarios was approximately 102 requests per second in the 100-user run. This combined figure should not be treated as the capacity of either individual service.</p>
<p>The throughput results also need context. Because k6 and both APIs shared the same host, the load generator competed with the services for CPU time. These figures therefore describe this local experiment, not the maximum throughput the applications could achieve on dedicated servers.</p>
<h2>7. What Happened at Higher Concurrency?</h2>
<p>The latency results became more interesting as I increased the number of virtual users.</p>
<p>At 10 virtual users, average HTTP latency was around 56 to 60 milliseconds. At 100 virtual users, it rose to about 772-839 milliseconds.</p>
<p>The CPU-intensive operation remained the same. What changed was the number of requests competing to execute that operation.</p>
<p>A trial-division prime-counting algorithm performs substantial CPU work for each request. When many requests arrive concurrently, they compete for available CPU time. Increasing concurrency does not automatically increase throughput because the machine has finite processing capacity.</p>
<p>During an earlier system-level observation using <code>mpstat</code>, total CPU utilization was approximately 98%, with only around 0.25% idle time. All 12 logical CPUs were heavily utilized.</p>
<p>This is evidence that the machine was close to CPU saturation during that observation.</p>
<p>Once the CPU is saturated, adding more virtual users can increase the number of requests waiting for execution without producing a proportional increase in completed requests per second.</p>
<p>The results illustrate an important performance-engineering principle: concurrency and throughput are related, but they are not interchangeable.</p>
<h2>8. CPU Usage: An Important Measurement Caveat</h2>
<p>I also used <code>pidstat</code> to observe the backend processes.</p>
<p>The captured output included the following average values across the entire sampling period:</p>
<table>
<thead>
<tr>
<th>Metric</th>
<th>Go process</th>
<th>Java process</th>
</tr>
</thead>
<tbody><tr>
<td>Reported average CPU</td>
<td>492.49%</td>
<td>524.36%</td>
</tr>
<tr>
<td>Average resident memory (RSS)</td>
<td>Approximately 18.2 MiB</td>
<td>Approximately 201.4 MiB</td>
</tr>
<tr>
<td>Average virtual address space (VSZ)</td>
<td>Approximately 2.32 GiB</td>
<td>Approximately 15.24 GiB</td>
</tr>
</tbody></table>
<p>On Linux, process CPU utilization can exceed 100% because 100% represents one fully utilized logical CPU in this reporting convention. A process using roughly 1,100% CPU is consuming approximately 11 logical CPUs' worth of processing time.</p>
<p>However, the average CPU figures above must not be interpreted as evidence that Go uses less CPU per request.</p>
<p>The two processes were primarily active during different portions of the sequential test. Their averages included periods when they were idle. This makes the overall averages unsuitable for a direct comparison of CPU efficiency.</p>
<p>A more rigorous comparison would collect CPU samples only during each service's active load window, preferably with k6 running on a separate machine. It would also compare CPU time per completed request, alongside throughput and latency.</p>
<p>The resource measurements are useful as an initial observation, but they do not yet establish which implementation is more CPU-efficient.</p>
<h2>9. Memory Usage: The Clearest Difference in This Experiment</h2>
<p>The most pronounced difference in my process measurements was resident memory.</p>
<p>The Go process averaged approximately 18.2 MiB of RSS, compared with approximately 201.4 MiB for the Java Spring Boot process.</p>
<p>That is roughly an elevenfold difference in resident memory for these specific implementations.</p>
<p>RSS, or resident set size, represents the physical memory currently resident for a process. VSZ, or virtual size, represents its virtual address space and should not be interpreted as physical RAM consumption.</p>
<p>This difference is plausible because a minimal Go HTTP server and a Spring Boot application have different runtime architectures. The Java process includes the JVM and the Spring Boot application stack, along with the associated framework and runtime overhead.</p>
<p>Nevertheless, this result is specific to the applications and configurations tested. It does not mean that every Go service will use one-eleventh the memory of every Java service.</p>
<p>A production comparison would need equivalent functionality, representative dependencies, consistent runtime configurations, and measurements taken after the applications have reached stable operating conditions.</p>
<p>Even with those qualifications, the measurements demonstrate why memory footprint can be an important factor when selecting a runtime for resource-constrained environments.</p>
<h2>10. What This Benchmark Does Not Prove</h2>
<p>A benchmark is only as useful as the conclusions supported by its methodology.</p>
<p>There are several limitations to this experiment.</p>
<p>First, the load generator and both APIs ran on the same machine. CPU contention could affect application latency, throughput, and scheduling.</p>
<p>Second, the Go and Java scenarios ran sequentially. Differences in JVM warm-up, host temperature, background processes, and other system conditions could influence the results.</p>
<p>Third, each reported concurrency level represents a single run in the measurements available for this comparison. There are no repeated-run confidence intervals, so small differences should not be treated as definitive.</p>
<p>Fourth, this is a CPU-intensive synthetic workload. It does not represent every backend application. A real API may spend substantial time waiting for a database, Redis, an external HTTP service, or disk I/O.</p>
<p>Fifth, the reported computation time is elapsed wall-clock time around the calculation. It is not a direct measurement of CPU execution time. When a process is descheduled, its elapsed time can increase even though it is not actively using the CPU.</p>
<p>Finally, this experiment does not compare garbage collection behavior, startup time, throughput under database load, memory growth over long periods, or performance after JVM warm-up and optimization.</p>
<p>These limitations do not make the benchmark useless. They define what it can reasonably tell us.</p>
<h2>11. How I Would Improve the Benchmark</h2>
<p>My next iteration would focus on reducing measurement noise and collecting more useful resource metrics.</p>
<ol>
<li><p><strong>Separate the load generator.</strong> Run k6 on another machine so that the backend has more of the test host's CPU capacity available.</p>
</li>
<li><p><strong>Run one backend at a time.</strong> Test Go and Java independently under identical conditions.</p>
</li>
<li><p><strong>Warm up the JVM.</strong> Send warm-up requests before collecting Java measurements and ensure the measurement period is long enough for stable behavior.</p>
</li>
<li><p><strong>Repeat each test.</strong> Run each concurrency level at least three to five times and compare the median results across runs.</p>
</li>
<li><p><strong>Measure CPU time per request.</strong> Capture process CPU usage during the active interval and divide CPU consumption by successfully completed requests.</p>
</li>
<li><p><strong>Record more latency percentiles.</strong> Collect p50, p95, and p99 rather than relying on average latency alone.</p>
</li>
<li><p><strong>Measure memory over time.</strong> Track RSS during warm-up and steady-state operation, not just an average across a mixed period.</p>
</li>
<li><p><strong>Test more realistic workloads.</strong> Add database-backed endpoints, JSON serialization, concurrent I/O, and representative application dependencies.</p>
</li>
<li><p><strong>Verify the same conditions.</strong> Keep the algorithm, response payload, request rate or concurrency model, timeout settings, and application behavior equivalent.</p>
</li>
</ol>
<p>This would provide a stronger basis for evaluating the trade-offs between Go and Java Spring Boot.</p>
<h2>12. Final Verdict</h2>
<p>Based on the measurements from this experiment, there is no universal winner.</p>
<p>Go showed lower average computation time and lower p95 computation latency in the 100-virtual-user run. Java recorded slightly higher throughput and lower average HTTP request latency across the tested concurrency levels.</p>
<p>The process measurements also showed a substantially smaller resident memory footprint for the Go implementation. The CPU averages, however, were collected across sequential active and idle periods and cannot establish that Go uses less CPU per request.</p>
<p>The most useful conclusion is that runtime performance depends on the workload, implementation, framework, resource allocation, and measurement methodology.</p>
<p>Go may be attractive when a small memory footprint and straightforward concurrent services are priorities. Java Spring Boot may be attractive when its mature ecosystem, framework capabilities, and integration with existing enterprise systems are important.</p>
<p>For a production decision, I would use these results as a starting point rather than a final verdict. I would first repeat the benchmark with an isolated load generator, warmed-up applications, and active-window CPU measurements.</p>
<p>The goal of benchmarking is not to find a language that wins every test. It is to gather enough reliable evidence to choose the right tool for a specific engineering problem.</p>
<h2>Closing Thoughts</h2>
<p>This experiment reminded me that measuring performance is more demanding than simply sending more requests and comparing two averages.</p>
<p>A meaningful benchmark requires correctness checks, repeatable conditions, resource monitoring, and a clear understanding of what each metric represents.</p>
<p>The initial results are useful, particularly the memory-footprint difference and the changes in latency under higher concurrency. But the next step is to improve the experimental design and determine which differences remain after controlling for system-level contention.</p>
<p>That is the part of performance engineering I find most valuable: not just collecting numbers, but understanding what those numbers actually mean.</p>
<hr />
<p><em>Benchmark note: Results were collected from local tests on a 12-logical-CPU Ubuntu machine using k6, a Go HTTP API, and a Java Spring Boot API. Both applications and the load generator shared the same machine. Results represent individual test runs and should not be interpreted as universal language-performance rankings.</em></p>
]]></content:encoded></item><item><title><![CDATA[Stop Paginating Like It’s 2010]]></title><description><![CDATA[The Scalable Pagination Strategy Every Spring Boot Developer Should Know]]></description><link>https://stacked.hashnode.dev/stop-paginating-like-its-2010</link><guid isPermaLink="true">https://stacked.hashnode.dev/stop-paginating-like-its-2010</guid><category><![CDATA[Pagination]]></category><category><![CDATA[System Design]]></category><category><![CDATA[backend]]></category><category><![CDATA[performance]]></category><category><![CDATA[Performance Optimization]]></category><category><![CDATA[Springboot]]></category><category><![CDATA[Java]]></category><category><![CDATA[Kotlin]]></category><dc:creator><![CDATA[Stacked]]></dc:creator><pubDate>Sat, 24 Jan 2026 16:01:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1769270356876/13cb33e6-6b03-4b69-927f-a4057f327a32.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<hr />
<p>When building applications with scaling datasets, the choice of pagination isn't just a minor implementation detail; it is a <strong>performance-defining decision</strong>. Like many developers, I initially fell into the "good enough" trap by relying on <strong>OFFSET pagination</strong>, largely because Spring Data JPA makes it so deceptively easy to implement. While it worked flawlessly in the low-pressure environment of development, the illusion shattered once I subjected the system to millions of rows during load testing. I watched as query latency spiked in direct proportion to page depth, while CPU and I/O utilization climbed to unsustainable levels. The data was clear: the bottleneck wasn't my business logic or my infrastructure; it was a fundamental architectural flaw in how I was asking the database to retrieve data.</p>
<h3 id="heading-why-the-offset-approach-fails-at-scale"><strong>Why the "Offset" approach fails at scale</strong></h3>
<p>To put it simply, <code>OFFSET</code> forces the database to "<strong>read and throw away.</strong>" If you want the <strong>1,000,000th</strong> row, the database still has to count and skip the first <strong>999,999</strong>. In 2026, when users expect instant feedback even on massive datasets, that extra work is a luxury your server simply can't afford.</p>
<pre><code class="lang-kotlin">
<span class="hljs-meta">@Service</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserService</span></span>(
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> userRepository: UserRepository
) {

    <span class="hljs-comment">//Offset based pagination</span>
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getUsers</span><span class="hljs-params">(offset: <span class="hljs-type">Int</span>, pageSize: <span class="hljs-type">Int</span>)</span></span>: Page&lt;User&gt; {
        <span class="hljs-keyword">return</span> userRepository.findAll(PageRequest.of(offset, pageSize))
    }
}
</code></pre>
<p>I tested my Spring Boot API with an offset-based request: <code>GET</code> <a target="_blank" href="http://localhost:8000/users?page=0&amp;size=100"><code>http://localhost:8000/users?page=0&amp;size=100</code></a>. The query executed in <strong>150 milliseconds</strong>, which seems perfectly fine at first glance. However, this speed is misleading. OFFSET pagination performs well only on the first few pages because the database doesn’t need to skip many rows. As the page number grows, the OFFSET value increases, forcing the database to <strong>scan and discard a large number of rows</strong> before returning the results. For example, <code>page=10,000</code> with <code>size=100</code> would require scanning over a <strong>million rows</strong>, causing query times to grow linearly. On top of that, Spring Data JPA triggers a <code>SELECT COUNT(*)</code> with each <code>Page&lt;T&gt;</code> request, which can become <strong>slower than the data fetch itself</strong> on large tables. This illustrates a fundamental limitation of offset-based pagination: it works for small datasets but <strong>fails to scale efficiently</strong> as data grows. Cursor-based pagination solves this problem by using a stable key to jump directly to the next record, keeping performance <strong>predictable and constant</strong>, regardless of dataset size.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769268791279/83b85cd2-55c4-476a-97b2-e0b9094f0e79.png" alt class="image--center mx-auto" /></p>
<p>To test how offset pagination scales, I pushed my Spring Boot API further: <code>GET</code> <a target="_blank" href="http://localhost:8000/users?page=9999&amp;size=100"><code>http://localhost:8000/users?page=9999&amp;size=100</code></a>. The response time increased to <strong>367 milliseconds</strong>—more than double the 150 ms it took for the first page (<code>page=0</code>). This clearly demonstrates how offset pagination performance <strong>degrades linearly with page depth</strong>. The deeper the page, the more rows the database must scan and discard before returning the requested data. While 367 ms is still acceptable in isolation, the trend highlights a critical problem: for datasets in the millions or under heavy load, <strong>response times can quickly become unmanageable</strong>. Additionally, the <code>SELECT COUNT(*)</code> query executed by Spring Data JPA on each page further adds to the load. This is why large-scale applications, such as Instagram, Facebook, and Google, avoid offset-based pagination entirely in favor of <strong>cursor-based (key-set) pagination</strong>, which maintains <strong>constant query performance regardless of page depth</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769269125570/e1d46797-9ad2-4d84-85e0-503b155f7f31.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-kotlin"><span class="hljs-meta">@Service</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserService</span></span>(
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> userRepository: UserRepository
) {
    <span class="hljs-comment">// Cursor based pagination</span>
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getUsers</span><span class="hljs-params">(cursor: <span class="hljs-type">Long</span>?, size: <span class="hljs-type">Int</span>)</span></span>: UserResponse&lt;User&gt; {


        <span class="hljs-keyword">val</span> pageable: Pageable = PageRequest.of(<span class="hljs-number">0</span>, size + <span class="hljs-number">1</span>)

        <span class="hljs-keyword">val</span> users: List&lt;User&gt; =
            userRepository.fetchNextPage(cursor, pageable)

        <span class="hljs-keyword">val</span> hasNext = users.size &gt; size

        <span class="hljs-keyword">val</span> <span class="hljs-keyword">data</span> = <span class="hljs-keyword">if</span> (hasNext) users.dropLast(<span class="hljs-number">1</span>) <span class="hljs-keyword">else</span> users

        <span class="hljs-keyword">val</span> nextCursor = <span class="hljs-keyword">data</span>.lastOrNull()?.id

        <span class="hljs-keyword">return</span> UserResponse(
            <span class="hljs-keyword">data</span> = <span class="hljs-keyword">data</span>,
            pageSize = size,
            nextCursor = nextCursor,
            hasNext = hasNext
        )
    }
}
</code></pre>
<p>Next, I tested the <strong>cursor-based pagination</strong> endpoint: <code>GET</code> <a target="_blank" href="http://localhost:8000/users/cursor?cursor=0&amp;size=100"><code>http://localhost:8000/users/cursor?cursor=0&amp;size=100</code></a>. The response time was just <strong>8 milliseconds</strong>—<strong>over 19x faster</strong> than the first-page offset request (150 ms) and <strong>over 45x faster than page 9999 using offset (367 ms)</strong>. This stark difference illustrates why cursor (key-set) pagination scales far more efficiently. Instead of scanning and discarding rows like offset pagination, cursor queries jump directly to the next record using an indexed key (<code>id</code> In this case). The result is <strong>constant-time query performance</strong>, even when fetching deep pages in a dataset with millions of records. For high-scale applications, this approach ensures predictable API latency and dramatically reduces CPU and I/O load on the database.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769269420509/0fc782d4-e160-4143-bf19-928af2c7b01f.png" alt class="image--center mx-auto" /></p>
<p>To test cursor-based pagination at deeper pages, I ran the request:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769269542965/35704865-75bb-4bee-9eaa-9b866a864213.png" alt class="image--center mx-auto" /></p>
<p>The response returned in just <strong>7 milliseconds</strong>. This is remarkable because even at a high cursor value, the query time <strong>remained constant</strong>. Unlike offset pagination, where deep pages require scanning and discarding thousands or millions of rows, cursor pagination uses the indexed key (<code>id</code>) to jump directly to the starting point. This makes fetching large datasets predictable and extremely fast, regardless of page depth. For high-scale applications with feeds, timelines, or infinite scrolling, this efficiency ensures low latency, minimal CPU and I/O usage, and consistent user experience—even when fetching hundreds or thousands of records at once.</p>
<h2 id="heading-why-choose-cursor-based-over-offset-based-pagination"><strong>Why Choose Cursor-Based over Offset-Based Pagination</strong></h2>
<ul>
<li><p><strong>Performance</strong>: As the offset increases in offset-based pagination, it can become slow because the database needs to read up to the offset position, involving counting rows from disk. In contrast, cursor-based pagination directly points to the cursor’s location, making it faster.</p>
</li>
<li><p><strong>Dynamic Data:</strong> Cursor-based pagination is better suited for dynamic data where records may be inserted or deleted, as it acts as a pointer to where the last request left off.</p>
</li>
</ul>
<h2 id="heading-why-choose-offset-based-over-cursor-based-pagination"><strong>Why Choose Offset-Based over Cursor-Based Pagination</strong></h2>
<ul>
<li><p><strong>Sorting Flexibility:</strong> Offset-based pagination allows for easier sorting of data based on various attributes. In cursor-based pagination, the cursor must be a unique attribute that can be sequentially ordered, and data will always be sorted by that attribute.</p>
</li>
<li><p><strong>User Navigation:</strong> Offset-based pagination enables users to jump to specific pages directly, which is not easily achievable in cursor-based pagination.</p>
</li>
</ul>
<p>In the performance tests above, we observed that the execution time for offset-based pagination increases as the offset value grows. However, with cursor-based pagination, the execution time remains relatively consistent, even when the cursor changes 🚀 . This highlights one of the key advantages of cursor-based pagination in handling large datasets efficiently.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>In this article, we’ve explored the details of offset-based and cursor-based pagination and compared their performance. With this information, you can now make an educated choice about which pagination method works best for your particular requirements.</p>
<p>You can check out the <strong>complete working code</strong> for both offset-based and cursor-based pagination on GitHub: <a target="_blank" href="https://github.com/Ansalpandey/Pagination-Demo">Repo Link</a>.</p>
<p>If you found this helpful, follow me on <a target="_blank" href="https://www.instagram.com/ansal_pandey">Instagram</a> and <a target="_blank" href="https://www.linkedin.com/in/ansalpandey/"><strong>LinkedIn</strong></a> for more insights on <strong>system design, Spring Boot, and backend development</strong>. I regularly share hands-on tutorials, performance tips, and real-world examples that help you build <strong>scalable and efficient applications</strong>.</p>
]]></content:encoded></item><item><title><![CDATA[HTTP:  Core Concepts]]></title><description><![CDATA[Explore the HTTP protocol, the backbone of modern web communication. Understand its core concepts, request-response cycle, methods, and how HTTP powers…]]></description><link>https://stacked.hashnode.dev/http-core-concepts</link><guid isPermaLink="true">https://stacked.hashnode.dev/http-core-concepts</guid><category><![CDATA[http]]></category><category><![CDATA[https]]></category><category><![CDATA[backend]]></category><category><![CDATA[software development]]></category><category><![CDATA[APIs]]></category><category><![CDATA[Springboot]]></category><dc:creator><![CDATA[Stacked]]></dc:creator><pubDate>Wed, 01 Oct 2025 13:12:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1759323354092/33db9bc5-0b07-4496-bc96-4f6bac66cbdf.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The <strong>Hypertext Transfer Protocol (HTTP)</strong> forms the backbone of the modern web. Every time you click a link, load a webpage, or interact with an online service, HTTP is quietly at work making that interaction possible. It is an <strong>application-layer protocol</strong> within the Internet Protocol Suite, specifically designed for transferring information between networked devices. Sitting on top of lower-level protocols like <strong>TCP/IP</strong>, HTTP provides a structured way for clients (such as web browsers, mobile apps, or IoT devices) to request resources and for servers to respond with the appropriate data.</p>
<p>At its core, HTTP follows a <strong>request–response model</strong>. A client initiates communication by sending an HTTP request to a server, often asking for a document, image, or other resource. The server processes this request and returns an HTTP response, which includes not only the requested resource but also metadata in the form of headers and a status code that informs the client about the outcome of the request.</p>
<p>Over time, HTTP has evolved significantly, from the early days of <strong>HTTP/0.9</strong>, which supported only raw data transfer, to the more feature-rich <strong>HTTP/1.1</strong>, the highly optimized <strong>HTTP/2</strong>, and the latest <strong>HTTP/3</strong>, which leverages QUIC for faster and more reliable communication. These advancements address limitations like latency, multiplexing, and connection overhead, ensuring that HTTP continues to meet the demands of today’s highly interactive, media-rich web applications.</p>
<p>In essence, HTTP is not just about loading pages; it is the <strong>universal protocol of communication on the web</strong>, powering everything from simple blogs to complex APIs and real-time applications.</p>
<h2 id="heading-what-is-in-an-http-request"><strong>What is in an HTTP request?</strong></h2>
<p>An HTTP request is the way Internet communications platforms, such as web browsers, ask for the information they need to load a website.</p>
<p>Each HTTP request made across the Internet carries with it a series of encoded data that carries different types of information. A typical HTTP request contains:</p>
<ol>
<li><p>HTTP version type</p>
</li>
<li><p>a URL</p>
</li>
<li><p>an HTTP method</p>
</li>
<li><p>HTTP request headers</p>
</li>
<li><p>Optional HTTP body.</p>
</li>
</ol>
<p>Let’s explore in greater depth how these requests work and how the contents of a request can be used to share information.</p>
<h2 id="heading-what-is-an-http-method"><strong>What is an HTTP method?</strong></h2>
<p>An <strong>HTTP method</strong>, often referred to as an <strong>HTTP verb</strong>, defines the type of action a client expects the server to perform when making a request. In simple terms, it tells the server <em>what to do</em> with the resource identified by the request URL. Each method represents a different intent, such as retrieving data, submitting data, updating an existing resource, or even deleting it.</p>
<p>Two of the most commonly used methods are <strong>GET</strong> and <strong>POST</strong>:</p>
<ul>
<li><p><strong>GET</strong>: Used to request data from a server. For example, when you enter a URL into your browser and press Enter, your browser sends a GET request to the server hosting that page. The server responds with the requested resource, usually in the form of an HTML document, image, or JSON data for APIs. Importantly, GET requests should not change the state of the server; they are meant to be <strong>read-only</strong> operations.</p>
</li>
<li><p><strong>POST</strong>: Used to send data to the server, often as part of creating or submitting a new resource. A common example is submitting a login form with a username and password. The server processes this data, possibly stores it, and then returns a response (such as redirecting you to your account dashboard). Unlike GET, POST requests can <strong>modify server-side resources</strong> and are not idempotent (meaning repeated identical requests can produce different effects).</p>
</li>
</ul>
<p>Beyond GET and POST, modern web development often relies on additional HTTP methods:</p>
<ul>
<li><p><strong>PUT</strong>: Replaces an existing resource or creates a new one if it doesn’t already exist.</p>
</li>
<li><p><strong>PATCH</strong>: Applies partial modifications to a resource, making it more efficient for updates.</p>
</li>
<li><p><strong>DELETE</strong>: Removes the specified resource from the server.</p>
</li>
<li><p><strong>HEAD</strong>: Similar to GET but only requests headers (no body), often used for checking metadata or caching.</p>
</li>
<li><p><strong>OPTIONS</strong>: Describes the communication options available for a given resource, commonly used in <strong>CORS (Cross-Origin Resource Sharing)</strong> checks.</p>
</li>
</ul>
<p>Together, these methods provide a flexible and standardized way for clients and servers to interact, forming the basis of everything from traditional web pages to RESTful APIs and microservices.</p>
<h2 id="heading-what-are-http-request-headers"><strong>What are HTTP request headers?</strong></h2>
<p>HTTP headers contain text information stored in key-value pairs, and they are included in every HTTP request (and response, more on that later). These headers communicate core information, such as what browser the client is using and what data is being requested.</p>
<p>Example of HTTP request headers from Google Chrome's network tab:</p>
<p><img src="https://www.cloudflare.com/img/learning/ddos/glossary/hypertext-transfer-protocol-http/http-request-headers.png" alt="HTTP request headers" /></p>
<h2 id="heading-what-is-in-an-http-request-body"><strong>What is in an HTTP request body?</strong></h2>
<p>The body of a request is the part that contains the ‘body’ of information the request is transferring. The body of an HTTP request contains any information being submitted to the web server, such as a username and password, or any other data entered into a form.</p>
<h2 id="heading-what-is-in-an-http-response"><strong>What is in an HTTP response?</strong></h2>
<p>An HTTP response is what web clients (often browsers) receive from an Internet server in answer to an HTTP request. These responses communicate valuable information based on what was asked for in the HTTP request.</p>
<p>A typical HTTP response contains:</p>
<ol>
<li><p>an HTTP status code</p>
</li>
<li><p>HTTP response headers</p>
</li>
<li><p>optional HTTP body</p>
</li>
</ol>
<p>Let’s break this down</p>
<h2 id="heading-whats-an-http-status-code"><strong>What’s an HTTP status code?</strong></h2>
<ol>
<li><p>HTTP status codes are 3-digit codes most often used to indicate whether an HTTP request has been completed. Status codes are broken into the following 5 blocks:</p>
<ol>
<li><p>1xx Informational</p>
</li>
<li><p>2xx Success</p>
</li>
<li><p>3xx Redirection</p>
</li>
<li><p>4xx Client Error</p>
</li>
<li><p>5xx Server Error</p>
</li>
<li><p>The “xx” refers to different numbers between 00 and 99.</p>
<p> Status codes starting with the number ‘2’ indicate a success. For example, after a client requests a webpage, the most commonly seen responses have a status code of ‘200 OK’, indicating that the request was properly completed.</p>
<p> If the response starts with a ‘4’ or a ‘5’, that means there was an error, and the webpage will not be displayed. A status code that begins with a ‘4’ indicates a client-side error (it is very common to encounter a ‘404 NOT FOUND’ status code when making a typo in a URL). A status code beginning in ‘5’ means something went wrong on the server side. Status codes can also begin with a ‘1’ or a ‘3’, which indicate an informational response and a redirect, respectively.</p>
</li>
</ol>
</li>
</ol>
<h2 id="heading-what-are-http-response-headers"><strong>What are HTTP response headers?</strong></h2>
<p>    Much like an HTTP request, an HTTP response comes with headers that convey important information, such as the language and format of the data being sent in the response body.</p>
<ol>
<li><p>Example of HTTP response headers from Google Chrome's network tab:</p>
<p> <img src="https://www.cloudflare.com/img/learning/ddos/glossary/hypertext-transfer-protocol-http/http-response-headers.png" alt="HTTP response headers" /></p>
</li>
</ol>
<h2 id="heading-what-is-in-an-http-response-body"><strong>What is in an HTTP response body?</strong></h2>
<p>    Successful HTTP responses to ‘GET’ requests generally have a body which contains the requested information. In most web requests, this is HTML data that a web browser will translate into a webpage.</p>
<p>    In the context of a traditional website, the response body typically contains <strong>HTML</strong>, which the browser interprets and renders into the webpage you see. However, the body isn’t limited to HTML. Depending on the request and resource, it can contain:</p>
<ul>
<li><p><strong>HTML documents</strong> → the most common case for rendering web pages.</p>
</li>
<li><p><strong>JSON data</strong> → widely used in APIs for structured data exchange between client and server.</p>
</li>
<li><p><strong>XML data</strong> → older format still used in certain systems.</p>
</li>
<li><p><strong>Plain text</strong> → simple responses or debugging messages.</p>
</li>
<li><p><strong>Images, audio, or video files</strong> → binary content requested via URLs.</p>
</li>
<li><p><strong>CSS or JavaScript files</strong> → resources required by the browser to properly style and run the page.</p>
</li>
</ul>
<p>    Not every response will contain a body. For instance, certain status codes like <strong>204 No Content</strong> or <strong>304 Not Modified</strong> deliberately omit it because the server doesn’t need to return additional data. Similarly, responses to requests like <code>HEAD</code> Only return headers without a body.</p>
<p>    In short, the <strong>response body delivers the resource</strong> the client asked for, whether it’s a web page, a JSON object for an API, or even a downloadable file. The headers in the HTTP response (such as <code>Content-Type</code> and <code>Content-Length</code>) help the client understand what’s inside the body and how to process it.</p>
<p>I hope you found this article useful. If you have any questions or comments, please feel free to leave them below. Thanks for reading!</p>
]]></content:encoded></item><item><title><![CDATA[🚀 Running LLMs Locally with Docker Models: A Step-by-Step Guide]]></title><description><![CDATA[Learn how to run large language models (LLMs) locally using Docker’s Model Runner (DMR). Pull, run, and integrate AI models in Node.js]]></description><link>https://stacked.hashnode.dev/running-llms-locally-with-docker</link><guid isPermaLink="true">https://stacked.hashnode.dev/running-llms-locally-with-docker</guid><category><![CDATA[Docker]]></category><category><![CDATA[AI]]></category><category><![CDATA[#ai-tools]]></category><category><![CDATA[ai agents]]></category><category><![CDATA[Machine Learning]]></category><category><![CDATA[ML]]></category><dc:creator><![CDATA[Stacked]]></dc:creator><pubDate>Fri, 12 Sep 2025 18:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1757773766469/0eeed22e-ca0f-4167-b3e4-4f5b9e615e65.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Docker has always been a developer’s best friend for containerization, packaging, and deployment. But did you know you can now use Docker to <strong>pull and run AI/LLM models locally</strong>, just like you run containers?</p>
<p>With the <strong>Docker Model Runner (DMR)</strong>, you can manage, run, and deploy AI models almost as easily as setting up a database. In this guide, I’ll walk you through:</p>
<ul>
<li><p>Enabling Docker Model Runner</p>
</li>
<li><p>Pulling and running models locally</p>
</li>
<li><p>Using REST APIs to interact with models</p>
</li>
<li><p>Seamlessly integrating local models with OpenAI’s SDK</p>
</li>
</ul>
<p>By the end, you’ll see how running LLMs locally can save costs, speed up development, and give you more flexibility.</p>
<hr />
<h2 id="heading-setting-up-docker-model-runner">Setting Up Docker Model Runner</h2>
<p>Before we begin, ensure Docker Desktop is installed. Inside <strong>Docker Settings → AI</strong>, enable:</p>
<ol>
<li><p>✅ <strong>Enable Docker Model Runner</strong></p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757773426739/5950543c-71e1-49ef-b353-89c632b97841.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>✅ <strong>Enable Host-side TCP Support</strong> (for exposing OpenAI-compatible APIs on port <code>12434</code>)</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757773440391/41c9e32c-1d6e-4830-b880-9dcf65c03474.png" alt class="image--center mx-auto" /></p>
<p>Once enabled, you’re ready to use Docker’s new <code>model</code> command.</p>
<hr />
<h2 id="heading-exploring-the-docker-model-cli">Exploring the Docker Model CLI</h2>
<p>Open a terminal and type:</p>
<pre><code class="lang-bash">docker model
</code></pre>
<p>You’ll see commands similar to how we work with Docker images:</p>
<ul>
<li><p><code>docker model list</code> → Lists downloaded models</p>
</li>
<li><p><code>docker model pull &lt;model&gt;</code> → Pulls a new model from Docker Hub</p>
</li>
<li><p><code>docker model run &lt;model&gt;</code> → Runs a model locally</p>
</li>
</ul>
<p>For example:</p>
<pre><code class="lang-bash">docker model list
</code></pre>
<p>This shows any models already available on your machine.</p>
<hr />
<h2 id="heading-pulling-models-from-docker-hub">Pulling Models from Docker Hub</h2>
<p>Just like container images, models are also hosted on <strong>Docker Hub</strong>. You can explore them under the <strong>Models</strong> section.</p>
<p>Example: pulling a small LLM (<code>gma-3</code>, ~57MB):</p>
<pre><code class="lang-bash">docker model pull ai/gemma3:270M-F16
</code></pre>
<p>Once pulled, you can run it interactively:</p>
<pre><code class="lang-bash">docker model run ai/gemma3:270M-F16
</code></pre>
<p>This starts a chat session with the model:</p>
<pre><code class="lang-bash">&gt; Hi
Hello! How can I <span class="hljs-built_in">help</span> you today?
</code></pre>
<p>Boom! Your local LLM is now up and running.</p>
<hr />
<h2 id="heading-accessing-models-via-rest-apis">Accessing Models via REST APIs</h2>
<p>Running models interactively is cool, but you’ll likely want to integrate them into apps. That’s where the REST API comes in.</p>
<p>By default, Docker exposes APIs on <a target="_blank" href="http://localhost:12434"><code>http://localhost:12434</code></a>.</p>
<p>Example:</p>
<pre><code class="lang-bash">curl http://localhost:12434/models
</code></pre>
<p>This returns the list of available models (just like OpenAI’s API).</p>
<hr />
<h2 id="heading-openai-compatible-endpoints">OpenAI-Compatible Endpoints</h2>
<p>Here’s the real magic ✨. Docker provides <strong>OpenAI-compatible endpoints</strong>. That means you don’t have to rewrite your code if you already use OpenAI’s SDK.</p>
<p>In Node.js, a typical OpenAI call looks like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> OpenAI <span class="hljs-keyword">from</span> <span class="hljs-string">"openai"</span>;

<span class="hljs-keyword">const</span> client = <span class="hljs-keyword">new</span> OpenAI({
  <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"your-key"</span>, <span class="hljs-comment">// Not required when using Docker Models</span>
  <span class="hljs-attr">baseURL</span>: <span class="hljs-string">"http://localhost:12434/engines/llama.cpp/v1"</span> <span class="hljs-comment">// override OpenAI endpoint</span>
});

<span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.chat.completions.create({
  <span class="hljs-attr">model</span>: <span class="hljs-string">"ai/gemma3:270M-F16"</span>,
  <span class="hljs-attr">messages</span>: [{ <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>, <span class="hljs-attr">content</span>: <span class="hljs-string">"Hello, I’m John Doe"</span> }]
});

<span class="hljs-built_in">console</span>.log(response.choices[<span class="hljs-number">0</span>].message.content);
</code></pre>
<p>Notice that the <strong>only changes</strong> are:</p>
<ul>
<li><p>Set <code>baseURL</code> to (http://localhost:12434/engines/llama.cpp/v1)</p>
</li>
<li><p>Use the local model name (ai/gemma3:270M-F16)</p>
</li>
</ul>
<p>No need to change your existing logic! 🚀</p>
<p>If Docker isn’t running, requests fail with <em>connection refused</em>, proving that everything is local.</p>
<hr />
<h2 id="heading-why-this-matters">Why This Matters</h2>
<ul>
<li><p>💸 <strong>Cost-Free Development</strong> → No API credits needed while experimenting locally</p>
</li>
<li><p>⚡ <strong>Faster Iteration</strong> → Run and test models instantly</p>
</li>
<li><p>🔄 <strong>Drop-in Replacement</strong> → Switch between local Docker models and OpenAI’s hosted models by just changing the <code>baseURL</code></p>
</li>
</ul>
<p>If you have a powerful GPU, you can even run bigger models (like GPT-OS or Code LLMs) locally.</p>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>Docker has extended its power beyond containerization into the AI world. With <strong>Docker Model Runner</strong>, you can:</p>
<ul>
<li><p>Pull and run LLMs locally</p>
</li>
<li><p>Access them through REST APIs</p>
</li>
<li><p>Use OpenAI SDKs without rewriting your code</p>
</li>
</ul>
<p>This enables AI development to be faster, cheaper, and more accessible.</p>
<hr />
<p>👉 If you’re starting with AI or want to save on API costs during prototyping, <strong>Docker Models</strong> are worth exploring.</p>
<p>✅ <strong>Like this post?</strong><br />Follow <strong>Stacked</strong> here on <strong>Hashnode</strong> for more deep-dives into Backend Development, AI, DevOps and System Design.</p>
]]></content:encoded></item><item><title><![CDATA[The Internet, Simplified]]></title><description><![CDATA[A beginner-friendly breakdown of how the internet works, the backbone of backend development. Learn about clients, servers, DNS, IPs, and the journey]]></description><link>https://stacked.hashnode.dev/the-internet-simplified</link><guid isPermaLink="true">https://stacked.hashnode.dev/the-internet-simplified</guid><category><![CDATA[internet]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[software development]]></category><category><![CDATA[backend]]></category><category><![CDATA[Docker]]></category><category><![CDATA[APIs]]></category><category><![CDATA[Springboot]]></category><dc:creator><![CDATA[Stacked]]></dc:creator><pubDate>Fri, 12 Sep 2025 18:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1757778796588/d4cd449c-b311-48a7-a91f-b6f18990a7db.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When you open your browser and type <a target="_blank" href="http://google.com"><strong>google.com</strong></a>, you get results in less than a second. But have you ever wondered what <em>actually happens</em> between hitting <strong>Enter</strong> and seeing the webpage load?</p>
<p>As backend developers, we spend most of our time writing APIs and handling data. However, all of that relies on the foundation known as <strong>the internet</strong>. Before we dive into Spring Boot, Kotlin, and databases, let’s first understand <em>the framework that all our backend code runs on</em>.</p>
<p>In this article, we will cover the basics of the internet, including what it is, how it works, some basic concepts, terminology, and some common protocols that are used to build applications and services on the internet.</p>
<h2 id="heading-what-is-the-internet">What is the internet?</h2>
<p>The Internet is the world’s most popular computer network. It began as an academic research project in 1969 and became a global commercial network in the 1990s. Today, it is used by over 2 billion people worldwide.</p>
<p>The internet is notable for its decentralization. No one owns the internet or controls who can connect to it. Instead, thousands of different organizations operate their own networks and negotiate voluntary interconnection agreements.</p>
<p>Most people access internet content using a web browser. Indeed, the web has become so popular that many people incorrectly treat the internet and the web as if they were synonymous. But in reality, the web is just one of many internet applications. Other popular Internet applications include email and BitTorrent.</p>
<h2 id="heading-where-is-the-internet">Where is the internet?</h2>
<p>The internet has three basic parts:</p>
<ul>
<li><p><strong>The last mile</strong> is the part of the internet that connects homes and small businesses to the internet. Currently, <a target="_blank" href="http://www.leichtmanresearch.com/research/notes03_2015.pdf">about 60 percent</a> of residential internet connections in the United States are provided by cable TV companies such as Comcast and Time Warner. Of the remaining 40 percent, a growing fraction uses new fiber optic cables, most of which are part of Verizon’s FiOS program or AT&amp;T’s U-Verse. Finally, a significant but shrinking number use outdated DSL service provided over telephone cables.</p>
<p>  The last mile also includes the towers that allow people to access the internet with their cell phones. Wireless internet service accounts for a large and growing share of all internet usage.</p>
</li>
<li><p><strong>Data centers</strong> are rooms full of servers that store user data and host online apps and content. Some are owned by large companies such as Google and Facebook. Others are commercial facilities that provide service to many smaller websites. Data centers have very fast internet connections, allowing them to serve many users simultaneously. Data centers can be located anywhere in the world, but they are often located in remote areas where land and electricity are cheap. For example, <a target="_blank" href="http://www.datacenterknowledge.com/archives/2013/12/02/in-iowa-a-field-becomes-a-huge-google-server-farm/">Google</a>, <a target="_blank" href="http://www.wired.com/wiredenterprise/2013/11/facebook-iowa-wind/">Facebook</a>, and <a target="_blank" href="http://www.wired.com/wiredenterprise/2013/06/microsoft-iowa-data-center/">Microsoft</a> have all constructed vast data centers in Iowa.</p>
</li>
<li><p><strong>The backbone</strong> consists of long-distance networks, mostly on fiber optic cables, that carry data between data centers and consumers. The backbone market is highly competitive. Backbone providers frequently connect their networks at <a target="_blank" href="https://en.wikipedia.org/wiki/List_of_Internet_exchange_points_by_size">internet exchange points</a>, usually located in major cities. Establishing a presence at IEPs makes it much easier for backbone providers to improve their connections to others.</p>
</li>
</ul>
<h2 id="heading-who-created-the-internet">Who created the Internet?</h2>
<p>The internet began as <a target="_blank" href="https://en.wikipedia.org/wiki/ARPANET">ARPANET</a>, an academic research network that was funded by the military’s Advanced Research Projects Agency (ARPA, now DARPA). The project was led by <a target="_blank" href="https://en.wikipedia.org/wiki/Robert_Taylor_\(computer_scientist\)">Bob Taylor</a>, an ARPA administrator, and the network was built by the consulting firm of Bolt, Beranek and Newman. It began operations in 1969.</p>
<p>In 1973, software engineers <a target="_blank" href="https://en.wikipedia.org/wiki/Vint_Cerf">Vint Cerf</a> and <a target="_blank" href="https://en.wikipedia.org/wiki/Bob_Kahn">Bob Kahn</a> began work on the next generation of networking standards for the ARPANET. These standards, known as <a target="_blank" href="https://en.wikipedia.org/wiki/Internet_protocol_suite">TCP/IP</a>, became the foundation of the modern internet. ARPANET switched to using TCP/IP on January 1, 1983.</p>
<p>During the 1980s, funding for the Internet shifted from the military to the <a target="_blank" href="http://www.nsf.gov/">National Science Foundation.</a> The NSF funded the long-distance networks that served as the Internet’s backbone from 1981 until 1994. In 1994, the Clinton Administration <a target="_blank" href="http://www.nytimes.com/1994/10/24/business/us-begins-privatizing-internet-s-operations.html">turned control</a> over the internet backbone to the private sector. It has been privately operated and funded ever since.</p>
<h2 id="heading-who-runs-the-internet">Who runs the internet?</h2>
<p>No one runs the internet. It’s organized as a decentralized network of networks. Thousands of companies, universities, governments, and other entities operate their own networks and exchange traffic with each other based on voluntary interconnection agreements.</p>
<p>The shared technical standards that make the internet work are managed by an organization called the <a target="_blank" href="http://www.ietf.org/">Internet Engineering Task Force.</a> The IETF is an open organization; anyone is free to attend meetings, propose new standards, and recommend changes to existing standards. No one is required to adopt standards endorsed by the IETF, but the IETF’s consensus-based decision-making process helps to ensure that its recommendations are generally adopted by the internet community.</p>
<p>The <a target="_blank" href="https://www.icann.org/">Internet Corporation for Assigned Names and Numbers</a> (ICANN) is sometimes described as being responsible for internet governance. As its name implies, ICANN is in charge of distributing domain names (like vox.com) and <a target="_blank" href="http://www.vox.com/cards/the-internet/whats-an-ip-address">IP addresses</a>. But ICANN doesn’t control who can connect to the internet or what kind of information can be sent over it.</p>
<h2 id="heading-how-the-internet-works-an-overview"><strong>How the Internet Works: An Overview</strong></h2>
<p>At a high level, the internet works by connecting devices and computer systems using a set of standardized protocols. These protocols define how information is exchanged between devices and ensure that data is transmitted reliably and securely.</p>
<p>The core of the internet is a global network of interconnected routers, which are responsible for directing traffic between different devices and systems. When you send data over the internet, it is broken up into small packets that are sent from your device to a router. The router examines the packet and forwards it to the next router in the path towards its destination. This process continues until the packet reaches its final destination.</p>
<p>To ensure that packets are sent and received correctly, the Internet uses a variety of protocols, including the Internet Protocol (IP) and the Transmission Control Protocol (TCP). IP is responsible for routing packets to their correct destination, while TCP ensures that packets are transmitted reliably and in the correct order.</p>
<p>In addition to these core protocols, there is a wide range of other technologies and protocols that are used to enable communication and data exchange over the internet, including the Domain Name System (DNS), the Hypertext Transfer Protocol (HTTP), and the Secure Sockets Layer/Transport Layer Security (SSL/TLS) protocol. As a developer, it is important to have a solid understanding of how these different technologies and protocols work together to enable communication and data exchange over the internet.</p>
<h2 id="heading-basic-concepts-and-terminology"><strong>Basic Concepts and Terminology</strong></h2>
<p>To understand the internet, it’s important to be familiar with some basic concepts and terminology. Here are some key terms and concepts to be aware of:</p>
<ul>
<li><p><strong>Packet:</strong> A small unit of data that is transmitted over the Internet.</p>
</li>
<li><p><strong>Router:</strong> A device that directs packets of data between different networks.</p>
</li>
<li><p><strong>IP Address:</strong> A unique identifier assigned to each device on a network, used to route data to the correct destination.</p>
</li>
<li><p><strong>Domain Name:</strong> A human-readable name that is used to identify a website, such as <a target="_blank" href="http://google.com">google.com</a>.</p>
</li>
<li><p><strong>DNS:</strong> The Domain Name System is responsible for translating domain names into IP addresses.</p>
</li>
<li><p><strong>HTTP:</strong> The Hypertext Transfer Protocol is used to transfer data between a client (such as a web browser) and a server (such as a website).</p>
</li>
<li><p><strong>HTTPS:</strong> An encrypted version of HTTP that is used to provide secure communication between a client and server.</p>
</li>
<li><p><strong>SSL/TLS:</strong> The Secure Sockets Layer and Transport Layer Security protocols are used to provide secure communication over the Internet.</p>
</li>
</ul>
<p>Understanding these basic concepts and terms is essential for working with the internet and developing internet-based applications and services.</p>
<h2 id="heading-the-role-of-protocols-in-the-internet"><strong>The Role of Protocols in the Internet</strong></h2>
<p>Protocols play a critical role in enabling communication and data exchange over the internet. A protocol is a set of rules and standards that define how information is exchanged between devices and systems.</p>
<p>There are many different protocols used in internet communication, including the Internet Protocol (IP), the Transmission Control Protocol (TCP), the User Datagram Protocol (UDP), the Domain Name System (DNS), and many others.</p>
<p>IP is responsible for routing packets of data to their correct destination, while TCP and UDP ensure that packets are transmitted reliably and efficiently. DNS is used to translate domain names into IP addresses, and HTTP is used to transfer data between clients and servers.</p>
<p>One of the key benefits of using standardized protocols is that they allow devices and systems from different manufacturers and vendors to communicate with each other seamlessly. For example, a web browser developed by one company can communicate with a web server developed by another company, as long as they both adhere to the HTTP protocol.</p>
<p>As a developer, it’s important to understand the various protocols used in internet communication and how they work together to enable the transfer of data and information over the internet.</p>
<h2 id="heading-understanding-ip-addresses-and-domain-names"><strong>Understanding IP Addresses and Domain Names</strong></h2>
<p>IP addresses and domain names are both important concepts to understand when working with the internet.</p>
<p>An IP address is a unique identifier assigned to each device on a network. It’s used to route data to the correct destination, ensuring that information is sent to the intended recipient. IP addresses are typically represented as a series of four numbers separated by periods, such as “192.168.1.1”.</p>
<p>Domain names, on the other hand, are human-readable names used to identify websites and other internet resources. They’re typically composed of two or more parts, separated by periods. For example, “<a target="_blank" href="http://google.com">google.com</a>” is a domain name. Domain names are translated into IP addresses using the Domain Name System (DNS).</p>
<p>DNS is a critical part of the internet infrastructure, responsible for translating domain names into IP addresses. When you enter a domain name into your web browser, your computer sends a DNS query to a DNS server, which returns the corresponding IP address. Your computer then uses that IP address to connect to the website or other resource you’ve requested.</p>
<h2 id="heading-introduction-to-http-and-https"><strong>Introduction to HTTP and HTTPS</strong></h2>
<p>HTTP (Hypertext Transfer Protocol) and HTTPS (HTTP Secure) are two of the most commonly used protocols in internet-based applications and services.</p>
<p>HTTP is the protocol used to transfer data between a client (such as a web browser) and a server (such as a website). When you visit a website, your web browser sends an HTTP request to the server, asking for the webpage or other resource you’ve requested. The server then sends an HTTP response back to the client, containing the requested data.</p>
<p>HTTPS is a more secure version of HTTP, which encrypts the data being transmitted between the client and server using SSL/TLS (Secure Sockets Layer/Transport Layer Security) encryption. This provides an additional layer of security, helping to protect sensitive information such as login credentials, payment information, and other personal data.</p>
<p>When you visit a website that uses HTTPS, your web browser will display a padlock icon in the address bar, indicating that the connection is secure. You may also see the letters “https” at the beginning of the website address, rather than “http”.</p>
<h2 id="heading-building-applications-with-tcpip"><strong>Building Applications with TCP/IP</strong></h2>
<p>TCP/IP (Transmission Control Protocol/Internet Protocol) is the underlying communication protocol used by most internet-based applications and services. It provides a reliable, ordered, and error-checked delivery of data between applications running on different devices.</p>
<p>When building applications with TCP/IP, there are a few key concepts to understand:</p>
<ul>
<li><p>Ports: Ports are used to identify the application or service running on a device. Each application or service is assigned a unique port number, allowing data to be sent to the correct destination.</p>
</li>
<li><p>Sockets: A socket is a combination of an IP address and a port number, representing a specific endpoint for communication. Sockets are used to establish connections between devices and transfer data between applications.</p>
</li>
<li><p>Connections: A connection is established between two sockets when two devices want to communicate with each other. During the connection establishment process, the devices negotiate various parameters such as the maximum segment size and window size, which determine how data will be transmitted over the connection.</p>
</li>
<li><p>Data transfer: Once a connection is established, data can be transferred between the applications running on each device. Data is typically transmitted in segments, with each segment containing a sequence number and other metadata to ensure reliable delivery.</p>
</li>
</ul>
<p>When building applications with TCP/IP, you’ll need to ensure that your application is designed to work with the appropriate ports, sockets, and connections. You’ll also need to be familiar with the various protocols and standards that are commonly used with TCP/IP, such as HTTP, FTP (File Transfer Protocol), and SMTP (Simple Mail Transfer Protocol). Understanding these concepts and protocols is essential for building effective, scalable, and secure internet-based applications and services.</p>
<h2 id="heading-securing-internet-communication-with-ssltls"><strong>Securing Internet Communication with SSL/TLS</strong></h2>
<p>As we discussed earlier, SSL/TLS is a protocol used to encrypt data being transmitted over the internet. It is commonly used to provide secure connections for applications such as web browsers, email clients, and file transfer programs.</p>
<p>When using SSL/TLS to secure internet communication, there are a few key concepts to understand:</p>
<ul>
<li><p><strong>Certificates:</strong> SSL/TLS certificates are used to establish trust between the client and server. They contain information about the identity of the server and are signed by a trusted third party (a Certificate Authority) to verify their authenticity.</p>
</li>
<li><p><strong>Handshake:</strong> During the SSL/TLS handshake process, the client and server exchange information to negotiate the encryption algorithm and other parameters for the secure connection.</p>
</li>
<li><p><strong>Encryption:</strong> Once the secure connection is established, data is encrypted using the agreed-upon algorithm and can be transmitted securely between the client and server.</p>
</li>
</ul>
<p>When building internet-based applications and services, it’s important to understand how SSL/TLS works and to ensure that your application is designed to use SSL/TLS when transmitting sensitive data such as login credentials, payment information, and other personal data. You’ll also need to ensure that you obtain and maintain valid SSL/TLS certificates for your servers, and that you follow best practices for configuring and securing your SSL/TLS connections. By doing so, you can help protect your users’ data and ensure the integrity and confidentiality of your application’s communication over the internet.</p>
<h2 id="heading-the-future-emerging-trends-and-technologies"><strong>The Future: Emerging Trends and Technologies</strong></h2>
<p>The internet is constantly evolving, and new technologies and trends are emerging all the time. As a developer, it’s important to stay up-to-date with the latest developments in order to build innovative and effective applications and services.</p>
<p>Here are some of the emerging trends and technologies that are shaping the future of the internet:</p>
<ul>
<li><p><strong>5G:</strong> 5G is the latest generation of mobile network technology, offering faster speeds, lower latency, and greater capacity than previous generations. It is expected to enable new use cases and applications, such as autonomous vehicles and remote surgery.</p>
</li>
<li><p><strong>Internet of Things (IoT):</strong> IoT refers to the network of physical devices, vehicles, home appliances, and other objects that are connected to the internet and can exchange data. As IoT continues to grow, it is expected to revolutionize industries such as healthcare, transportation, and manufacturing.</p>
</li>
<li><p><strong>Artificial Intelligence (AI):</strong> AI technologies such as machine learning and natural language processing are already being used to power a wide range of applications and services, from voice assistants to fraud detection. As AI continues to advance, it is expected to enable new use cases and transform industries such as healthcare, finance, and education.</p>
</li>
<li><p><strong>Blockchain:</strong> Blockchain is a distributed ledger technology that enables secure, decentralized transactions. It is being used to power a wide range of applications, from cryptocurrency to supply chain management.</p>
</li>
<li><p><strong>Edge computing:</strong> Edge computing refers to the processing and storage of data at the edge of the network, rather than in centralized data centers. It is expected to enable new use cases and applications, such as real-time analytics and low-latency applications.</p>
</li>
</ul>
<p>By staying up-to-date with these and other emerging trends and technologies, you can ensure that your applications and services are built to take advantage of the latest capabilities and offer the best possible experience for your users.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>And that brings us to the end of this article. We’ve covered a lot of ground, so let’s take a moment to review what we’ve learned:</p>
<ul>
<li><p>The internet is a global network of interconnected computers that uses a standard set of communication protocols to exchange data.</p>
</li>
<li><p>The internet works by connecting devices and computer systems using standardized protocols, such as IP and TCP.</p>
</li>
<li><p>The core of the internet is a global network of interconnected routers that direct traffic between different devices and systems.</p>
</li>
<li><p>Basic concepts and terminology that you need to familiarize yourself with include packets, routers, IP addresses, domain names, DNS, HTTP, HTTPS, and SSL/TLS.</p>
</li>
<li><p>Protocols play a critical role in enabling communication and data exchange over the internet, allowing devices and systems from different manufacturers and vendors to communicate seamlessly.</p>
</li>
</ul>
<p>I hope you found this article useful. If you have any questions or comments, please feel free to leave them below. Thanks for reading!</p>
]]></content:encoded></item></channel></rss>