YugabyteDB: A Guide to Setting Up PostgreSQL-Compatible Distributed SQL with Auto-Sharding and Automatic Fault Tolerance

Database tutorial - IT technology blog
Database tutorial - IT technology blog

Quick Start: Run YugabyteDB in 5 Minutes

If you’re already familiar with PostgreSQL, good news — YugabyteDB works almost identically in terms of SQL syntax and tooling. The fastest way to try it out is with Docker:

docker pull yugabytedb/yugabyte

docker run -d --name yugabyte \
  -p 5433:5433 -p 7000:7000 -p 9000:9000 -p 9042:9042 \
  yugabytedb/yugabyte \
  bin/yugabyted start --daemon=false

Wait about 30 seconds, then try connecting:

psql -h 127.0.0.1 -p 5433 -U yugabyte -d yugabyte

Note the port 5433 (different from Postgres’s default 5432) to avoid conflicts if you’re running Postgres on the same machine. Once connected, create a test table:

CREATE TABLE employees (
  id SERIAL PRIMARY KEY,
  name VARCHAR(100) NOT NULL,
  department VARCHAR(50),
  created_at TIMESTAMP DEFAULT NOW()
);

INSERT INTO employees (name, department) VALUES
  ('Nguyen Van A', 'Engineering'),
  ('Tran Thi B', 'DevOps'),
  ('Le Van C', 'Backend');

SELECT * FROM employees;

It works — and this is already a distributed SQL database that you interact with exactly like Postgres. The web dashboard at http://localhost:7000 shows full cluster info, tablet distribution, and node health.

What Is YugabyteDB and Why Do You Need It?

A standalone Postgres instance handles most applications just fine — but once your data grows to tens of millions of records, write traffic spikes, or you need to deploy across multiple regions simultaneously, things start to strain. At that point, you have a few options: manual sharding in application code (complex and bug-prone), read replicas (only scales reads, not writes), or switching to a distributed database.

YugabyteDB was built to solve exactly that problem. Its internal architecture has three layers:

  • YSQL layer — PostgreSQL wire protocol compatible, reuses most SQL syntax and drivers
  • DocDB — a custom storage engine based on RocksDB, uses Raft consensus to ensure consistency across nodes
  • Tablet system — automatically splits data into shards (called tablets) and distributes them evenly across nodes

The biggest strength is auto-sharding — you don’t need to define shard keys or write routing logic in your app. YugabyteDB automatically rebalances when nodes are added or removed.

Key Differences from Plain Postgres

  • SERIAL sequence: has gaps (gaps are normal, not a bug) due to its distributed nature — if you need gap-free sequential IDs, use UUID instead
  • Foreign keys: work normally, but heavy joins between large tables require colocation to be declared
  • Extensions: supports pgcrypto, pg_stat_statements, and some popular extensions — but not the full extension ecosystem
  • Default port: 5433 for YSQL, 9042 for YCQL (Cassandra-compatible API)

Setting Up a Multi-Node Cluster

A single-node Docker setup is fine for dev/test. For a real cluster with fault tolerance, you need at least 3 nodes. Here’s an example with 3 machines at IPs: 192.168.1.1, 192.168.1.2, 192.168.1.3.

On each machine, download and extract:

wget https://downloads.yugabyte.com/releases/2.21.0.0/yugabyte-2.21.0.0-b545-linux-x86_64.tar.gz
tar xvfz yugabyte-2.21.0.0-b545-linux-x86_64.tar.gz
cd yugabyte-2.21.0.0/

Start each node in sequence:

# Node 1 — start first
./bin/yugabyted start \
  --advertise_address=192.168.1.1 \
  --cloud_location=aws.us-east-1.us-east-1a

# Node 2 — join Node 1
./bin/yugabyted start \
  --advertise_address=192.168.1.2 \
  --join=192.168.1.1 \
  --cloud_location=aws.us-east-1.us-east-1b

# Node 3 — join Node 1
./bin/yugabyted start \
  --advertise_address=192.168.1.3 \
  --join=192.168.1.1 \
  --cloud_location=aws.us-east-1.us-east-1c

Check the status:

./bin/yugabyted status

With the default replication factor of 3, if one node goes down the cluster keeps running normally — Raft consensus automatically elects a new leader without any manual intervention. This is a major difference from traditional Postgres Streaming Replication.

Multi-Region Configuration

To deploy across multiple regions (Tokyo + Singapore + Seoul, for example), just set the --cloud_location parameter to match the actual region:

# Tokyo node
./bin/yugabyted start \
  --advertise_address=10.0.1.1 \
  --join=10.0.1.1 \
  --cloud_location=aws.ap-northeast-1.ap-northeast-1a

# Singapore node
./bin/yugabyted start \
  --advertise_address=10.0.2.1 \
  --join=10.0.1.1 \
  --cloud_location=aws.ap-southeast-1.ap-southeast-1a

# Seoul node
./bin/yugabyted start \
  --advertise_address=10.0.3.1 \
  --join=10.0.1.1 \
  --cloud_location=aws.ap-northeast-2.ap-northeast-2a

Then use tablespaces to pin data to specific regions — reducing latency for users in each area:

CREATE TABLESPACE tokyo_ts WITH (
  replica_placement='{"num_replicas": 1, "placement_blocks": [
    {"cloud": "aws", "region": "ap-northeast-1", "zone": "ap-northeast-1a", "min_num_replicas": 1}
  ]}'
);

CREATE TABLE orders (
  id BIGSERIAL,
  user_id INT,
  region TEXT NOT NULL,
  amount DECIMAL(10,2),
  PRIMARY KEY (id, region)
) PARTITION BY LIST (region);

CREATE TABLE orders_tokyo PARTITION OF orders
  FOR VALUES IN ('tokyo')
  TABLESPACE tokyo_ts;

Practical Tips for Working with YugabyteDB

1. Use UUID Instead of SERIAL for Distributed Workloads

CREATE EXTENSION IF NOT EXISTS pgcrypto;

CREATE TABLE sessions (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  user_id INT,
  token TEXT,
  expires_at TIMESTAMP
);

UUIDs distribute more evenly across tablets, avoiding hotspots during high-volume inserts.

2. Colocation for Small Tables with Frequent Joins

-- Database with colocation — small tables share the same tablet
CREATE DATABASE myapp WITH COLOCATION = true;

-- Large tables opt out of colocation
CREATE TABLE large_events (...) WITH (COLOCATION = false);

3. Importing Data from CSV/JSON

When I need to import test data from CSV into the database, I usually convert it to JSON first, then use a Python script to import it. I often use the converter at toolcraft.app/en/tools/data/csv-to-json — it runs entirely in the browser so there’s no risk of data leakage, and it’s far more convenient than writing a conversion script by hand.

Once you have the JSON file, import it with Python using psycopg2 (connects exactly like Postgres):

import psycopg2
import json

conn = psycopg2.connect(
    host="127.0.0.1",
    port=5433,          # YugabyteDB YSQL port
    database="yugabyte",
    user="yugabyte",
    password="yugabyte"
)

with open("data.json") as f:
    records = json.load(f)

cur = conn.cursor()
for record in records:
    cur.execute(
        "INSERT INTO employees (name, department) VALUES (%s, %s)",
        (record["name"], record["department"])
    )

conn.commit()
cur.close()
conn.close()
print(f"Imported {len(records)} records")

4. Backup and Restore

# Backup — same syntax as pg_dump
./bin/ysql_dump -h 127.0.0.1 -p 5433 -U yugabyte yugabyte > backup.sql

# Restore
./bin/ysqlsh -h 127.0.0.1 -p 5433 -U yugabyte -d yugabyte -f backup.sql

5. Checking Health via REST API

# Overall health check
curl http://localhost:7000/api/v1/health-check

# Tablet distribution across nodes
curl http://localhost:7000/api/v1/tablet-servers

When Should You Use YugabyteDB?

Not every project needs distributed SQL. YugabyteDB is a good fit when:

  • You need to scale writes horizontally — write traffic exceeds what a single Postgres node can handle
  • You need multi-region active-active — users across different geographic regions need low latency
  • You want automatic fault tolerance without manually handling failovers at 3 AM
  • You want to keep your SQL — no desire to refactor to NoSQL or swap out your ORM

If your app is still running fine on a single Postgres node, there’s no rush to migrate. Distributed systems come with their own complexity — network latency between nodes, replication lag in edge cases. But when you’ve reached the point where scaling is necessary, YugabyteDB is the least painful option because you don’t have to rewrite queries or learn an entirely new data model.

Share: