Proyek ini mengimplementasikan algoritma konsensus Raft menggunakan TypeScript dan gRPC untuk komunikasi antar node. Raft adalah algoritma konsensus terdistribusi yang dirancang untuk mengelola log yang direplikasi di sebuah cluster server.
- Distributed Key-Value Store - Penyimpanan key-value yang terdistribusi
- Leader Election - Pemilihan leader otomatis saat leader gagal
- Log Replication - Replikasi log ke semua node follower
- Heartbeat Mechanism - Mekanisme heartbeat untuk deteksi kegagalan
- Membership Change - Penambahan/penghapusan node secara dinamis
- Transaction Support (BONUS) - Dukungan transaksi untuk operasi atomik
- Jest Unit Testing (BONUS) - Unit testing untuk setiap komponen raft
Pastikan Anda telah menginstal:
- Node.js versi 18 atau lebih tinggi
- npm (Node Package Manager)
- Docker dan Docker Compose (untuk menjalankan dengan container)
git clone https://github.com/labsister22/tugas-besar-if3130-sistem-paralel-dan-terdistribusi-mylittlecuda.git
cd tugas-besar-if3130-sistem-paralel-dan-terdistribusi-mylittlecudanpm installJika Anda perlu regenerate file proto:
npm run protoCara paling mudah untuk menjalankan cluster Raft dengan 4 node:
docker-compose up -d --buildIni akan menjalankan:
- Node 1 (Leader) pada port
5001 - Node 2 (Follower) pada port
5002 - Node 3 (Follower) pada port
5003 - Node 4 (Follower) pada port
5004
Untuk menghentikan cluster:
docker-compose downUntuk demo membership change atau melihat proses join:
# Start node1 saja (menjadi leader)
docker-compose up -d node1
# Join node2
docker-compose up -d node2
# Join node3
docker-compose up -d node3
# Join node4
docker-compose up -d node4# Semua nodes (gabungan)
docker-compose logs -f
# Single node
docker-compose logs -f node1
docker-compose logs -f node2npm run server 5001Buka terminal baru untuk setiap node:
# Node 2
npm run server 5002 localhost:5001 localhost
# Node 3
npm run server 5003 localhost:5001 localhost
# Node 4
npm run server 5004 localhost:5001 localhostFormat Perintah:
npm run server <port> <contact_address> <hostname>
| Parameter | Deskripsi |
|---|---|
port |
Port yang akan digunakan node |
contact_address |
Alamat node yang sudah ada di cluster (untuk join) |
hostname |
Hostname node (default: localhost) |
Client digunakan untuk berinteraksi dengan cluster Raft. Semua operasi akan diteruskan ke leader.
npm run client <port> <command> [arguments...]npm run client 5001 pingOutput: PONG
npm run client 5001 set <key> <value>Contoh:
npm run client 5001 set nama "John Doe"
npm run client 5001 set umur 25npm run client 5001 get <key>Contoh:
npm run client 5001 get nama
# Output: John Doenpm run client 5001 del <key>Contoh:
npm run client 5001 del namanpm run client 5001 append <key> <value>Contoh:
npm run client 5001 set greeting "Hello"
npm run client 5001 append greeting " World"
npm run client 5001 get greeting
# Output: Hello Worldnpm run client 5001 strln <key>Contoh:
npm run client 5001 set pesan "Hello World"
npm run client 5001 strln pesan
# Output: 11npm run client 5001 request_logOutput akan menampilkan semua log entry dengan format:
[CLIENT] Retrieved N log entries
[0] Term: 1, Command: set, Key: nama, Value: John
[1] Term: 1, Command: set, Key: umur, Value: 25
...
npm run client 5001 txn <command1> <command2> ...Format command: type:key=value
Contoh:
npm run client 5001 txn set:nama=John set:umur=25 append:nama=Doe┌─────────────────────────────────────────────────────────────┐
│ CLIENT │
│ (npm run client) │
└─────────────────────────────┬───────────────────────────────┘
│ gRPC
▼
┌─────────────────────────────────────────────────────────────┐
│ RAFT CLUSTER │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Node1 │◄──►│ Node2 │◄──►│ Node3 │◄──►│ Node4 │ │
│ │ (Leader)│ │(Follower│ │(Follower│ │(Follower│ │
│ │ :5001 │ │ :5002 │ │ :5003 │ │ :5004 │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
│ │ │ │ │ │
│ └──────────────┴──────────────┴──────────────┘ │
│ Log Replication │
└─────────────────────────────────────────────────────────────┘
.
├── src/
│ ├── client/
│ │ └── Client.ts
│ ├── constants/
│ │ └── constants.ts
│ ├── proto/
│ │ ├── raft.proto
│ │ └── raft.ts
│ ├── raft/
│ │ ├── RaftNode.ts
│ │ ├── RaftState.ts
│ │ ├── LogEntry.ts
│ │ ├── PersistentStore.ts
│ │ ├── commit/
│ │ │ └── AdvanceCommitIndex.ts
│ │ ├── handlers/
│ │ │ ├── AppendEntriesHandler.ts
│ │ │ ├── RequestVoteHandler.ts
│ │ │ ├── ExecuteHandler.ts
│ │ │ ├── MembershipHandler.ts
│ │ │ └── RequestLogHandler.ts
│ │ ├── statemachine/
│ │ │ ├── KVStore.ts
│ │ │ └── ApplyCommitted.ts
│ │ ├── timers/
│ │ │ ├── ElectionTimer.ts
│ │ │ ├── HeartbeatTimer.ts
│ │ │ └── StartElection.ts
│ │ ├── transitions/
│ │ │ ├── BecomeLeader.ts
│ │ │ └── StepDown.ts
│ │ └── utils/
│ │ ├── LogUtils.ts
│ │ └── TermUtils.ts
│ ├── rpc/
│ │ ├── client/
│ │ │ └── RaftRpcClient.ts
│ │ └── server/
│ │ ├── RaftRpcServer.ts
│ │ ├── NodeBootstrap.ts
│ │ ├── controllers/
│ │ └── helpers/
│ └── __tests__/
│ ├── raft/
│ ├── kvstore/
│ └── utils/
├── data/
├── docker-compose.yml
├── Dockerfile
└── package.json
File-file penting:
src/raft/RaftNode.ts- Core Raft node implementationsrc/raft/handlers/- RPC request handlers (AppendEntries, RequestVote, Execute, dll)src/raft/statemachine/KVStore.ts- Key-value store state machinesrc/rpc/server/NodeBootstrap.ts- Node startup dan auto-join logicsrc/client/Client.ts- Client CLI untuk interaksi dengan clusterdocker-compose.yml- Docker compose untuk 4-node clusterdata/- Persistent state storage
Jalankan unit tests:
npm run testDengan coverage:
npm run test:coverageMode watch (development):
npm run test:watch| Fitur | Status |
|---|---|
| Heartbeat | Selesai |
| Leader Election | Selesai |
| Log Replication | Selesai |
| Membership Change | Selesai |
| Unit Testing (bonus) | Selesai |
| Transaction (bonus) | Selesai |
| Log Compaction (bonus) | Belum |
Kelompok: MyLittleCuda
| Name | Student ID |
|---|---|
| Andrew Tedjapratama | 13523148 |
| Muhammad Farrel Wibowo | 13523153 |
| Theo Kurniady | 13523154 |