[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-sharding-vs-partitioning-arsitektur-tabel-masif":3},{"article":4,"author":58},{"id":5,"category_id":6,"title":7,"slug":8,"excerpt":9,"content_md":10,"content_html":11,"locale":12,"author_id":13,"published":14,"published_at":15,"meta_title":16,"meta_description":17,"focus_keyword":18,"og_image":19,"canonical_url":19,"robots_meta":20,"created_at":15,"updated_at":15,"tags":21,"category_name":24,"related_articles":39},"d2000000-0000-0000-0000-000000000126","a0000000-0000-0000-0000-000000000025","Sharding vs Partitioning — Arsitektur untuk Tabel Masif","sharding-vs-partitioning-arsitektur-tabel-masif","Perbandingan mendalam sharding dan partitioning: kapan menggunakan masing-masing, strategi sharding key, routing query, dan migrasi dari single-node ke arsitektur terdistribusi.","## Partitioning vs Sharding: Apa Bedanya?\n\n**Partitioning** membagi tabel menjadi beberapa bagian dalam satu server database. PostgreSQL mengelolanya secara transparan.\n\n**Sharding** mendistribusikan data ke beberapa server database yang berbeda. Aplikasi (atau middleware) bertanggung jawab routing query ke shard yang tepat.\n\n| Aspek | Partitioning | Sharding |\n|-------|-------------|----------|\n| Server | Satu | Banyak |\n| Transparansi | Otomatis | Manual\u002Fmiddleware |\n| Skalabilitas | Vertikal | Horizontal |\n| Kompleksitas | Rendah | Tinggi |\n| Cross-partition query | Mudah | Sulit\u002Flambat |\n| Batas | Hardware satu server | Teoritis tak terbatas |\n\n## Kapan Partitioning Cukup\n\nPartitioning cukup ketika:\n- Data muat di satu server (\u003C 1TB aktif)\n- Beban write \u003C 10.000 TPS\n- Perlu cross-partition query yang sering\n- Tim kecil tanpa expertise distributed systems\n\n## Kapan Harus Sharding\n\nPertimbangkan sharding ketika:\n- Data melebihi kapasitas satu server\n- Beban write > 10.000 TPS\n- Memerlukan isolasi multi-region\n- Ketersediaan 99.99%+ diperlukan\n\n## Strategi Shard Key\n\nPilihan shard key menentukan distribusi data dan pola query:\n\n### 1. Hash-Based Sharding\n```rust\nfn get_shard(user_id: Uuid, num_shards: u32) -> u32 {\n    let hash = xxhash(&user_id.as_bytes());\n    hash % num_shards\n}\n```\n\nDistribusi merata, tetapi range query harus menghubungi semua shard.\n\n### 2. Range-Based Sharding\n```rust\nfn get_shard(created_at: DateTime) -> &str {\n    match created_at.year() {\n        2024 => \"shard_2024\",\n        2025 => \"shard_2025\",\n        2026 => \"shard_2026\",\n        _ => \"shard_default\",\n    }\n}\n```\n\nCocok untuk data time-series. Shard lama bisa di-archive.\n\n### 3. Directory-Based Sharding\n```rust\nasync fn get_shard(tenant_id: Uuid, directory: &PgPool) -> String {\n    sqlx::query_scalar(\"SELECT shard_name FROM shard_directory WHERE tenant_id = $1\")\n        .bind(tenant_id)\n        .fetch_one(directory)\n        .await\n        .unwrap()\n}\n```\n\nFleksibel — bisa memindahkan tenant antar shard. Tetapi directory adalah single point of failure.\n\n## Implementasi Query Router di Rust\n\n```rust\nstruct ShardRouter {\n    shards: HashMap\u003Cu32, PgPool>,\n    num_shards: u32,\n}\n\nimpl ShardRouter {\n    fn get_pool(&self, shard_key: &Uuid) -> &PgPool {\n        let shard_id = xxhash(shard_key.as_bytes()) % self.num_shards;\n        &self.shards[&shard_id]\n    }\n    \n    async fn query_all\u003CT: FromRow>(\n        &self,\n        query: &str,\n    ) -> Result\u003CVec\u003CT>, DbError> {\n        let futures: Vec\u003C_> = self.shards.values()\n            .map(|pool| {\n                sqlx::query_as::\u003C_, T>(query)\n                    .fetch_all(pool)\n            })\n            .collect();\n        \n        let results = futures::future::try_join_all(futures).await?;\n        Ok(results.into_iter().flatten().collect())\n    }\n}\n```\n\n## Migrasi ke Sharding\n\n1. **Mulai dengan partitioning** — Lebih sederhana, selesaikan dulu\n2. **Identifikasi shard key** — Kolom yang paling sering di-filter\n3. **Dual-write** — Tulis ke database lama dan baru secara bersamaan\n4. **Verifikasi** — Bandingkan hasil query antara kedua sistem\n5. **Cutover** — Arahkan pembacaan ke sistem baru\n6. **Cleanup** — Hapus dual-write dan database lama\n\n## Tantangan Sharding\n\n1. **Cross-shard join** — Tidak bisa JOIN antar shard secara native\n2. **Transaksi terdistribusi** — 2-phase commit lambat dan kompleks\n3. **Rebalancing** — Menambah shard memerlukan redistribusi data\n4. **Operasional** — Monitoring, backup, dan upgrade lebih kompleks\n\n## Kesimpulan\n\nMulai dengan partitioning — ini menyelesaikan 90% masalah skala database. Sharding adalah langkah selanjutnya ketika satu server tidak lagi cukup. Pilih shard key berdasarkan pola query, implementasikan router query, dan rencanakan migrasi dengan hati-hati.","\u003Ch2 id=\"partitioning-vs-sharding-apa-bedanya\">Partitioning vs Sharding: Apa Bedanya?\u003C\u002Fh2>\n\u003Cp>\u003Cstrong>Partitioning\u003C\u002Fstrong> membagi tabel menjadi beberapa bagian dalam satu server database. PostgreSQL mengelolanya secara transparan.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Sharding\u003C\u002Fstrong> mendistribusikan data ke beberapa server database yang berbeda. Aplikasi (atau middleware) bertanggung jawab routing query ke shard yang tepat.\u003C\u002Fp>\n\u003Ctable>\u003Cthead>\u003Ctr>\u003Cth>Aspek\u003C\u002Fth>\u003Cth>Partitioning\u003C\u002Fth>\u003Cth>Sharding\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\n\u003Ctr>\u003Ctd>Server\u003C\u002Ftd>\u003Ctd>Satu\u003C\u002Ftd>\u003Ctd>Banyak\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Transparansi\u003C\u002Ftd>\u003Ctd>Otomatis\u003C\u002Ftd>\u003Ctd>Manual\u002Fmiddleware\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Skalabilitas\u003C\u002Ftd>\u003Ctd>Vertikal\u003C\u002Ftd>\u003Ctd>Horizontal\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Kompleksitas\u003C\u002Ftd>\u003Ctd>Rendah\u003C\u002Ftd>\u003Ctd>Tinggi\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Cross-partition query\u003C\u002Ftd>\u003Ctd>Mudah\u003C\u002Ftd>\u003Ctd>Sulit\u002Flambat\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Batas\u003C\u002Ftd>\u003Ctd>Hardware satu server\u003C\u002Ftd>\u003Ctd>Teoritis tak terbatas\u003C\u002Ftd>\u003C\u002Ftr>\n\u003C\u002Ftbody>\u003C\u002Ftable>\n\u003Ch2 id=\"kapan-partitioning-cukup\">Kapan Partitioning Cukup\u003C\u002Fh2>\n\u003Cp>Partitioning cukup ketika:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Data muat di satu server (&lt; 1TB aktif)\u003C\u002Fli>\n\u003Cli>Beban write &lt; 10.000 TPS\u003C\u002Fli>\n\u003Cli>Perlu cross-partition query yang sering\u003C\u002Fli>\n\u003Cli>Tim kecil tanpa expertise distributed systems\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"kapan-harus-sharding\">Kapan Harus Sharding\u003C\u002Fh2>\n\u003Cp>Pertimbangkan sharding ketika:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Data melebihi kapasitas satu server\u003C\u002Fli>\n\u003Cli>Beban write &gt; 10.000 TPS\u003C\u002Fli>\n\u003Cli>Memerlukan isolasi multi-region\u003C\u002Fli>\n\u003Cli>Ketersediaan 99.99%+ diperlukan\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"strategi-shard-key\">Strategi Shard Key\u003C\u002Fh2>\n\u003Cp>Pilihan shard key menentukan distribusi data dan pola query:\u003C\u002Fp>\n\u003Ch3>1. Hash-Based Sharding\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-rust\">fn get_shard(user_id: Uuid, num_shards: u32) -&gt; u32 {\n    let hash = xxhash(&amp;user_id.as_bytes());\n    hash % num_shards\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Distribusi merata, tetapi range query harus menghubungi semua shard.\u003C\u002Fp>\n\u003Ch3>2. Range-Based Sharding\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-rust\">fn get_shard(created_at: DateTime) -&gt; &amp;str {\n    match created_at.year() {\n        2024 =&gt; \"shard_2024\",\n        2025 =&gt; \"shard_2025\",\n        2026 =&gt; \"shard_2026\",\n        _ =&gt; \"shard_default\",\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Cocok untuk data time-series. Shard lama bisa di-archive.\u003C\u002Fp>\n\u003Ch3>3. Directory-Based Sharding\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-rust\">async fn get_shard(tenant_id: Uuid, directory: &amp;PgPool) -&gt; String {\n    sqlx::query_scalar(\"SELECT shard_name FROM shard_directory WHERE tenant_id = $1\")\n        .bind(tenant_id)\n        .fetch_one(directory)\n        .await\n        .unwrap()\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Fleksibel — bisa memindahkan tenant antar shard. Tetapi directory adalah single point of failure.\u003C\u002Fp>\n\u003Ch2 id=\"implementasi-query-router-di-rust\">Implementasi Query Router di Rust\u003C\u002Fh2>\n\u003Cpre>\u003Ccode class=\"language-rust\">struct ShardRouter {\n    shards: HashMap&lt;u32, PgPool&gt;,\n    num_shards: u32,\n}\n\nimpl ShardRouter {\n    fn get_pool(&amp;self, shard_key: &amp;Uuid) -&gt; &amp;PgPool {\n        let shard_id = xxhash(shard_key.as_bytes()) % self.num_shards;\n        &amp;self.shards[&amp;shard_id]\n    }\n    \n    async fn query_all&lt;T: FromRow&gt;(\n        &amp;self,\n        query: &amp;str,\n    ) -&gt; Result&lt;Vec&lt;T&gt;, DbError&gt; {\n        let futures: Vec&lt;_&gt; = self.shards.values()\n            .map(|pool| {\n                sqlx::query_as::&lt;_, T&gt;(query)\n                    .fetch_all(pool)\n            })\n            .collect();\n        \n        let results = futures::future::try_join_all(futures).await?;\n        Ok(results.into_iter().flatten().collect())\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"migrasi-ke-sharding\">Migrasi ke Sharding\u003C\u002Fh2>\n\u003Col>\n\u003Cli>\u003Cstrong>Mulai dengan partitioning\u003C\u002Fstrong> — Lebih sederhana, selesaikan dulu\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Identifikasi shard key\u003C\u002Fstrong> — Kolom yang paling sering di-filter\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Dual-write\u003C\u002Fstrong> — Tulis ke database lama dan baru secara bersamaan\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Verifikasi\u003C\u002Fstrong> — Bandingkan hasil query antara kedua sistem\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Cutover\u003C\u002Fstrong> — Arahkan pembacaan ke sistem baru\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Cleanup\u003C\u002Fstrong> — Hapus dual-write dan database lama\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2 id=\"tantangan-sharding\">Tantangan Sharding\u003C\u002Fh2>\n\u003Col>\n\u003Cli>\u003Cstrong>Cross-shard join\u003C\u002Fstrong> — Tidak bisa JOIN antar shard secara native\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Transaksi terdistribusi\u003C\u002Fstrong> — 2-phase commit lambat dan kompleks\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Rebalancing\u003C\u002Fstrong> — Menambah shard memerlukan redistribusi data\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Operasional\u003C\u002Fstrong> — Monitoring, backup, dan upgrade lebih kompleks\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2 id=\"kesimpulan\">Kesimpulan\u003C\u002Fh2>\n\u003Cp>Mulai dengan partitioning — ini menyelesaikan 90% masalah skala database. Sharding adalah langkah selanjutnya ketika satu server tidak lagi cukup. Pilih shard key berdasarkan pola query, implementasikan router query, dan rencanakan migrasi dengan hati-hati.\u003C\u002Fp>\n","id","b0000000-0000-0000-0000-000000000001",true,"2026-03-28T10:44:25.157532Z","Sharding vs Partitioning — Arsitektur Tabel Masif","Perbandingan sharding dan partitioning: kapan menggunakan, strategi shard key, implementasi router Rust, dan migrasi.","sharding vs partitioning",null,"index, follow",[22,27,31,35],{"id":23,"name":24,"slug":25,"created_at":26},"c0000000-0000-0000-0000-000000000012","DevOps","devops","2026-03-28T10:44:21.513630Z",{"id":28,"name":29,"slug":30,"created_at":26},"c0000000-0000-0000-0000-000000000022","Performance","performance",{"id":32,"name":33,"slug":34,"created_at":26},"c0000000-0000-0000-0000-000000000005","PostgreSQL","postgresql",{"id":36,"name":37,"slug":38,"created_at":26},"c0000000-0000-0000-0000-000000000001","Rust","rust",[40,46,52],{"id":41,"title":42,"slug":43,"excerpt":44,"locale":12,"category_name":24,"published_at":45},"d0000000-0000-0000-0000-000000000644","Platform Engineering Memakan DevOps: Membangun Internal Developer Platform di 2026","platform-engineering-memakan-devops-membangun-idp-2026","80% organisasi engineering besar kini memiliki tim platform khusus, naik dari 45% di 2024. Internal developer platform — portal self-service, infrastruktur yang sudah disetujui, guardrail otomatis — telah menjadi cara standar untuk menghadirkan DevOps secara besar-besaran.","2026-03-28T10:44:47.476351Z",{"id":47,"title":48,"slug":49,"excerpt":50,"locale":12,"category_name":24,"published_at":51},"d0000000-0000-0000-0000-000000000643","Observabilitas Tanpa Instrumentasi: Bagaimana eBPF Menggantikan Armada Sidecar","observabilitas-tanpa-instrumentasi-ebpf-menggantikan-armada-sidecar","67% tim Kubernetes kini menggunakan alat observabilitas berbasis eBPF, naik dari 29% di 2024. Dengan memindahkan pengumpulan telemetri ke kernel, eBPF menghilangkan kontainer sidecar, memangkas penggunaan RAM sebesar 84%, dan memberikan overhead CPU di bawah 1%.","2026-03-28T10:44:47.469045Z",{"id":53,"title":54,"slug":55,"excerpt":56,"locale":12,"category_name":24,"published_at":57},"d0000000-0000-0000-0000-000000000642","WASI 0.3 dan Kematian Cold Start: Wasm Sisi Server di Produksi","wasi-0-3-kematian-cold-start-wasm-sisi-server-di-produksi","WASI 0.3 dirilis pada Februari 2026 dengan async I\u002FO native, tipe stream, dan dukungan socket penuh. WebAssembly sisi server kini menghadirkan cold start dalam hitungan mikrodetik, dan setiap penyedia cloud besar menawarkan Wasm serverless.","2026-03-28T10:44:47.445780Z",{"id":13,"name":59,"slug":60,"bio":61,"photo_url":19,"linkedin":19,"role":62,"created_at":63,"updated_at":63},"Open Soft Team","open-soft-team","The engineering team at Open Soft, building premium software solutions from Bali, Indonesia.","Engineering Team","2026-03-28T08:31:22.226811Z"]