Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Architecting a Scalable Heterogeneous Distributed Object Storage Service

Tech Aug 3 1

Distributed object storage systems require a decoupled architecture that separates request handling, metadata coordination, physical persistnece, and data routing. The following implementation outlines core components using Python for rapid prototyping and C++ for performance-critical paths.

Request Handling & API Gateway

The entry point manages authentication, rate limiting, and initial payload validation. Using asynchronous handlers prevents I/O blocking during file transfers.

Python Implementation

import asyncio
from typing import Dict, Any
from fastapi import FastAPI, UploadFile, File, HTTPException

app = FastAPI(title="StorageGateway")

class AuthMiddleware:
    def __init__(self):
        self.sessions: Dict[str, str] = {}

    def validate_token(self, token: str) -> bool:
        return token in self.sessions

middleware = AuthMiddleware()

@app.post("/auth/token")
async def create_session(credentials: dict) -> dict:
    # Token generation logic omitted for brevity
    token = f"sess_{id(credentials)}"
    middleware.sessions[token] = credentials.get("user_id")
    return {"token": token}

@app.post("/objects/upload")
async def ingest_object(token: str = ..., file: UploadFile = File(...)):
    if not middleware.validate_token(token):
        raise HTTPException(401, "Invalid credentials")
    # Pipeline passes validated data to the distribution layer
    return {"status": "accepted", "handler": "routing_service"}

C++ Implementation

#include <httplib.h>
#include <string>
#include <unordered_map>
#include <cstdlib>
#include <ctime>

class SessionRegistry {
public:
    bool is_valid(const std::string& token) const {
        return sessions_.find(token) != sessions_.end();
    }
    void register_session(const std::string& token, const std::string& user) {
        sessions_[token] = user;
    }
private:
    std::unordered_map<std::string, std::string> sessions_;
};

static SessionRegistry auth_registry;

int main() {
    srand(time(nullptr));
    httplib::Server server;
    server.Post("/v1/auth/session", [](const httplib::Request&, httplib::Response& res) {
        auth_registry.register_session("gen-" + std::to_string(rand()), "admin");
        res.set_content(R"({"state":"authenticated"})", "application/json");
    });
    server.Post("/v1/objects/bulk", [](const httplib::Request& req, httplib::Response& res) {
        auto token = req.get_header_value("X-Auth-Token");
        if (!auth_registry.is_valid(token)) {
            res.status = 401;
            return;
        }
        // Forward to internal router
        res.set_content(R"({"code":"queued"})", "application/json");
    });
    server.listen("0.0.0.0", 8080);
    return 0;
}

Metadata Coordination Layer

File attributes, checksums, and replication factors must be tracked atomically. A thread-safe map ensures consistency across concurrent read/write operations.

Unified Logic Pattern Both language stacks utilize a synchronized registry to prevent race conditions during concurrent metadata updates.

Python Example

import threading
from typing import Optional, Dict

class AttributeStore:
    def __init__(self):
        self._cache: Dict[str, Dict] = {}
        self._lock = threading.RLock()

    def persist_attributes(self, obj_key: str, attrs: Dict) -> None:
        with self._lock:
            self._cache[obj_key] = attrs.copy()

    def retrieve_attributes(self, obj_key: str) -> Optional[Dict]:
        with self._lock:
            return self._cache.get(obj_key)

    def revoke_access(self, obj_key: str) -> bool:
        with self._lock:
            return self._cache.pop(obj_key, None) is not None

C++ Example

#include <unordered_map>
#include <mutex>
#include <optional>
#include <string>

struct NodeAttributes {
    uint64_t size_bytes;
    int replication_factor;
};

class CatalogService {
public:
    void upsert_entry(const std::string& key, const NodeAttributes& meta) {
        std::lock_guard<std::mutex> guard(catalog_mutex_);
        catalog_[key] = meta;
    }

    std::optional<NodeAttributes> fetch_entry(const std::string& key) const {
        std::lock_guard<std::mutex> guard(catalog_mutex_);
        auto it = catalog_.find(key);
        return (it != catalog_.end()) ? std::make_optional(it->second) : std::nullopt;
    }

    bool remove_entry(const std::string& key) {
        std::lock_guard<std::mutex> guard(catalog_mutex_);
        return catalog_.erase(key) > 0;
    }

private:
    mutable std::mutex catalog_mutex_;
    std::unordered_map<std::string, NodeAttributes> catalog_;
};

Physical Persistence Adapter

Raw byte streams are written to localized disk volumes. The adapter abstracts unedrlying filesystem variations.

Python Adapter

import os
from pathlib import Path

class DiskBackend:
    def __init__(self, mount_point: str):
        self.root = Path(mount_point)
        self.root.mkdir(parents=True, exist_ok=True)

    def commit_blob(self, target_id: str, payload: bytes) -> bool:
        dest = self.root / target_id
        try:
            dest.write_bytes(payload)
            return True
        except OSError:
            return False

    def extract_blob(self, target_id: str) -> bytes | None:
        src = self.root / target_id
        if src.exists():
            return src.read_bytes()
        return None

C++ Adapter

#include <fstream>
#include <string>
#include <vector>
#include <filesystem>

class BlockWriter {
public:
    explicit BlockWriter(const std::string& base_dir) : base_dir_(base_dir) {
        std::filesystem::create_directories(base_dir);
    }

    bool write_segment(const std::string& segment_id, const std::vector<uint8_t>& data) {
        std::ofstream out(base_dir_ + "/" + segment_id, std::ios::binary | std::ios::trunc);
        if (!out.is_open()) return false;
        out.write(reinterpret_cast<const char*>(data.data()), data.size());
        return out.good();
    }

    std::vector<uint8_t> read_segment(const std::string& segment_id) {
        std::ifstream in(base_dir_ + "/" + segment_id, std::ios::binary);
        return std::vector<uint8_t>((std::istreambuf_iterator<char>(in)),
                                    std::istreambuf_iterator<char>());
    }

private:
    std::string base_dir_;
};

Distributive Routing Engine

Data chunking requires deterministic placement algorithms. Virtual node mapping reduces hotspotting compared to naive modulo hashing.

Python Routing Service

import hashlib
from typing import List, Dict

class RingRouter:
    def __init__(self, targets: List, replicas_per_node: int = 150):
        self.ring: List[tuple] = []
        self.node_map: Dict[int, str] = {}
        self._build_virtual_ring(targets, replicas_per_node)

    def _build_virtual_ring(self, targets: List, vnodes: int) -> None:
        for target in targets:
            for i in range(vnodes):
                hash_val = int(hashlib.md5(f"{target}-{i}".encode()).hexdigest(), 16)
                self.ring.append(hash_val)
                self.node_map[hash_val] = target
        self.ring.sort()

    def resolve_target(self, item_key: str) -> str:
        key_hash = int(hashlib.sha256(item_key.encode()).hexdigest(), 16)
        idx = 0
        while idx < len(self.ring) and self.ring[idx] < key_hash:
            idx += 1
        idx %= len(self.ring)
        return self.node_map[self.ring[idx]]

C++ Routing Service

#include <vector>
#include <cstdint>
#include <algorithm>
#include <functional>
#include <string>

struct HashedEntry {
    uint64_t hash_val;
    std::string node_id;
};

class ConsistentAllocator {
public:
    explicit ConsistentAllocator(const std::vector<std::string>& cluster_nodes, int vnodes = 150) {
        for (const auto& nid : cluster_nodes) {
            for (int i = 0; i < vnodes; ++i) {
                std::string seed = nid + "-" + std::to_string(i);
                HashedEntry entry{std::hash<std::string>{}(seed), nid};
                ring_.push_back(entry);
            }
        }
        std::sort(ring_.begin(), ring_.end(), [](const HashedEntry& a, const HashedEntry& b){
            return a.hash_val < b.hash_val;
        });
    }

    std::string assign_slot(const std::string& object_id) const {
        uint64_t target = std::hash<std::string>{}(object_id);
        auto it = std::lower_bound(ring_.begin(), ring_.end(), target,
            [](const HashedEntry& e, uint64_t val){ return e.hash_val < val; });
        if (it == ring_.end()) it = ring_.begin();
        return it->node_id;
    }

private:
    std::vector<HashedEntry> ring_;
};

Network Transport Handler

Cross-node synchronization utilizes connection pooling and buffered I/O to minimize latency during replica propagation.

Python Transfer Unit

import aiohttp
from typing import Dict

class PipeLine:
    def __init__(self):
        self.client = aiohttp.ClientSession()

    async def propagate_chunk(self, endpoint: str, chunk_data: bytes) -> int:
        async with self.client.post(endpoint, data=chunk_data) as resp:
            return resp.status

    async def sync_replica(self, source_url: str) -> bytes:
        async with self.client.get(source_url) as resp:
            return await resp.read()

C++ Transport Unit

#include <curl/curl.h>
#include <string>
#include <iostream>

class NetBridge {
public:
    NetBridge() { curl_global_init(CURL_GLOBAL_DEFAULT); }
    ~NetBridge() { curl_global_cleanup(); }

    int upload_payload(const std::string& dest_url, const std::string& payload) {
        CURL* handle = curl_easy_init();
        if (!handle) return CURLE_FAILED_INIT;

        curl_easy_setopt(handle, CURLOPT_URL, dest_url.c_str());
        curl_easy_setopt(handle, CURLOPT_POST, 1L);
        curl_easy_setopt(handle, CURLOPT_POSTFIELDS, payload.c_str());
        curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, payload.length());
        curl_easy_setopt(handle, CURLOPT_TIMEOUT, 30L);

        CURLcode res = curl_easy_perform(handle);
        long http_code = 0;
        curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &http_code);

        curl_easy_cleanup(handle);
        return static_cast<int>(http_code);
    }

    std::string fetch_remote_block(const std::string& remote_addr) {
        std::string buffer;
        CURL* handle = curl_easy_init();
        if (!handle) return "";

        curl_easy_setopt(handle, CURLOPT_URL, remote_addr.c_str());
        curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, OnWriteData);
        curl_easy_setopt(handle, CURLOPT_WRITEDATA, &buffer);

        curl_easy_perform(handle);
        curl_easy_cleanup(handle);
        return buffer;
    }

private:
    static size_t OnWriteData(void* buffer, size_t size, size_t nmemb, void* stream) {
        ((std::string*)stream)->append((char*)buffer, size * nmemb);
        return size * nmemb;
    }
};

Health Observer & Remediation Loop

Continuous probing detects degraded endpoints. Failed nodes are temporarily excluded from the active ring until recovery verification succeeds.

Python Monitor

import time
from concurrent.futures import ThreadPoolExecutor
from threading import Thread

class Sentinel:
    def __init__(self, active_nodes):
        self.active = set(active_nodes)
        self.executor = ThreadPoolExecutor(max_workers=4)

    def run_diagnostic_cycle(self):
        while True:
            for node in list(self.active):
                future = self.executor.submit(self._probe_health, node)
                if not future.result():
                    self.active.discard(node)
            time.sleep(15)

    def _probe_health(self, target: str) -> bool:
        # Mock health check simulation
        return True

C++ Monitor

#include <thread>
#include <chrono>
#include <set>
#include <atomic>
#include <string>

class Watchdog {
public:
    explicit Watchdog(std::set<std::string> members) : members_(std::move(members)) {}

    void execute_scan_cycle() {
        while (running_) {
            for (auto it = members_.begin(); it != members_.end();) {
                if (!verify_connectivity(*it)) {
                    it = members_.erase(it);
                } else {
                    ++it;
                }
            }
            std::this_thread::sleep_for(std::chrono::seconds(15));
        }
    }

    void stop() { running_ = false; }

private:
    bool verify_connectivity(const std::string& node) {
        // TCP handshake or HTTP ping logic
        return true;
    }

    std::set<std::string> members_;
    std::atomic<bool> running_{true};
};

System Orchestrator

Initialization sequences instantiate dependencies, wire communication channels, and launch background daemons concurrently.

Python Launcher

from threading import Thread

def bootstrap_cluster():
    registry = AttributeStore()
    backend = DiskBackend("/mnt/data/volume_01")
    router = RingRouter(["node-a:9000", "node-b:9000"])
    pipeline = PipeLine()
    monitor = Sentinel(router.node_map.values())

    daemon_threads = [
        Thread(target=monitor.run_diagnostic_cycle, daemon=True),
        Thread(target=start_gateway, daemon=True)
    ]
    for t in daemon_threads:
        t.start()
    for t in daemon_threads:
        t.join()

C++ Launcher

#include <thread>
#include <memory>

// Forward declarations for orchestrator context
void start_http_daemon();

int orchestrate_startup() {
    auto catalog = std::make_unique<CatalogService>();
    auto writer = std::make_unique<BlockWriter>("/var/lib/storage/blk_01");
    auto allocator = std::make_unique<ConsistentAllocator>({"worker-1", "worker-2", "worker-3"});
    auto watcher = std::make_unique<Watchdog>({"worker-1", "worker-2", "worker-3"});

    std::thread svc_thread([&]() { start_http_daemon(); });
    std::thread mon_thread([&]() { watcher->execute_scan_cycle(); });

    svc_thread.join();
    mon_thread.join();
    return 0;
}

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

SBUS Signal Analysis and Communication Implementation Using STM32 with Fus Remote Controller

Overview In a recent project, I utilized the SBUS protocol with the Fus remote controller to control a vehicle's basic operations, including movement, lights, and mode switching. This article is aimed...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.