Belajar Swoole - Microservices: gRPC & JSON-RPC
Episode 16 of 26

Belajar Swoole - Microservices: gRPC & JSON-RPC

Membangun microservices dengan Swoole: memahami protobuf dan HTTP/2 untuk gRPC server dan client, JSON-RPC sebagai alternatif ringan, serta pola service discovery agar service bisa saling menemukan.

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Setelah di episode 15 kita memilih framework — pada episode kali ini kita membangun layer komunikasi antar service: microservices. Di dunia nyata, sistem tidak lagi satu monolith besar; mereka dipecah menjadi service-service kecil yang saling memanggil dengan protokol yang efisien.

Mengapa episode ini penting? Karena REST + JSON itu nyaman tapi boros: parsing teks, overhead HTTP header, dan tanpa schema. gRPC menawarkan schema kuat (protobuf), binary payload, dan streaming — dengan performa jauh lebih baik untuk traffic antar service. Swoole mendukungnya langsung.

gRPC: Fondasi

gRPC dibangun di atas dua teknologi:

LapisanFungsi
Protocol Buffers (protobuf)Bahasa definisi schema + serialisasi binary
HTTP/2Multiplexing, binary framing, streaming

Keunggulan utamanya: schema didefinisikan sekali (.proto), dan dari schema itu di-generate kode client & server di semua bahasa. Client dan server tidak bisa "salah asumsi" tentang bentuk data.

Definisi Service

greeter.proto
syntax = "proto3";
 
package greeter;
 
service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply);
}
 
message HelloRequest {
  string name = 1;
}
 
message HelloReply {
  string message = 1;
}

Dari file ini, kalian generate kode PHP dengan plugin protoc:

Generate kode PHP dari proto
protoc --php_out=./generated greeter.proto

gRPC Server dengan Swoole

Swoole menyediakan server gRPC lewat mode HTTP/2. Aktifkan open_http2_protocol, lalu tangani frame gRPC di on('Request'):

grpc-server.php
<?php
use Swoole\Http\Server;
use Swoole\Http\Request;
use Swoole\Http\Response;
 
$server = new Server('0.0.0.0', 50051, SWOOLE_PROCESS);
$server->set([
    'open_http2_protocol' => true,
    'worker_num' => 4,
]);
 
$server->on('Request', function (Request $req, Response $res) {
    $path = $req->server['request_uri'];
 
    if ($path === '/greeter.Greeter/SayHello') {
        // baca frame gRPC: 1-byte compressed flag + 4-byte length + payload
        $payload = substr($req->getContent(), 5);
        $data = json_decode($payload, true);
 
        $reply = json_encode(['message' => 'Halo, ' . ($data['name'] ?? 'dunia') . '!']);
        $frame = pack('N1', 0) . $reply;
 
        $res->header('content-type', 'application/grpc');
        $res->header('grpc-status', '0');
        $res->header('grpc-message', '');
        $res->end($frame);
    } else {
        $res->header('grpc-status', '12'); // UNIMPLEMENTED
        $res->end();
    }
});
 
$server->start();

Format frame gRPC wajib dipahami: 1 byte flag kompresi, 4 byte panjang (big-endian), lalu payload. Client yang kita tulis di episode 9 memakai format yang sama:

gRPC client (dari episode 9)
$grpc = new Coroutine\Http2\Client('127.0.0.1', 50051);
$grpc->connect();
 
$req = new Coroutine\Http2\Request;
$req->method = 'POST';
$req->path = '/greeter.Greeter/SayHello';
$req->headers['content-type'] = 'application/grpc';
$req->data = pack('N1', 0) . pack('N1', 0) . '{"name":"Andi"}';
 
$grpc->send($req);
$resp = $grpc->recv();
echo $resp->data; // frame gRPC: {message: "Halo, Andi!"}

Tip

Untuk produksi, jangan tulis parser gRPC manual — gunakan library siap pakai seperti grpc/grpc + generated code, spiral/roadrunner-grpc, atau framework Hyperf yang menyediakan hyperf/grpc-server. Kode manual di atas hanya untuk memahami mekanisme yang sebenarnya terjadi.

JSON-RPC: Alternatif Ringan

Tidak semua komunikasi internal butuh protobuf. JSON-RPC adalah protokol RPC berbasis JSON yang jauh lebih sederhana — cukup TCP/HTTP dan format request yang terstandar:

json
{"jsonrpc": "2.0", "method": "UserService.getById", "params": [42], "id": 1}

Implementasi server TCP dengan Swoole:

jsonrpc-server.php
<?php
use Swoole\Server;
 
$server = new Server('0.0.0.0', 9503);
$server->set(['open_length_check' => true, 'package_max_length' => 81920]);
 
$server->on('Receive', function (Server $server, $fd, $reactorId, $data) {
    $rpc = json_decode($data, true);
 
    $result = match ($rpc['method'] ?? '') {
        'UserService.getById' => ['id' => $rpc['params'][0] ?? 0, 'name' => 'Andi'],
        'UserService.list'    => [['id' => 1], ['id' => 2]],
        default               => null,
    };
 
    $reply = ['jsonrpc' => '2.0', 'id' => $rpc['id'] ?? null];
    if ($result === null) {
        $reply['error'] = ['code' => -32601, 'message' => 'Method not found'];
    } else {
        $reply['result'] = $result;
    }
 
    $server->send($fd, json_encode($reply));
});
 
$server->start();

JSON-RPC populer di ekosistem PHP (Hyperf memakainya sebagai protokol RPC default) karena sederhana, mudah di-debug, dan cukup cepat untuk traffic internal skala sedang.

Service Discovery

Microservices harus saling menemukan satu sama lain. Dua pendekatan umum:

Registry-based: service mendaftarkan diri ke registry (Consul, etcd, atau Redis) saat start, dan client bertanya ke registry untuk mendapatkan alamat.

Registrasi service ke Redis
$server->on('WorkerStart', function ($server, $workerId) use ($redis) {
    if ($workerId === 0) {
        $redis->hSet('svc:user-service', 'instances', json_encode([
            'host' => '10.0.0.5',
            'port' => 50051,
        ]));
    }
});

Load balancer statis: alamat service di-hardcode di config (env SERVICE_URL), lalu diputar di client dengan round-robin.

PendekatanKelebihanKekurangan
RegistryAuto scaling, health check terpusatInfra tambahan (Consul/etcd)
StatisSimpelTidak adaptif saat instance naik/turun

Untuk skala kecil, mulai dengan statis; pindah ke registry saat instance sudah puluhan.

Common Pitfalls

MasalahPenyebabSolusi
UNIMPLEMENTED saat panggilPath gRPC salah (/package.Service/Method)Cek path lengkap di client & server
Frame gRPC kebaca rusakSalah hitung panjang frameFormat: 1 byte flag + 4 byte length big-endian + payload
JSON-RPC balasan tanpa idRequest tidak punya idSelalu sertakan id untuk matching request-response
Service tidak ketemuRegistry tidak update saat instance matiAktifkan health check / TTL pada registry

Penutup

Pada episode 16 ini, kalian telah membangun komunikasi microservices dengan Swoole.

Inti yang harus dibawa pulang:

  • gRPC = protobuf (schema) + HTTP/2; efficient untuk traffic internal.
  • Frame gRPC: 1 byte flag + 4 byte length + payload; client Swoole HTTP/2 bisa langsung dipakai.
  • JSON-RPC: alternatif ringan berbasis JSON untuk RPC internal.
  • Service discovery: registry (Redis/Consul) untuk skala besar, statis untuk skala kecil.
  • Di produksi, pakai library/framework gRPC siap pakai — bukan parser manual.

Di episode 17 selanjutnya, kita mengamankan server: Keamanan Server & Hardening — input validation di layer server, limit connection, timeouts, dan proteksi terhadap Slowloris & connection flooding. Sampai jumpa di episode 17!

Belajar Swoole - Microservices: gRPC & JSON-RPC | Belajar Swoole