Data Modeling Terms
Empat istilah dasar pemodelan data pada key-value database: key, value, namespace, schemaless.
Key
Key adalah referensi ke sebuah value — analog dengan alamat. Key bukan value, melainkan cara untuk menemukan dan memanipulasi value. Bentuk key bergantung implementasi:
- Minimal, key berupa string karakter, mis.
"Cust9876"atau"Patient:A384J:Allergies". - Beberapa key-value database (mis. Redis) mendukung struktur data lebih kompleks sebagai key: strings, lists, sets, sorted sets, hashes, bit arrays.
Key juga berperan penting dalam arsitektur skalabel — selain merujuk value, key dipakai untuk mengorganisasi data lintas banyak server.
Key-naming convention: pakai kombinasi nama tabel, nilai primary key, dan nama atribut untuk membuat key yang menyimpan nilai suatu atribut. Contoh:
customer:1982737:firstName
customer:1982737:lastName
customer:1982737:shippingAddress
customer:1982737:shippingCity
customer:1982737:shippingState
customer:1982737:shippingZip
Peringatan: jangan terlalu panjang (boros memori — key-value database cenderung memory-intensive) maupun terlalu pendek (rawan konflik nama key).
Value
Value adalah objek — umumnya sekumpulan byte — yang diasosiasikan dengan sebuah key. Bisa berupa integer, floating-point, string, BLOB (binary large object), konstruksi semi-terstruktur seperti objek JSON, gambar, audio, dan tipe data apapun yang bisa direpresentasikan sebagai rangkaian byte.
Tiap implementasi punya batasan berbeda untuk value, mis. Redis membolehkan string value hingga 512 MB, sedangkan FoundationDB membatasi ukuran value hingga 100.000 byte. Key dan value adalah building block dasar key-value database.
Namespace
Namespace adalah kumpulan pasangan key-value — bisa dibayangkan sebagai set/collection/list pasangan key-value tanpa duplikat, atau bucket untuk menampung pasangan key-value. Sebuah namespace bisa jadi mencakup seluruh basis data. Karakteristik esensialnya: tidak boleh ada key duplikat dalam satu namespace (value boleh duplikat).
Namespace berguna ketika banyak aplikasi memakai satu key-value database yang sama — jika dua tim memodelkan data spesifik aplikasi masing-masing, berpotensi terjadi konflik penamaan key. Namespace menyelesaikan masalah ini dengan secara implisit mendefinisikan prefix tambahan untuk key, sehingga key yang sama secara literal bisa eksis di namespace berbeda tanpa bentrok (mis. CMGMT[Prod:12986:name] dan OMGMT[Prod:12986:name] adalah dua entri terpisah meski nama key-nya identik).
Schemaless
Schemaless mendeskripsikan model logis basis data — pada key-value database, artinya kamu tidak diwajibkan mendefinisikan seluruh key dan tipe value yang akan dipakai sebelum menambahkannya ke basis data. Contoh: cust:8983:fullName = 'Jane Anderson' bisa langsung disimpan tanpa deklarasi skema apapun sebelumnya.
Model schemaless memungkinkan perubahan kapan pun tanpa perlu mengubah skema yang mengatalogkan seluruh key dan tipe value. Contoh: jika kemudian diputuskan lebih baik memisahkan nama depan dan belakang, kode aplikasi cukup diubah untuk menyimpan cust:8983:firstName = 'Jane' dan cust:8983:lastName = 'Anderson' — tanpa perlu migrasi skema, dan representasi lama (cust:8983:fullName) tetap bisa terus eksis berdampingan untuk record lain.
Key-Value Architecture Terms
Lima istilah arsitektur: partition, partition key, cluster, ring, replication.
Partition
Partitioned cluster adalah kelompok server tempat instance software key-value database ditugaskan mengelola subset dari basis data. Contoh sederhana cluster dua-server: idealnya tiap server menangani 50% beban kerja (mis. key berawalan A–L ditangani Server 1, M–Z ditangani Server 2). Namun jika distribusi key tidak merata (mis. mayoritas key berawalan huruf C), terjadi ketidakseimbangan beban antar-server.
Skema partisi sebaiknya dipilih untuk mendistribusikan beban kerja seakurat mungkin. Saat menambah server ke cluster, instance dapat dialokasikan ulang untuk menyeimbangkan beban — mis. dari 2 server (masing-masing menangani rentang setengah alfabet) menjadi 3 server dengan rentang yang direbalance.
Partition Key
Partition key adalah key yang dipakai untuk menentukan partisi mana yang menyimpan suatu nilai data — pada key-value database, seluruh key dipakai untuk menentukan lokasi penyimpanan value terkait. Contoh strategi sederhana: huruf pertama nama key, partisi berdasarkan nilai numerik, atau partisi berdasarkan nilai string.
Partition key yang baik mendistribusikan beban kerja secara merata. Jika tidak ada key yang secara alami mendistribusikan beban merata, gunakan hash function — fungsi yang memetakan string input ke string berukuran tetap yang (umumnya) unik terhadap input-nya.
Cluster
Cluster adalah sekumpulan komputer yang saling terhubung dan mengoordinasikan operasinya. Cluster bisa loosely coupled (server relatif independen) atau tightly coupled (komunikasi antar-server tinggi) — cluster key-value cenderung loosely coupled.
Server (node) dalam cluster loosely coupled saling berbagi informasi tentang rentang data yang menjadi tanggung jawabnya, dan rutin mengirim pesan (heartbeat) untuk menandakan masih berfungsi. Saat sebuah node gagal, node lain dapat mengambil alih pekerjaannya. Dua model manajemen cluster:
- Master node (mis. Redis): master bertanggung jawab menerima operasi baca/tulis dan mereplikasi salinan data ke slave node yang merespons request baca. Jika master gagal, node lain memilih master baru; jika slave gagal, node lain tetap bisa merespons request baca.
- Masterless cluster (mis. Riak): seluruh node menjalankan operasi baca/tulis; jika satu node gagal, node lain mengambil alih tanggung jawab baca/tulisnya.
Ring
Ring adalah pola sirkular tempat tiap server/instance software key-value database ditautkan ke dua instance yang bersebelahan. Tiap server bertanggung jawab mengelola rentang data berdasarkan partition key — mis. hash function memetakan partition key 'cust:8983:firstName' ke angka 0–95, lalu rentang angka tersebut dipetakan ke 8 server node (mis. Server 1 menangani 0–11, Server 2 menangani 12–23, dst.).
graph LR S1((Server 1)) --> S2((Server 2)) --> S3((Server 3)) --> S4((Server 4)) S4 --> S5((Server 5)) --> S6((Server 6)) --> S1
Setiap kali data ditulis ke suatu server, data tersebut juga ditulis ke dua server bersebelahan — ini menjadi mekanisme replikasi yang mengaktifkan high availability. Contoh: jika Server 4 gagal, Server 3 dan Server 5 dapat merespons request baca maupun menerima operasi tulis yang seharusnya ditujukan ke Server 4; saat Server 4 kembali online, Server 3 dan 5 mengirim ulang (sinkronisasi) tulisan yang terjadi selama Server 4 down.
Replication
Replication adalah proses menyimpan banyak salinan data dalam cluster. Parameter penting: jumlah replika yang dijaga.
- Semakin banyak replika → semakin kecil kemungkinan kehilangan data, tapi performa berpotensi menurun.
- Jika data mudah diregenerasi/dimuat ulang ke key-value database, jumlah replika kecil sudah cukup.
- Jika toleransi kehilangan data rendah, disarankan jumlah replika lebih tinggi.
Key Design and Partitioning
Key-Naming Convention
Panduan umum:
- Gunakan komponen nama yang bermakna dan tidak ambigu, mis.
'cust'untuk customer,'inv'untuk inventory. - Gunakan komponen berbasis rentang (range-based) saat ingin mengambil rentang nilai — mis. tanggal atau counter integer.
- Gunakan delimiter yang konsisten saat menggabungkan komponen menjadi key —
:umum dipakai, tapi karakter apapun yang tidak muncul di dalam key itu sendiri bisa dipakai. - Buat key sesingkat mungkin tanpa mengorbankan karakteristik di atas.
Pola key yang terdesain baik meminimalkan jumlah kode yang perlu ditulis developer untuk fungsi akses/set nilai. Contoh pola: <entity>:<unique_id>:<attribute_name>:
define getCustAttr(p_id, p_attrName)
v_key = 'cust' + ':' + p_id + ':' + p_attrName;
return(AppNameSpace[v_key]);
define setCustAttr(p_id, p_attrName, p_value)
v_key = 'cust' + ':' + p_id + ':' + p_attrName
AppNameSpace[v_key] = p_value
Dalam praktiknya, sebaiknya ada naming convention juga untuk namespace, bukan hanya key.
Menangani Rentang Nilai (Range of Values)
Pertimbangkan memakai nilai yang mengindikasikan rentang saat ingin mengambil sekelompok nilai. Contoh: key untuk 10 customer pertama yang membeli produk pada 15 Juni 2014 memakai counter sebagai bagian key (cust061514:1:custId sampai cust061514:10:custId), lalu fungsi pengambilan mengiterasi counter dari 1 hingga key tersebut tidak lagi ditemukan.
Keterbatasan Implementasi terhadap Key
Tiap key-value database punya batasan berbeda:
- Beberapa membatasi ukuran key — mis. FoundationDB membatasi ukuran key hingga 10.000 byte.
- Beberapa membatasi tipe data yang boleh dipakai sebagai key — Riak memperlakukan key sebagai nilai biner/string, sedangkan Redis lebih liberal dan mendukung struktur lebih kompleks sebagai key.
Bagaimana Key Dipakai dalam Partitioning
Partitioning adalah proses mengelompokkan set pasangan key-value dan menugaskannya ke node berbeda dalam cluster.
- Hashing: metode partitioning umum yang mendistribusikan key dan value secara merata ke seluruh node.
- Range partitioning: mengelompokkan nilai-nilai yang berdekatan (contiguous) dan mengirimkannya ke node cluster yang sama, mis.
cust:00001–cust:00999→ Server 1,cust:01000–cust:01999→ Server 2, dst.
Designing Structured Values
Tipe Data Terstruktur Membantu Mengurangi Latensi
Pertimbangkan beban kerja server sekaligus beban kerja developer saat mendesain aplikasi yang memakai key-value store. Contoh: jika alamat customer dibutuhkan ~80% dari waktu ketika nama customer juga dibutuhkan, masuk akal untuk membuat satu fungsi yang mengambil nama dan alamat sekaligus dalam satu panggilan fungsi, alih-alih dua panggilan getCustAttr terpisah — karena mengambil value dari key-value database memerlukan waktu relatif lama dibanding operasi primitif (analog dengan waktu seek disk: head harus berpindah track dan platter berputar ke blok yang tepat).
Cara meningkatkan kecepatan pengambilan value:
- Simpan value yang sering dipakai di memory cache.
- Simpan atribut yang sering dipakai bersama-sama dalam satu value (mis.
cstMgtNS[cust:198277:nameAddr] = {'Jane Anderson', '39 NE River St. Portland, OR 97222'}), sehingga membaca satu blok data lebih cepat dibanding membaca banyak blok yang dirujuk banyak key terpisah.
Duplicating Data (Denormalisasi)
Duplikasi data adalah cara umum meningkatkan performa query relational database (denormalisasi). Contoh: jika sering hanya butuh nama customer (tanpa alamat), simpan nama secara terpisah — ini menduplikasi nama customer di key-value database.
Value Besar Bisa Menyebabkan Operasi Baca/Tulis Tidak Efisien
Struktur data terstruktur (list, set) dapat meningkatkan efisiensi dengan meminimalkan waktu pengambilan data — tapi perlu diperhatikan dampak buruk value yang semakin besar:
- Jika ukuran value melebihi ukuran blok, banyak blok harus dibaca.
- Saat operasi tulis, seluruh value harus ditulis ulang, meski hanya sebagian kecil yang berubah.
- Saat satu blok dibaca, seluruh value dalam blok tersebut bisa masuk ke in-memory cache — menghemat waktu baca disk berikutnya. Blok berisi banyak value kecil cenderung lebih menguntungkan cache dibanding blok berisi sedikit value besar.
Jika kamu sering mendesain struktur value yang besar, pertimbangkan memakai document database (lihat Document Database) alih-alih key-value database.
Limitations of Key-Value Databases
Hanya Bisa Lookup Berdasarkan Key
Cara satu-satunya mencari value adalah lewat key — padahal kadang kita ingin mencari informasi objek tanpa tahu nilai key-nya. Fitur ekstensi untuk mengatasi keterbatasan ini:
- Text search capability — mis. Riak menyediakan mekanisme search & API yang mengindeks nilai data saat ditambahkan ke basis data (
field: {'motherboard' AND 'computer case'} AND NOT 'CPU'). - Secondary index.
Tidak Mendukung Range Query
Range query (mis. memilih record dengan tanggal antara dua nilai, atau nama dalam rentang alfabet tertentu) pada dasarnya tidak didukung kecuali memakai naming convention khusus + lookup table (lihat pola dealing with ranges of values di atas). Alternatif: ordered key-value database — tipe khusus yang menjaga struktur terurut sehingga mendukung range query; atau jika key-value database mendukung secondary index, range query bisa dilakukan atas nilai yang diindeks.
Tidak Ada Bahasa Query Standar Setara SQL
Beberapa key-value database memahami struktur umum seperti XML dan JSON. Banyak bahasa pemrograman punya library untuk membangun/mem-parsing XML dan JSON, mis. Solr dan Lucene.
Design Patterns for Key-Value Databases
Enam pola desain utama: Time to Live (TTL) keys, emulating tables, aggregates, atomic aggregates, enumerable keys, [inverted] indexes.
Time to Live (TTL)
TTL menggambarkan objek yang bersifat transient — berguna saat data di-cache pada server memori terbatas, atau saat key dipakai untuk menahan (hold) suatu resource selama periode waktu tertentu. Contoh: aplikasi penjualan tiket — pasangan key-value ditambahkan untuk menahan kursi selagi pembayaran customer diproses, dengan TTL lima menit untuk memberi waktu cukup menyelesaikan pembayaran.
Emulating Tables
Meniru fitur relational table lewat naming convention berbasis nama entitas, unique identifier, dan nama atribut (lihat pola key-naming di atas). Namun tidak praktis meniru relational table secara utuh — pola ini tidak menyediakan kemampuan query bergaya SQL, hanya operasi dasar get/set. Berguna saat kamu rutin mengambil/menyetel sekumpulan atribut terkait, dan cocok untuk sejumlah kecil tabel emulasi. Jika ternyata butuh mengemulasi banyak tabel atau filtering/range search yang rumit, pertimbangkan pendekatan lain.
Aggregates
Pola yang mendukung atribut berbeda untuk subtipe berbeda dari suatu entitas. Satu entity type (mis. 'concert') dipakai untuk seluruh subtipe, dengan value berupa list pasangan atribut-nilai yang spesifik per subtipe, plus indikator tipe untuk membedakan subtipe (mis. stadium, small venue, festival sama-sama disimpan sebagai tipe 'concert' dengan atribut berbeda-beda sesuai type).
Atomic Aggregates
Atomic aggregate berisi seluruh nilai yang harus di-update bersamaan atau tidak sama sekali — mirip properti Atomic pada ACID. Beberapa key-value database menyediakan transaksi untuk memastikan beberapa statement selesai seluruhnya atau tidak sama sekali. Pola atomic aggregate memakai satu statement assignment untuk menyimpan banyak nilai sekaligus — mis. mencatat date, location, dan assigned seat dalam satu operasi tulis, sehingga ketiganya tersimpan lengkap atau tidak sama sekali (menghindari risiko sebagian atribut tersimpan, sebagian tidak, jika di-log terpisah).
Enumerable Keys
Key yang memakai counter atau sequence untuk membuat key baru — dikombinasikan dengan atribut lain, berguna untuk bekerja dengan grup key. Contoh: alih-alih hanya ticketLog:<counter>, format key yang lebih baik untuk mengambil seluruh log tiket pada tanggal tertentu adalah 'ticketLog' digabung tanggal digabung counter, mis. 'ticketLog:20140617:10' — memungkinkan pengambilan rentang key lewat generate serangkaian key berurutan.
[Inverted] Index
Inverted index adalah set pasangan key-value yang memungkinkan pencarian key/value lewat atribut lain milik entitas yang sama. Contoh: mencatat semua kursi yang ditetapkan (assgnSeat) per lokasi konser lewat fungsi addLocAssgnSeat(p_locDescr, p_seat) yang menambahkan seat ke list pada key berbasis lokasi (ConcertApp[p_locDescr]) — berguna untuk query “semua kursi yang terjual di lokasi X”, yang sulit dilakukan langsung dari data yang diindeks berdasarkan ticketLog saja (kecuali ada kemampuan search).
Case Study: Key-Value Database untuk Konfigurasi Aplikasi Mobile
Konteks: TransGlobal Transport and Shipping (TGTS) mengembangkan aplikasi mobile TGTS Tracker untuk memungkinkan customer melacak pengiriman dari perangkat mobile mana pun. Desainer aplikasi memutuskan menyimpan informasi konfigurasi tiap customer di basis data terpusat, mencakup: nama & nomor akun customer, mata uang default untuk harga, atribut shipment yang muncul di dashboard ringkasan, preferensi alert & notifikasi, dan opsi UI (skema warna, font).
Selain konfigurasi, aplikasi perlu menampilkan ringkasan cepat di dashboard — respons lebih lambat masih dapat diterima saat customer mencari detail shipment. Basis data yang mendukung TGTS Tracker harus mendukung hingga 10.000 user simultan, dengan read mencapai 90% dari seluruh operasi I/O.
Desain Namespace, Key, dan Entity Type
Karena cakupan data yang dibutuhkan aplikasi mobile relatif terbatas, desainer memutuskan satu namespace sudah cukup — dinamakan TrackerNS. Nomor akun customer dipilih sebagai unique identifier, dengan konvensi key <entity type>:<account number>. Empat entity type didefinisikan:
| Entity type | Singkatan |
|---|---|
| Informasi customer | cust |
| Opsi konfigurasi dashboard | dshb |
| Spesifikasi alert & notifikasi | alrt |
| Konfigurasi user interface | ui |
Menentukan Atribut Tiap Entity
- Customer: dari review desain UI awal, nama dan nomor akun sering muncul bersama, begitu pula mata uang default — sehingga entity
custmenyimpan nama dan mata uang preferensi:TrackerNS['cust:4719364'] = { 'name': 'Prime Machine, Inc.', 'currency': 'USD' } - Dashboard: berupa list hingga enam atribut shipment yang ditampilkan di layar ringkasan (dipilih dari opsi seperti
shpComp,shpCity,shpState,shpCountry,shpDate,shpDelivDate,shpCnt,shpType,shpWght,shpNotes):TrackerNS['dash:4719364'] = { 'shpComp', 'shpState', 'shpDate', 'shpDelivDate' } - Alerts & notification: perlu memodelkan bahwa beberapa orang bisa menerima notifikasi (via email atau SMS), masing-masing dengan kondisi trigger berbeda (pickup, delivered, delayed) — dimodelkan sebagai list of lists:
TrackerNS[alrt:4719364] = { altList: { {'jane.washingon@primemachineinc.com','pickup'}, {'(202)555-9812','delay'} } } - UI configuration: list sederhana pasangan atribut-nilai (font, ukuran font, skema warna):
TrackerNS['ui:4719364'] = { 'fontName':'Cambria', 'fontSize':9, 'colorScheme':'default' }
Studi kasus ini menunjukkan bagaimana prinsip key design, namespace, aggregate pattern (list & list-of-lists sebagai value) diterapkan bersama untuk memenuhi kebutuhan spesifik aplikasi read-heavy dengan skala ribuan user simultan.
Sumber
- D. Sullivan: NoSQL for Mere Mortals, Addison-Wesley, 2015, Chapter 4 (Key-Value Databases) & Chapter 5 (bagian latency/structured value).
Flashcard
flashcards Apa perbedaan key, value, dan namespace pada key-value database? :: Key = referensi/alamat untuk menemukan value (biasanya string, atau struktur kompleks pada Redis); value = objek/sekumpulan byte yang diasosiasikan dengan key; namespace = kumpulan pasangan key-value tanpa key duplikat (bisa mencakup seluruh basis data atau sebagian). Kenapa key tidak boleh terlalu panjang maupun terlalu pendek? :: Terlalu panjang boros memori (key-value database cenderung memory-intensive); terlalu pendek rawan menimbulkan konflik nama key antar-entitas. Apa fungsi namespace saat banyak aplikasi memakai satu key-value database yang sama? :: Namespace secara implisit menambahkan prefix ke key, sehingga key dengan nama literal sama dari aplikasi berbeda tidak saling bentrok (masing-masing dianggap entri terpisah dalam namespace masing-masing). Apa arti “schemaless” pada key-value database, dan apa konsekuensinya? :: Tidak perlu mendefinisikan seluruh key/tipe value sebelum menyimpannya — memberi fleksibilitas mengubah representasi data kapan pun tanpa migrasi skema, tapi validasi data sepenuhnya jadi tanggung jawab kode aplikasi. Apa perbedaan cluster dengan master node vs masterless cluster? :: Master node (mis. Redis): satu node menerima seluruh baca/tulis dan mereplikasi ke slave; jika master gagal, node lain memilih master baru. Masterless (mis. Riak): seluruh node ikut menangani baca/tulis; jika satu node gagal, node lain mengambil alih tanpa proses pemilihan master. Bagaimana arsitektur ring pada key-value database bekerja dan apa manfaatnya untuk high availability? :: Tiap server ditautkan ke dua server bersebelahan secara sirkular; data yang ditulis ke satu server juga direplikasi ke dua server tetangganya, sehingga jika satu server gagal, kedua tetangganya bisa tetap melayani baca/tulis untuk rentang data server yang gagal tersebut. Apa dua metode utama partitioning pada key-value database dan bedanya? :: Hashing (mendistribusikan key/value secara merata lewat fungsi hash) dan range partitioning (mengelompokkan nilai-nilai berdekatan/contiguous ke node yang sama). Kenapa key-value database secara default tidak mendukung range query, dan apa solusinya? :: Karena lookup hanya bisa lewat key persis, bukan rentang nilai — solusinya memakai naming convention + lookup table berbasis counter, ordered key-value database (struktur terurut), atau secondary index bila didukung. Jelaskan pola desain “atomic aggregate” pada key-value database :: Menyimpan seluruh nilai yang harus konsisten bersama-sama dalam satu operasi assignment tunggal, sehingga seluruh nilai tersimpan lengkap atau tidak sama sekali — mirip properti Atomicity pada ACID, menghindari risiko sebagian atribut tersimpan saat proses gagal di tengah jalan. Apa fungsi pola “enumerable keys” dan berikan contoh formatnya :: Memakai counter/sequence sebagai bagian key agar bisa mengambil rentang/grup key terkait secara berurutan, mis. ‘ticketLog:20140617:10’ (nama+tanggal+counter) sehingga seluruh log tiket pada tanggal tertentu bisa diambil dengan mengiterasi counter. Kapan sebaiknya beralih dari key-value database ke document database menurut materi ini? :: Ketika kamu sering perlu mendesain struktur value yang besar/kompleks, karena value besar menyebabkan operasi baca/tulis tidak efisien (banyak blok harus dibaca/ditulis ulang) pada key-value database.