<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged sharding</title>
<link>https://coderlegion.com/tag/sharding</link>
<description>Powered by Question2Answer</description>
<item>
<title>Horizontally Scaling PostgreSQL: Database Sharding with Citus</title>
<link>https://coderlegion.com/28711/horizontally-scaling-postgresql-database-sharding-with-citus</link>
<description>&lt;blockquote&gt;&lt;p&gt;A practical guide to scaling your database infrastructure horizontally. Learn how to shard your data, optimize query routing, and build a distributed multi-tenant architecture using Postgres, Citus and Docker.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h3&gt;
&lt;p&gt;What do you need to follow along?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A working Laptop/PC?&lt;/li&gt;
&lt;li&gt;Working knowledge of SQL or PostgreSQL.&lt;/li&gt;
&lt;li&gt;To have at least eaten something today (preferably swallow related).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Database sharding is a strategy used to solve scalability issues in applications that have a massive amount of data. It involves splitting data into smaller chunks called shards. Each shard is stored on a separate database server instance, effectively spreading the data and the workload across multiple machines.&lt;/p&gt;
&lt;h3 id=&quot;why-shard-data-&quot;&gt;Why Shard Data?&lt;/h3&gt;
&lt;p&gt;As an application grows, the number of users and the amount of data it stores increase over time. At a certain limit, a single database server will become a bottleneck. The application slows down and affects the user experience.&lt;/p&gt;
&lt;p&gt;Instead of upgrading a single server with more CPU or RAM, which will eventually hit a hardware ceiling, sharding lets you add more servers to your cluster. This allows applications to handle nearly infinite growth in data volume and user traffic.&lt;/p&gt;
&lt;h3 id=&quot;understanding-shards-and-shard-keys&quot;&gt;Understanding Shards and Shard Keys&lt;/h3&gt;
&lt;p&gt;Before we start sharding data, let's first understand what shards and shard keys are.&lt;/p&gt;
&lt;h4 id=&quot;shards&quot;&gt;Shards&lt;/h4&gt;
&lt;p&gt;The partitioned data chunks are called logical shards. The machine that stores the logical shard is called a physical shard or database node. A physical shard can contain multiple logical shards.&lt;/p&gt;
&lt;h4 id=&quot;shard-key&quot;&gt;Shard Key&lt;/h4&gt;
&lt;p&gt;A shard key is used to determine how to partition the dataset. A shard key is a specific column in your dataset that determines which rows of data group together to form a shard.&lt;/p&gt;
&lt;h3 id=&quot;sharding-methods&quot;&gt;Sharding Methods&lt;/h3&gt;
&lt;p&gt;There are a few ways to shard data depending on the application requirements.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Key-based sharding (hash sharding)&lt;/strong&gt;: Hash sharding uses a mathematical formula called a hash function. The hash function takes your shard key and generates a hash value, this hash value determines the exact physical shard where the row will be stored.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Range-based sharding&lt;/strong&gt;: Range-based sharding, or dynamic sharding, splits database rows based on a range of values. Then the database designer assigns a shard key to the respective range.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Directory-based sharding&lt;/strong&gt;: Directory sharding uses a lookup table to match database information to the corresponding physical shard. A lookup table is like a table on a spreadsheet that links a database column to a shard key.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Geo sharding&lt;/strong&gt;: Geo sharding splits and stores database information according to geographical location.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For this guide, we are focusing exclusively on &lt;strong&gt;Hash Sharding&lt;/strong&gt;. This is the industry standard for multi-tenant applications like the e-commerce platform we will be building in this tutorial.&lt;/p&gt;
&lt;h3 id=&quot;choosing-your-shard-key&quot;&gt;Choosing Your Shard Key&lt;/h3&gt;
&lt;p&gt;If you pick the wrong shard key, your database will still crash under load. When choosing a shard key, you must ensure the data is distributed evenly across your nodes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Cardinality&lt;/strong&gt;: This refers to the number of unique values a key can have. You want a key with high cardinality like a User ID, not low cardinality like a Gender or State column, so the data can be split into many small, even chunks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Frequency&lt;/strong&gt;: You must avoid keys where one specific value appears too often. For example, if you shard by a City column and 80% of your users live in Ikeja, the Ikeja node will be overloaded while the others sit idle.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monotonic change&lt;/strong&gt;: This is the rate of change of the shard key. A monotonically increasing or decreasing shard key results in unbalanced shards. For example, consider a feedback database that is split into three different physical shards as follows:&lt;ul&gt;
&lt;li&gt;Shard A stores feedback from customers who have made 0 to 10 purchases.&lt;/li&gt;
&lt;li&gt;Shard B stores feedback from customers who have made 11 to 20 purchases.&lt;/li&gt;
&lt;li&gt;Shard C stores feedback from customers who have made 21 or more purchases.&lt;br&gt;
As the business grows, customers will make 21 or more purchases. The application stores their feedback in Shard C. This results in an unbalanced shard because Shard C contains more feedback records than the other shards.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;is-sharding-actually-for-you-&quot;&gt;Is Sharding Actually For You?&lt;/h3&gt;
&lt;p&gt;While sharding solves massive scale requirements, it introduces significant technical and operational tradeoffs. You should not shard your database unless a single, heavily provisioned Postgres instance can no longer handle your traffic.&lt;/p&gt;
&lt;p&gt;If you do decide to shard your database, here are some of the biggest challenges you will face:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Data hotspots&lt;/strong&gt;: Even with a good hash function, uneven traffic can create hotspots where one server becomes overloaded by a small group of highly active users.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance regression&lt;/strong&gt;: Queries that do not use the shard key require the system to scatter and gather across every server. Cross-shard joins are computationally expensive because the application must pull and merge data from multiple physical locations over the network.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operational complexity&lt;/strong&gt;: Managing a sharded environment increases the difficulty of routine tasks. Schema updates, backups, and point-in-time recovery must be coordinated across multiple independent instances.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;how-can-we-shard-our-postgres-database-introducing-citus&quot;&gt;How Can We Shard Our Postgres Database: Introducing Citus&lt;/h3&gt;
&lt;p&gt;Citus is an open-source extension that transforms standard PostgreSQL into a distributed database. Instead of being limited to a single server, Citus allows your database to scale horizontally across multiple machines.&lt;/p&gt;
&lt;h4 id=&quot;how-citus-works&quot;&gt;How Citus Works&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The Coordinator Node&lt;/strong&gt;: When you ask your database a question, you talk to the coordinator. The coordinator directs your request to the right servers, gathers the answers, and combines them for your application.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Worker Nodes&lt;/strong&gt;: Citus breaks down large tables into smaller, manageable chunks (shards) and spreads them across these worker servers. They do the heavy lifting of storing the data and running the queries.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;start-early-scale-later&quot;&gt;Start Early, Scale Later&lt;/h4&gt;
&lt;p&gt;Migrating a traditional, monolithic PostgreSQL database to a distributed, sharded database later in its life is incredibly difficult. You have to change your schema, rewrite complex queries, and alter how your application connects to the database.&lt;/p&gt;
&lt;p&gt;To avoid this nightmare, you can start using Citus on a single node from day one. You design your tables with distribution keys immediately, and your application code is written to query a distributed database from the start.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Transition&lt;/strong&gt;: When your data outgrows that single machine, you won't have to rewrite your application. You simply spin up new worker machines, and Citus moves the existing shards over to the new hardware in the background while the application keeps running.&lt;/p&gt;
&lt;h3 id=&quot;running-citus-locally&quot;&gt;Running Citus Locally&lt;/h3&gt;
&lt;p&gt;We will use Docker to run Citus locally. Why use Docker instead of adding the extension directly to your host machine's Postgres installation?&lt;/p&gt;
&lt;p&gt;Simulating a distributed database means running multiple Postgres instances simultaneously. Doing this natively forces you to manually manage conflicting ports and multiple data directories. Docker Compose solves this by orchestrating the entire cluster's networking with a single command, giving you a clean state that can be torn down and rebuilt in seconds.&lt;/p&gt;
&lt;h4 id=&quot;single-node-vs-multi-node-setup&quot;&gt;Single Node vs Multi-Node Setup&lt;/h4&gt;
&lt;p&gt;While it is possible to run a single node Citus instance using a simple &lt;code&gt;docker run&lt;/code&gt; command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker run -d --name citus_standalone -p 5432:5432 -e POSTGRES_PASSWORD=postgres citusdata/citus:14.1.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This guide will focus exclusively on setting up a &lt;strong&gt;Multi-Node Cluster&lt;/strong&gt;. If you are interested in exploring the single node setup further, you can &lt;a rel=&quot;nofollow&quot; href=&quot;https://learn.microsoft.com/en-us/postgresql/citus/single-node-docker?view=citus-14&quot;&gt;check out the official Citus documentation here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For our distributed, multi-node cluster, we will use the following Docker Compose configuration:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;services:
  master:
    container_name: &quot;${PROJECT_NAME:-citus}_master&quot;
    image: &quot;citusdata/citus:14.1.0&quot;
    ports: [&quot;${COORDINATOR_EXTERNAL_PORT:-5433}:5432&quot;]
    labels: [&quot;com.citusdata.role=Master&quot;]
    environment: &amp;amp;AUTH
      POSTGRES_USER: &quot;${POSTGRES_USER:-postgres}&quot;
      POSTGRES_PASSWORD: &quot;${POSTGRES_PASSWORD}&quot;
      PGUSER: &quot;${POSTGRES_USER:-postgres}&quot;
      PGPASSWORD: &quot;${POSTGRES_PASSWORD}&quot;
      POSTGRES_HOST_AUTH_METHOD: &quot;${POSTGRES_HOST_AUTH_METHOD:-trust}&quot;
  worker:
    image: &quot;citusdata/citus:14.1.0&quot;
    labels: [&quot;com.citusdata.role=Worker&quot;]
    environment: *AUTH
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Citus has a built-in initialization script in its official Docker image. When launched via Docker Compose with these specific labels like &lt;code&gt;com.citusdata.role&lt;/code&gt;, the coordinator automatically detects and registers the workers for you.&lt;/p&gt;
&lt;p&gt;We can build and start the cluster in the background with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can also scale up dynamically. If you want to spin up a second or third worker machine on the fly, you do not even need to edit the compose file. Just run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker compose up -d --scale worker=3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where 3 is the total number of workers you want to have running.&lt;/p&gt;
&lt;p&gt;Simply spinning up the worker containers is not enough. After adding new worker nodes, we must register them with the coordinator so Citus knows they are active and ready to hold data. To do this, we will first connect to the interactive Postgres terminal on the master node:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker compose exec master psql -U postgres
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can register our workers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT citus_add_node('db-sharding-worker-1', 5432);
SELECT citus_add_node('db-sharding-worker-2', 5432);
SELECT citus_add_node('db-sharding-worker-3', 5432);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, if you scale up again to say 5 workers, you will have to run this command 2 more times to register the 2 new workers.&lt;/p&gt;
&lt;p&gt;Notice the &lt;code&gt;db-sharding-&lt;/code&gt; prefix in the hostnames. This is necessary because Docker Compose prefixes your project folder name to the container's network alias.&lt;/p&gt;
&lt;h3 id=&quot;a-real-world-scenario&quot;&gt;A Real World Scenario&lt;/h3&gt;
&lt;p&gt;In order to showcase the functionality of this database sharding setup, let's try to work with a real world scenario.&lt;/p&gt;
&lt;p&gt;Consider an e-commerce multi-tenant application. It serves multiple independent companies that all share the same database infrastructure. To scale this effectively, we need to use a hash-based distribution with a well-chosen shard key. Let's assume by design, every tenant has a shared &lt;code&gt;company_id&lt;/code&gt;, we will use that as our shard key.&lt;/p&gt;
&lt;p&gt;By using &lt;code&gt;company_id&lt;/code&gt; as the shard key across all operational tables, Citus guarantees that all data belonging to a specific company (like its users, its products, and its orders) is physically co-located on the exact same worker node.&lt;/p&gt;
&lt;p&gt;Now that our workers are registered, we can create our core tables directly in the master node. Citus will automatically handle the underlying sharding for us.&lt;/p&gt;
&lt;p&gt;Please note that the following schema is highly simplified to focus on the core concepts of sharding.&lt;/p&gt;
&lt;p&gt;Run the following SQL commands in your coordinator's postgres interactive terminal:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;-- 1. Create Tenant Table
CREATE TABLE companies (
    company_id INT PRIMARY KEY,
    company_name TEXT NOT NULL
);

-- 2. Create Tenant-Scoped Orders Table
CREATE TABLE orders (
    company_id INT NOT NULL,
    order_id INT NOT NULL,
    user_id INT NOT NULL,
    status_id INT NOT NULL, -- References our global order status table
    order_amount NUMERIC(10,2) NOT NULL,
    PRIMARY KEY (company_id, order_id)
);

-- 3. Create Global Order Reference Table
CREATE TABLE order_statuses (
    status_id INT PRIMARY KEY,
    status_name TEXT NOT NULL
);

-- 4. Create Tenant-Scoped Users Table
CREATE TABLE users (
    company_id INT NOT NULL,
    user_id INT NOT NULL,
    username TEXT NOT NULL,
    PRIMARY KEY (company_id, user_id)
);

-- 5. Create Tenant-Scoped Products Table
CREATE TABLE products (
    company_id INT NOT NULL,
    product_id INT NOT NULL,
    product_name TEXT NOT NULL,
    price NUMERIC(10,2) NOT NULL,
    PRIMARY KEY (company_id, product_id)
);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;telling-citus-how-to-shard-and-replicate&quot;&gt;Telling Citus How to Shard and Replicate&lt;/h3&gt;
&lt;p&gt;Now that we have created our core tables, we have to tell Citus how to shard and replicate them across our worker nodes.&lt;/p&gt;
&lt;h4 id=&quot;reference-tables&quot;&gt;Reference Tables&lt;/h4&gt;
&lt;p&gt;First, we will set &lt;code&gt;order_statuses&lt;/code&gt; as a reference table. We do this using &lt;code&gt;create_reference_table&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Why do we create a reference table? A reference table is designed for relatively small, slowly-changing data like user roles, country codes, or order statuses.&lt;/p&gt;
&lt;p&gt;When you mark a table as a reference table, Citus physically replicates a full copy of that entire table to every single worker node. This bypasses network overhead completely during JOIN operations. Because the worker node already has the data locally, it does not need to fetch it from another node to complete a query.&lt;/p&gt;
&lt;h4 id=&quot;distributed-tables&quot;&gt;Distributed Tables&lt;/h4&gt;
&lt;p&gt;Next, we need to distribute our large tenant-data tables. We do this using &lt;code&gt;create_distributed_table&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This function is the core of Citus's sharding mechanism. It tells the coordinator to partition the table based on a specific column (our shard key, &lt;code&gt;company_id&lt;/code&gt;), and spread those partitions across the available worker nodes.&lt;/p&gt;
&lt;p&gt;Because we use &lt;code&gt;company_id&lt;/code&gt; across all these tables, any query filtering by a specific company will be routed directly to a single node, making it incredibly fast.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;-- Replicate order_statuses to ALL nodes
SELECT create_reference_table('order_statuses');

-- Shard data based on the Hash of company_id
SELECT create_distributed_table('companies', 'company_id');
SELECT create_distributed_table('users', 'company_id');
SELECT create_distributed_table('products', 'company_id');
SELECT create_distributed_table('orders', 'company_id');
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;multi-tenant-seed-data&quot;&gt;Multi-Tenant Seed Data&lt;/h3&gt;
&lt;p&gt;Now we will populate our cluster with some dummy companies along with some global order status entries, orders, and tenant users.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;-- Global Order Lookups
INSERT INTO order_statuses VALUES (1, 'Pending'), (2, 'Shipped'), (3, 'Delivered');

-- Company Tenants
INSERT INTO companies VALUES (1, 'EbaMart'), (2, 'FufuHub'), (3, 'GymGear');

-- Multi-Tenant Users scattered across companies
INSERT INTO users (company_id, user_id, username) VALUES
(1, 101, 'Samuel'),   -- EbaMart Customer
(2, 201, 'Folashade'),-- FufuHub Customer
(1, 102, 'Umoh'),     -- EbaMart Customer
(3, 301, 'Oladejo'),  -- GymGear Customer
(2, 202, 'BigSam');   -- FufuHub Customer

-- Orders
INSERT INTO orders (company_id, order_id, user_id, status_id, order_amount) VALUES
(1, 5001, 101, 1, 150.00),  -- EbaMart order: Pending
(1, 5002, 102, 3, 45.00),   -- EbaMart order: Delivered
(2, 6001, 201, 2, 99.00),   -- FufuHub order: Shipped
(2, 6002, 202, 1, 250.00);  -- FufuHub order: Pending
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;verify-layout-and-node-placement&quot;&gt;Verify Layout and Node Placement&lt;/h3&gt;
&lt;p&gt;We can now verify the layout and node placement to see where they are added to and display it by running:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT
    u.company_id,
    u.user_id,
    u.username,
    s.shardid,
    s.nodename
FROM users u
JOIN citus_shards s
  ON s.shardid = get_shard_id_for_distribution_column('users', u.company_id)
ORDER BY u.company_id;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;company_id &lt;/th&gt;&lt;th&gt;user_id &lt;/th&gt;&lt;th&gt;username  &lt;/th&gt;&lt;th&gt;shardid &lt;/th&gt;&lt;th&gt;nodename&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1          &lt;/td&gt;&lt;td&gt;101     &lt;/td&gt;&lt;td&gt;Samuel    &lt;/td&gt;&lt;td&gt;102042  &lt;/td&gt;&lt;td&gt;db-sharding-worker-2&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;1          &lt;/td&gt;&lt;td&gt;102     &lt;/td&gt;&lt;td&gt;Umoh      &lt;/td&gt;&lt;td&gt;102042  &lt;/td&gt;&lt;td&gt;db-sharding-worker-2&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2          &lt;/td&gt;&lt;td&gt;201     &lt;/td&gt;&lt;td&gt;Folashade &lt;/td&gt;&lt;td&gt;102065  &lt;/td&gt;&lt;td&gt;db-sharding-worker-1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2          &lt;/td&gt;&lt;td&gt;202     &lt;/td&gt;&lt;td&gt;BigSam    &lt;/td&gt;&lt;td&gt;102065  &lt;/td&gt;&lt;td&gt;db-sharding-worker-1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;3          &lt;/td&gt;&lt;td&gt;301     &lt;/td&gt;&lt;td&gt;Oladejo   &lt;/td&gt;&lt;td&gt;102056  &lt;/td&gt;&lt;td&gt;db-sharding-worker-1&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;As you can see, all data for &lt;code&gt;company_id = 1&lt;/code&gt; sits neatly on &lt;code&gt;db-sharding-worker-2&lt;/code&gt;, while &lt;code&gt;company_id = 2&lt;/code&gt; sits on &lt;code&gt;db-sharding-worker-1&lt;/code&gt;. This guarantees that queries for a single tenant will only hit one node.&lt;/p&gt;
&lt;p&gt;We can also inspect the query plan for joining distributed tables with reference tables:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;EXPLAIN (VERBOSE, COSTS OFF)
SELECT o.order_id, o.order_amount, s.status_name
FROM orders o
JOIN order_statuses s ON o.status_id = s.status_id
WHERE o.company_id = 1;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;                                      QUERY PLAN
---------------------------------------------------------------------
---------------------------------------------------------------------
---------------------------------------------------------------------
------------------------
 Custom Scan (Citus Adaptive)
   Output: remote_scan.order_id, remote_scan.order_amount, remote_scan.status_name
   Task Count: 1
   Tasks Shown: All
   -&amp;gt;  Task
         Query: SELECT o.order_id, o.order_amount, s.status_name FROM (public.orders_102106 o JOIN public.order_statuses_102008 s ON ((o.status_id OPERATOR(pg_catalog.=) s.status_id))) WHERE (o.company_id OPERATOR(pg_catalog.=) 1)
         Node: host=db-sharding-worker-2 port=5432 dbname=postgres
         -&amp;gt;  Hash Join
               Output: o.order_id, o.order_amount, s.status_name
               Hash Cond: (s.status_id = o.status_id)
               -&amp;gt;  Seq Scan on public.order_statuses_102008 s
                     Output: s.status_id, s.status_name
               -&amp;gt;  Hash
                     Output: o.order_id, o.order_amount, o.status_id
                     -&amp;gt;  Bitmap Heap Scan on public.orders_102106 o
                           Output: o.order_id, o.order_amount, o.status_id
                           Recheck Cond: (o.company_id = 1)
                           -&amp;gt;  Bitmap Index Scan on orders_pkey_102106
                                 Index Cond: (o.company_id = 1)
(19 rows)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The query plan shows a &lt;code&gt;Custom Scan (Citus Adaptive)&lt;/code&gt; delegating the query to the specific worker node holding &lt;code&gt;company_id = 1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We can check the active worker nodes with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT * FROM master_get_active_worker_nodes();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;node_name            &lt;/th&gt;&lt;th&gt;node_port&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;db-sharding-worker-3 &lt;/td&gt;&lt;td&gt;5432&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;db-sharding-worker-1 &lt;/td&gt;&lt;td&gt;5432&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;db-sharding-worker-2 &lt;/td&gt;&lt;td&gt;5432&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;rebalancing-the-cluster&quot;&gt;Rebalancing the Cluster&lt;/h3&gt;
&lt;p&gt;Anytime you dynamically scale the cluster and register a new worker node, you must run the Citus Shard Rebalancer:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT citus_rebalance_start();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When new nodes are added, the coordinator does not automatically move existing data onto them. We have to explicitly balance the load. The rebalancer handles this by dynamically moving a subset of your tenants' data over to the new worker servers in the background, without taking the database offline.&lt;/p&gt;
&lt;h3 id=&quot;production-setup&quot;&gt;Production Setup&lt;/h3&gt;
&lt;p&gt;The Docker Compose setup is perfect for local testing and development. However, running a distributed database in production across multiple physical servers or virtual machines requires a slightly different approach.&lt;/p&gt;
&lt;p&gt;We must first change how network addressing and orchestration work. In a local setup, Docker Compose handles networking automatically because everything shares a single machine loopback. On production VMs, each container must be bound to the public or private IP address of its physical host machine, and you must enforce strict firewall security.&lt;/p&gt;
&lt;h4 id=&quot;1-spin-up-your-vms&quot;&gt;1. Spin up your VMs&lt;/h4&gt;
&lt;p&gt;Spin up your virtual machines on your preferred cloud provider. Assuming we provision 4 VMs, our network layout will look something like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;VM 1 (Coordinator Node)&lt;/strong&gt;: Private IP 10.0.0.10&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VM 2 (Worker Node 1)&lt;/strong&gt;: Private IP 10.0.0.11&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VM 3 (Worker Node 2)&lt;/strong&gt;: Private IP 10.0.0.12&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VM 4 (Worker Node 3)&lt;/strong&gt;: Private IP 10.0.0.13&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I used random private IPs, but you should substitute them with your real VMs' private IPs.&lt;/p&gt;
&lt;h4 id=&quot;2-install-docker&quot;&gt;2. Install Docker&lt;/h4&gt;
&lt;p&gt;Next, you will need to install Docker and Docker Compose on every VM. The installation commands will depend on your specific Linux distribution, so refer to the official Docker documentation for your OS.&lt;/p&gt;
&lt;p&gt;You will no longer use a single master compose file for the cluster. Instead, you deploy an isolated, optimized compose layout directly on each corresponding VM instance.&lt;/p&gt;
&lt;h4 id=&quot;3-the-coordinator-instance-vm-1-&quot;&gt;3. The Coordinator Instance (VM 1)&lt;/h4&gt;
&lt;p&gt;Create a &lt;code&gt;docker-compose.yml&lt;/code&gt; file specifically tailored to map the Postgres engine port directly out to the host VM network interface:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;services:
  master:
    container_name: &quot;citus_coordinator&quot;
    image: &quot;citusdata/citus:14.1.0&quot;
    ports:
      - &quot;5432:5432&quot;
    restart: always
    environment:
      POSTGRES_USER: &quot;citus_admin&quot;
      POSTGRES_PASSWORD: &quot;YOUR_SUPER_SECURE_PRODUCTION_PASSWORD&quot;
      PGUSER: &quot;citus_admin&quot;
      PGPASSWORD: &quot;YOUR_SUPER_SECURE_PRODUCTION_PASSWORD&quot;
      POSTGRES_HOST_AUTH_METHOD: &quot;scram-sha-256&quot;
    volumes:
      - coordinator_data:/var/lib/postgresql/data

volumes:
  coordinator_data:
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;4-the-worker-instances-vms-2-3-and-4-&quot;&gt;4. The Worker Instances (VMs 2, 3, and 4)&lt;/h4&gt;
&lt;p&gt;Every worker VM gets its own standalone compose file. Notice we expose port 5432 on the workers too, because the coordinator node needs a direct network pipe to talk to them:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;services:
  worker:
    container_name: &quot;citus_worker&quot;
    image: &quot;citusdata/citus:14.1.0&quot;
    ports:
      - &quot;5432:5432&quot;
    restart: always
    environment:
      POSTGRES_USER: &quot;citus_admin&quot;
      POSTGRES_PASSWORD: &quot;YOUR_SUPER_SECURE_PRODUCTION_PASSWORD&quot;
      PGUSER: &quot;citus_admin&quot;
      PGPASSWORD: &quot;YOUR_SUPER_SECURE_PRODUCTION_PASSWORD&quot;
      POSTGRES_HOST_AUTH_METHOD: &quot;scram-sha-256&quot;
    volumes:
      - worker_data:/var/lib/postgresql/data

volumes:
  worker_data:
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;5-configure-network-firewall-security&quot;&gt;5. Configure Network Firewall Security&lt;/h4&gt;
&lt;p&gt;Since you are running across independent cloud instances, your cloud platform's Security Groups or Firewalls (like AWS Security Groups or ufw on Ubuntu) must be strictly configured to prevent public database scanning.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;On the Coordinator VM (VM 1)&lt;/strong&gt;: Allow inbound TCP traffic on port 5432 from Anywhere (0.0.0.0/0) only if your external application servers need public access. If your application servers are in the same VPC, restrict inbound port 5432 access exclusively to your app servers' IP subnet range.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;On the Worker VMs (VMs 2, 3, 4)&lt;/strong&gt;: Allow inbound TCP traffic on port 5432 EXCLUSIVELY from the Coordinator's Private IP (10.0.0.10). Block all other inbound network requests to the workers. They should never be exposed to the internet.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next, log in to each VM and run the containers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once all containers are healthy, access the interactive postgres interface on VM 1 (the coordinator node):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker compose exec master psql -U citus_admin
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Register your external worker instances using their physical Private VPC IP addresses:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT citus_add_node('10.0.0.11', 5432); -- Register Worker VM 2
SELECT citus_add_node('10.0.0.12', 5432); -- Register Worker VM 3
SELECT citus_add_node('10.0.0.13', 5432); -- Register Worker VM 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Verify everything works:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT * FROM master_get_active_worker_nodes();
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;6-configure-production-password-authentication&quot;&gt;6. Configure Production Password Authentication&lt;/h4&gt;
&lt;p&gt;Because we updated &lt;code&gt;POSTGRES_HOST_AUTH_METHOD&lt;/code&gt; to &lt;code&gt;scram-sha-256&lt;/code&gt; for security, your instances will require passwords to authenticate cross-node.&lt;/p&gt;
&lt;p&gt;We must add a Postgres password passfile on the coordinator container:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker compose exec master bash -c &quot;echo '*:*:*:citus_admin:YOUR_SUPER_SECURE_PRODUCTION_PASSWORD' &amp;gt;&amp;gt; /var/lib/postgresql/.pgpass &amp;amp;&amp;amp; chmod 600 /var/lib/postgresql/.pgpass&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Surely you will know to replace &lt;code&gt;YOUR_SUPER_SECURE_PRODUCTION_PASSWORD&lt;/code&gt; with your actual password.&lt;/p&gt;
&lt;p&gt;Here is a detailed documentation of Citus multi-node installation and setup for reference: &lt;a rel=&quot;nofollow&quot; href=&quot;https://learn.microsoft.com/en-us/postgresql/citus/multi-node-ubuntu-debian?view=citus-14&quot;&gt;Citus Multi-Node Setup&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;adding-citus-to-an-existing-project&quot;&gt;Adding Citus to an Existing Project&lt;/h3&gt;
&lt;p&gt;To add Citus to an already existing Postgres database project, the process follows these general steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Install the Extension&lt;/strong&gt;: Install the Citus extension on your Postgres server. You will also need to add &lt;code&gt;citus&lt;/code&gt; to the &lt;code&gt;shared_preload_libraries&lt;/code&gt; in your &lt;code&gt;postgresql.conf&lt;/code&gt; file and restart the database.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Create the Extension&lt;/strong&gt;: Run &lt;code&gt;CREATE EXTENSION citus;&lt;/code&gt; in your database.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Select a Shard Key&lt;/strong&gt;: Identify the column that will serve as the shard key for your distributed tables, such as a company or tenant ID.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Convert Tables&lt;/strong&gt;: Use &lt;code&gt;create_distributed_table()&lt;/code&gt; to convert your existing tables into distributed tables. Use &lt;code&gt;create_reference_table()&lt;/code&gt; for lookup tables that do not need to be sharded.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Migrate Data&lt;/strong&gt;: If you already have data in the tables, it might need to be exported and loaded back in, depending on the volume of data and the specific requirements of the migration.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Database sharding is an incredibly powerful architectural pattern, but it comes with immense operational tradeoffs. By using tools like Citus, we can bridge the gap between standard relational SQL databases and massively distributed systems.&lt;/p&gt;
&lt;p&gt;Whether you are starting a new multi-tenant application or scaling out an existing infrastructure, adopting a distributed mindset and orchestrating your local environments with tools like Citus and Docker Compose will save you countless hours of architectural nightmares down the road.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You can find the full Docker Compose source code for this tutorial on GitHub:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/umohsamuel/database-sharding&quot;&gt;umohsamuel/database-sharding&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://cloud.google.com/discover/what-is-database-sharding&quot;&gt;What is Database Sharding? (Google Cloud)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://aws.amazon.com/what-is/database-sharding/&quot;&gt;What is Database Sharding? (AWS)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/citusdata/docker/blob/master/docker-compose.yml&quot;&gt;Citus Docker Compose Setup&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/28711/horizontally-scaling-postgresql-database-sharding-with-citus</guid>
<pubDate>Sat, 26 Sep 2026 10:35:35 +0000</pubDate>
</item>
<item>
<title>The Decentralized Storage Revolution: Exploring SIA's Tech Exploring S3 gateway with Sia's renterd.</title>
<link>https://coderlegion.com/25307/decentralized-storage-revolution-exploring-sias-tech-exploring-gateway-with-sias-renterd</link>
<description>&lt;p&gt;The Decentralized Storage Revolution: Exploring SIA’s Cutting Edge Technology.&lt;/p&gt;
&lt;p&gt;Table Of Contents&lt;/p&gt;
&lt;p&gt;Brief about SIA&lt;br&gt;
Rivals in the industry&lt;br&gt;
Exclusiveness of SIA&lt;br&gt;
Security of SIA protocol.&lt;br&gt;
Enters Renterd.&lt;br&gt;
Renterd’s user interface.&lt;br&gt;
Storage Utility.&lt;br&gt;
Notable Improvement made by Renterd.&lt;br&gt;
SIA’s S3-compatible gateway.&lt;br&gt;
Ways Renterd could be used with S3.&lt;br&gt;
Interplanetary File System.&lt;br&gt;
Sharing a data file.&lt;br&gt;
Benefits of SIA’s decentralized storage technology.&lt;br&gt;
Reference.&lt;/p&gt;
&lt;p&gt;Brief about SIA&lt;/p&gt;
&lt;p&gt;Launched in 2015, Sia protocol curved out an enviable name in decentralized storage cloud storage ecosystem. It is a secure and trustless blockchain protocol, amongst the first, to integrate the principle of idle storage space leasing to users in its mechanism, making it the pioneer layer zero storage chain in the crypto sphere.&lt;br&gt;
Sia has several innovative products and services which include Hostd, Walletd and Renterd. Users in need of storage spaces are provided same on a rental basis. Sia’s utility is powered by its own token, Siacoin (SC).Founded by David Vorick and Luke Champine, Sia is named after the god of perception in ancient Egypt and has weathered the storm in the competitive world of blockchain technology.&lt;/p&gt;
&lt;p&gt;Rivals in the industry&lt;/p&gt;
&lt;p&gt;At the time that Sia was founded, it emerged as a notable rival to the likes of Google, Microsoft, Apple and amazon which are centralized storage systems up to this day. In like manner, several other companies like Bitquery, Zap3, and Footprint analytics are Sia’s competitors today. This is good for decentralization and Innovation.&lt;/p&gt;
&lt;p&gt;Exclusiveness of SIA&lt;/p&gt;
&lt;p&gt;Sia distinguished itself from existing centralized storage structures by its decentralized mechanism which enhanced lower rates of internet storage facility. A synergy between leasers and renters of storage space has streamlined a special kind of peer to peer business relationship implemented by Sia’s immutable and trustless smart contract technology.&lt;br&gt;
In place of fiat currency which is the norm with traditional hubs, the use of Siacoin as the choice of payment created a utility need in the Sia network. In terms of its storage mechanism, Sia utilizes encrypted files which are stored in 30 fragments and each fragment hosted across the world. In the common day parlance, is said to utilize the shard technology.&lt;/p&gt;
&lt;p&gt;Security of Sia protocol&lt;/p&gt;
&lt;p&gt;Like Bitcoin, the safety of the Sia protocol is guaranteed by proof of work consensus where the majority of workers are required to approve a mined block in addition to an intense mining competition among them.&lt;br&gt;
Collaterals are required of decentralized computers wanting to host on the Sia protocols and this requirement safeguards the protocol against their intentions to defraud or attack the network.&lt;br&gt;
The segregation of encrypted files into 30 fragments also protect the protocol in the eventuality of a natural disaster as there is the unlikelihood of a natural disaster happening simultaneously across the world where these segments are hosted.&lt;/p&gt;
&lt;p&gt;Enters Renterd&lt;/p&gt;
&lt;p&gt;Having been a robust network through progressive development and research, Sia is up with Renterd, a new software, galvanized for storage app developers and storage space users. Developed by the Sia foundation, Renterd succeeded Siad which was the previous data renting software utilized by Sia protocol since her inception.&lt;br&gt;
Renterd is meant to improve on Siad’s performance even though it was built from the ground up. It remedied scalability, flexibility, usability and interface issues that were found wanting in Siad. In the area of scalability, Renterd is integrated with a horizontal scalability which consist of an autopilot, a bus and a worker; each of these components has an API.&lt;br&gt;
However, all the 3 apparatuses can defaultedly function as a single unit or separately by customization. The autopilot integrates communication with the bus and the worker. The bus encompasses all the codes and the worker manages task-related communication with the hosting nodes.&lt;/p&gt;
&lt;p&gt;Renterd’s User Interface.&lt;/p&gt;
&lt;p&gt;The user interface in Renterd is designed to be web-friendly and with authentication features, making it handy for devices and by remote means. Through the employment of metrics, chronological data can be viewed. The user interface has a placement of an alert system where users and host nodes are timely informed about current events in the Sia network, a deviation from the status quo with Siad where users had to login before they can access relevant network communication.&lt;br&gt;
Developers outside the Sia network can also integrate with Sia webhook API to customize their own environment alert systems such as chat bots. Sia’ Renterd is crafted for compatibility with S3, a standardized cloud storage platform and through the use of APIs, users can now store their data on Sia network as a cloud folder or file without having to resort to the use of disks.&lt;/p&gt;
&lt;p&gt;Storage Utility.&lt;/p&gt;
&lt;p&gt;Storage utility has not been left out in Renterd’s design. To minimize storage waste, Renterd comes with a dual feature to improve storage efficiency: contract pruning and built-in upload packing. In the era of Siad, users’ data were inerasable and this means continuous storage cost.&lt;br&gt;
Also by default, files as small as 1kb , are amplified or padded to a size of 40MB before being uploaded and this is obviously unproductive With Renterd, the integration of these two storage utility features now make storage cost less expensive, expands utility and eliminates waste.&lt;/p&gt;
&lt;p&gt;Notable Improvement made by Renterd&lt;/p&gt;
&lt;p&gt;Workers can now extract files via uploading and downloading in a single effective process.&lt;br&gt;
Utilization of an array of SQL databases to erase downtime on the network, thus improving usability for large industries and single users.&lt;br&gt;
User and remote friendly interface which is made possible by Bus hosting.&lt;br&gt;
Establishment of node health surveillance unswervingly from the user interface.&lt;br&gt;
Implementation of Sia-Amazon S3 compatibility and integration.&lt;br&gt;
Waste mitigation through the use of built-in upload packing and contract pruning.&lt;br&gt;
Promotion of privacy through enhanced encryption.&lt;/p&gt;
&lt;p&gt;Sia’s S3-compatible gateway.&lt;/p&gt;
&lt;p&gt;It’s mentioned how Renterd was designed for compatibility with S3 which is a simple storage service developed by amazon web services in 2006. S3 is a storage service that employs cloud technology. It stores myriad forms of data ranging from analytics to web applications. It has a robust encryption which protects users from privacy intrusion through control mechanisms such as buckets, access control lists (ACLs) and identity and access management (IAM).&lt;br&gt;
Ways Renterd could be used with S3.&lt;br&gt;
Renterd could be used as an IPFS data reservoir in the absence of a tangible space. Backing up files onto Sia’s grid using S3 responsive gears and setting up an object container (Bucket) locally as a dossier are extra ways which users can use Sia’s S3 compatible gateway.&lt;/p&gt;
&lt;p&gt;Interplanetary File System.&lt;/p&gt;
&lt;p&gt;IFPS is a file sharing technological structure that utilizes encrypted and decentralized distribution mechanism. It is the abbreviated form for Interplanetary file system. To share a data in a peer to peer mode, the user is required to install and activate a node. IFPS gateways are needed and set up to increase the web availability of IFPS.&lt;br&gt;
Each IFPS node set up is carried using Renterd, a plugin and an IFPS gateway before making it available for public. The public gateway also needs a Renterd server, a domain name and a web server. First, the potential user needs to set up Renterd followed by S3 gateway and a public gateway.&lt;/p&gt;
&lt;p&gt;Sharing a data file.&lt;/p&gt;
&lt;p&gt;When these set ups are effectively running, the user shares data by way of uploading or downloading. To do this, he should access Sia website and generate storage space after funding Sia wallet with Siacoin. Then, he needs to launch Sia gateway on his S3 gateway and generate object buckets before sharing a file.&lt;br&gt;
The flow of file sharing are reversal for uploading and downloading. The former requires files to be transferred to Sia from a server where they have been momentarily stockpiled and the upload completion cycle is reached when the redundancy level is 1x. Sia then amplifies the redundancy threshold to 10x. The reverse is the case when files are being downloaded (from Sia to S3 and public servers). Both process flows utilize encryption and only permitted users can access any shared file.&lt;/p&gt;
&lt;p&gt;Benefits of Sia’s decentralized storage technology&lt;/p&gt;
&lt;p&gt;Decentralized storage technology enhances data security, maintains user’s privacy, supplants the monopoly of gigantic data industries, promotes sufficient control on one’s data, reduces the frequent risks of data violations, makes uploaded data readily available, checks unlawful access to data, mitigate abuse of data.&lt;/p&gt;
&lt;p&gt;Conclusion&lt;/p&gt;
&lt;p&gt;The Sia protocol and its accessories have proven to be pliable, useful, and viable. With approximately a decade of operation, it has explored and curated a data sharing and storage software packed with tested innovative features which are compatible with S3 portal.&lt;br&gt;
Decentralized data storage systems are here to stay. In an epoch characterized by authoritative control by centralized institutions and counter forces of democracy, privacy and freedom, Sia’s decentralized storage projects shall remain relevant in the blockchain ecosystem.&lt;/p&gt;
&lt;h3 id=&quot;reference&quot;&gt;Reference&lt;/h3&gt;
&lt;p&gt;Alphagrowth (2023). Top 6 Sia competitors andalternatives.&lt;a rel=&quot;nofollow&quot; href=&quot;https://alphagrowth.io/siacoin/competitors&quot;&gt;https://alphagrowth.io/siacoin/competitors&lt;/a&gt;&lt;br&gt;
Bitdegree (2023)What is amazon S3. &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.bitdegree.org/crypto/learn/crypto-terms/what-is-amazon-s3&quot;&gt;https://www.bitdegree.org/crypto/learn/crypto-terms/what-is-amazon-s3&lt;/a&gt;&lt;br&gt;
Coinweb (2024).What is Amazon S3? &lt;a rel=&quot;nofollow&quot; href=&quot;https://coinweb.com/wiki/amazon-s3/&quot;&gt;https://coinweb.com/wiki/amazon-s3/&lt;/a&gt;&lt;br&gt;
Devpost (2023) Renterd Innovate &lt;a rel=&quot;nofollow&quot; href=&quot;https://renterdinnovate2023.devpost.com/?utm_source=devpost&amp;amp;utm_medium=alert&amp;amp;utm_campaign=20231222_allinterest&quot;&gt;https://renterdinnovate2023.devpost.com/?utm_source=devpost&amp;amp;utm_medium=alert&amp;amp;utm_campaign=20231222_allinterest&lt;/a&gt;&lt;br&gt;
Herbert, Z. (2017) Introducing S3-style file sharing for Sia through the new minio integration. &lt;a rel=&quot;nofollow&quot; href=&quot;https://blog.sia.tech/introducing-s3-style-file-sharing-for-sia-through-the-new-minio-integration-bb880af2366a&quot;&gt;https://blog.sia.tech/introducing-s3-style-file-sharing-for-sia-through-the-new-minio-integration-bb880af2366a&lt;/a&gt;&lt;br&gt;
Ink, S. (2023) Sia S3 Integration: IPFS. Creating a public IPFS gateway backed by Sia &lt;a rel=&quot;nofollow&quot; href=&quot;https://blog.sia.tech/sia-s3-integration-ipfs-ac9f50fb3a5d&quot;&gt;https://blog.sia.tech/sia-s3-integration-ipfs-ac9f50fb3a5d&lt;/a&gt;&lt;br&gt;
Ink, S.(2023) The state of Sia. &lt;a rel=&quot;nofollow&quot; href=&quot;https://blog.sia.tech/the-state-of-sia-december-2023-0973db5b4d94&quot;&gt;https://blog.sia.tech/the-state-of-sia-december-2023-0973db5b4d94&lt;/a&gt;&lt;br&gt;
Oracle cloud infrastructure (2024) Object storage buckets. &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.oracle.com/en-us/iaas/Content/Object/Tasks/managingbuckets.htm&quot;&gt;https://docs.oracle.com/en-us/iaas/Content/Object/Tasks/managingbuckets.htm&lt;/a&gt;&lt;br&gt;
Schinnerl, C .(2023).The next generation of renting Sia storage. &lt;a rel=&quot;nofollow&quot; href=&quot;https://blog.sia.tech/the-next-generation-of-renting-sia-storage-releasing-renterd-v1-0-42ac9ae6d0e8&quot;&gt;https://blog.sia.tech/the-next-generation-of-renting-sia-storage-releasing-renterd-v1-0-42ac9ae6d0e8&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/25307/decentralized-storage-revolution-exploring-sias-tech-exploring-gateway-with-sias-renterd</guid>
<pubDate>Mon, 24 Aug 2026 20:38:05 +0000</pubDate>
</item>
</channel>
</rss>