Cara menggunakan php swoole vs golang

The coroutine scheduler in Golang is multiple threads design. There are multiple coroutines parallel running, it is necessary to solve race conditions for the globally shared resources, to do synchronization and lock the critical section`, please see more at: https://golang.org/pkg/sync/.

Although Golang has solved the problem of synchronizing between units of work by communicating over shared channels. But Golang still used mutex and locks underlayer.

The coroutine scheduler in Open Swoole 4.x is single thread design. Only one coroutine is parallel running, so there are no problems such as data syncing between threads and avoid locking.

But how to share global variables and resources between different Swoole processes? There are three ways to solve this problem:

  • Use Swoole Table or Swoole Atomic or share memory structure
  • Use IPC, communicate between processes
  • Use external data storage such as Redis, MySQL, or file operation

defer in Golang is binding with a function. The deferred task will be executed when the function is finished. This is used to clean up and release the resources created and used within the function.

For example, in Golang:

func test() {
    db := new(database)
      close := db.connect()
      defer close()

      fmt.Println("query db...")
}

defer task is needed to release the connection resources. Compare with the PHP style doing the defer task within

<?php
function test() {
    $db = new Database;
    $db->connect('127.0.0.1', 6379);
    $db->query($sql);
}
0.

defer is doing similar tasks in Golang as a destructor in PHP.

Looking at this piece of normal PHP code:

<?php
function test() {
    $db = new Database;
    $db->connect('127.0.0.1', 6379);
    $db->query($sql);
}

Compare with the Golang test function, it is not necessary to close the DB connection in PHP since PHP destroy and clean up the DB object created within the function. Because of the destructor function including the logic of closing the connection in

<?php
function test() {
    $db = new Database;
    $db->connect('127.0.0.1', 6379);
    $db->query($sql);
}
1 will be called before the DB object is destroyed.

defer in Swoole 4.x is designed to be executed when the

<?php
function test() {
    $db = new Database;
    $db->connect('127.0.0.1', 6379);
    $db->query($sql);
}
2 task is finished. It is binding with the coroutine task.

In Golang, it is possible to read the same socket with multiple coroutines concurrently. But the developer needs to control when to do so. For example, the following Golang code may throw errors:

func test() {
    db := new(database)
    close := db.connect()

    go func(db) {
        db.query(sql);
    } (db);

    go func(db) {
        db.query(sql);
    } (db);
}

Compare with Golang, reading socket concurrently with multiple coroutines is prohibited.

<?php
function test() {
    $db = new Database;
    $db->connect('127.0.0.1', 6379);

    go(function () use ($db) {
        $db->query($sql);
    });

    go(function () use ($db) {
        $db->query($sql);
    });
}

The above code throws Error:

"%s has already been bound to another coroutine#%ld, reading or writing of the same socket in multiple coroutines at the same time is not allowed."

If you like to reading socket concurrently, use

<?php
function test() {
    $db = new Database;
    $db->connect('127.0.0.1', 6379);
    $db->query($sql);
}
3 or
<?php
function test() {
    $db = new Database;
    $db->connect('127.0.0.1', 6379);
    $db->query($sql);
}
4 to build a connection pool to control the access to the connection resource.

TeknoCerdas.com – Pada kesempatan ini penulis akan melakukan benchmark HTTP server PHP Swoole vs NodeJs vs Go. Benchmark yang dilakukan adalah benchmark sederhana yaitu masing-masing bahasa pemrograman mengembalikan sebuah string “Welcome to hello world benchmark.”

Benchmark ini tidak menggambarkan kondisi nyata aplikasi pada umumnya dimana banyak I/O seperti pembacaan file atau database. Namun paling tidak benchmark ini dapat mengindikasikan bagaimana performa dasar dari setiap bahasa pemrograman.

Bagi Anda yang tidak memiliki banyak waktu untuk membaca silahkan langsung ke bagian hasil benchmark untuk konklusi dari ketiga bahasa ini.

Ini adalah artikel yang ditulis ulang. Artikel asli dapat dilihat pada halaman Medium Rio Astamal.

Sekilas Tentang PHP Swoole, NodeJS dan Go

Swoole adalah sebuah asynchronus framework berbasis co-routine untuk PHP. Swoole ditulis menggunakan C dan dan didistribusikan dalam bentuk eksensi untuk PHP. Untuk menggunakannya pengguna harus melakukan instalasi lewat pecl.

NodeJS adalah sebuah runtime Javascript yang mendukung asynchronous event-driven dan non-blocking I/O. NodeJS dibangun diatas javascript engine yang digunakan oleh Chrome yaitu V8.

Go atau Golang adalah sebuah bahasa pemrograman open source yang dikembangkan oleh Google. Go mendukung concurency secara default melalui apa yang disebut sebagai goroutine atau channel.

Konfigurasi Benchmark

Terdapat dua mesin dalam konfigurasi benchmark yang dilakukan. Satu mesin untuk hosting HTTP server yang dibuat pada masing-masing bahasa pemrograman. Satu lagi untuk menjalankan HTTP load testing menggunakan Apache Bench (ab).

Versi dari bahasa pemrograman atau runtime yang digunakan pada benchmark kali ini.

  1. PHP v7.4.5 dan Swoole v4.5.0
  2. NodeJS v12.16.3
  3. Golang v1.14.2

Benchmark ini dilakukan menggunakan layanan AWS cloud dengan tipe instance c5d.2xlarge. Berikut spesifikasi untuk kedua mesin yang digunakan.

+------------+------------------------------------------------+
| CPU        | Intel(R) Xeon(R) Platinum 8275CL CPU @ 3.00GHz |
|------------|------------------------------------------------|
| Core       | 8 cores                                        |
|------------|------------------------------------------------|
| RAM        | 16 GB                                          |
|------------|------------------------------------------------|
| Disk       | 8 GB nvme                                      |
|------------|------------------------------------------------|
| Local CIDR | 172.31.0.0/16                                  |
|------------|------------------------------------------------|
| OS         | Ubuntu 18.04 LTS                               |
+------------+------------------------------------------------+

Konfigurasi kernel yang digunakan baik untuk application server atau client.

# tee /etc/sysctl.conf
fs.file-max=2097152
net.ipv4.tcp_synack_retries=2
net.ipv4.ip_local_port_range = 2000 65535
net.ipv4.tcp_rfc1337=1
net.core.somaxconn=65535
net.core.netdev_max_backlog=65536
net.ipv4.tcp_slow_start_after_idle=0
net.ipv4.tcp_slow_start_after_idle=0
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_fin_timeout = 5
vm.swappiness = 0
EOF

Script untuk PHP Swoole

$ cat > hello.php
<?php
$http = new Swoole\HTTP\Server('0.0.0.0', 8081);

$http->on('request', function ($request, $response) {
    $response->end('Welcome to hello world benchmark.');
});

echo '> Starting Swoole HTTP server...';
$http->start();

Script untuk NodeJS

$ cat > hello.js
const http = require('http');

const requestListener = function (req, res) {
  res.writeHead(200);
  res.end('Welcome to hello world benchmark.');
}

const server = http.createServer(requestListener);
process.stdout.write('> Starting Node HTTP server...')
server.listen(8082, '0.0.0.0');

Script untuk Go

$ cat > hello.go
package main

import (
  "fmt"
  "net/http"
)

func main() {
  http.HandleFunc("/", func (w http.ResponseWriter, r *http.Request) {
      fmt.Fprintf(w, "Welcome to hello world benchmark.")
  })

fmt.Print("> Starting Go HTTP server...")
  http.ListenAndServe("0.0.00:8083", nil)
}

Memulai Benchmark

Benchmark dijalankan secara bergantian artinya hanya ada satu server aplikasi yang jalan pada satu waktu. Sebagai contoh ketika melakukan benchmark pada PHP Swoole maka server NodeJS dan Go dimatikan. Hal ini untuk memberikan gambaran yang lebih adil terutama penggunaan memori.

Benchmark yang dilakukan adalah mengirim HTTP request dengan concurency 500 dengan total request sebanyak 500,000.

Berikut cara penulis menjalankan benchmark untuk masing-masing http server. Setiap benchmark diulang 3 kali tanpa mematikan http server. Setiap akan diulang cache memory dibersihkan dengan perintah.

$ echo 2 > sudo tee /proc/sys/vm/drop_caches

Sebelum memulai lagi penulis juga memastikan bahwa semua network socket yang ada sudah bersih dan tidak ada yang menunggu.

$ sudo netstat -ntap | grep WAIT

Jika tidak socket yang tergantung maka benchmark dapat dimulai. Hal ini untuk menghindari limit open_max_files. Karena setiap socket yang dibuka juga merupakan sebuah file di sistem operasi berbasis *NIX.

Benchmark PHP Swoole

# Pada Mesin Server
$ php hello.php
> Starting Swoole HTTP server...

# Pada Mesin Client (Load testing)
$ ab -c 500 -n 500000 http://IP_SERVER:8081/

Benchmark NodeJS

# Pada Mesin Server
$ node hello.js
> Starting Node HTTP server...

# Pada Mesin Client (Load testing)
$ ab -c 500 -n 500000 http://IP_SERVER:8082/

Benchmark Go

# Pada Mesin Server
$ go build hello.go
$ ./hello
> Starting Go HTTP server...

# Pada Mesin Client (Load testing)
$ ab -c 500 -n 500000 http://IP_SERVER:8083/

Hasil Benchmark PHP Swoole vs NodeJS vs Go

Hasil benchmark dibagi dalam tiga bagian. Satu adalah Request per Second (RPS). Kedua adalah Max CPU Usage atau penggunaan CPU maksimum. Ketiga adalah Memory Usage atau penggunaan memory.

Request per Second

Cara menggunakan php swoole vs golang
Request per Second (Semakin tinggi semakin baik)

Pemenang untuk benchmark request per second (RPS) adalah Go. Namun bersaing ketat dengan PHP Swoole.

  1. Go — 35,509 req/s
  2. PHP Swoole — 34,919 req/s
  3. NodeJS — 21,626 req/s

Max CPU Usage

Cara menggunakan php swoole vs golang
Max CPU Usage (Semakin kecil semakin baik)

Pemenang untuk benchmark Max CPU Usage adalah NodeJS dengan rata-rata 20% maksimum penggunaan CPU. Dimana penggunaannya tidak sampai separuh dari PHP Swoole dan Go.

  1. NodeJS — 20%
  2. PHP Swoole — 49,33%
  3. Go — 50,67%

Memory Usage

Cara menggunakan php swoole vs golang
System Memory Usage (Semakin kecil semakin baik)

Pemenang untuk penggunaan memory atau RAM adalah PHP Swoole. Dimana rata-rata maksimum penggunaannya 228,67 MB. Selish cukup kecil dengan Go diposisi kedua.

  1. PHP Swoole — 228,67 MB.
  2. Go — 232 MB.
  3. NodeJS — 266 MB.

Ringkasan Benchmark

Untuk urusan performa PHP Swoole dan Go bersaing cukup ketat. NodeJS tertinggal cukup jauh untuk bagian ini.

Hal yang positif dari NodeJS adalah penggunaan CPU yang cukup rendah. Ini dikarenakan NodeJS secara design adalah single-threaded sehingga tidak memanfaatkan 8 core CPU yang ada.

Penulis mencoba menjalankan NodeJS dengan mode cluster untuk multi-core processor menggunakan pm2. Namun anehnya performannya malah jauh menurun dari normal 21,626 req/s menjadi hanya 15k req/s. Entah apa yang salah dengan konfigurasi penulis.

Hal yang diluar dugaan adalah Swoole yang fantastis dan hampir setara dengan Go. Jadi jika Anda dalah PHP developer dan tidak ada waktu untuk migrasi ke Go maka Swoole adalah alternatif yang sangat menarik.

Penulis tidak menggunakan opsi keep-alive untuk lebih mensimulasikan kondisi sebenarnya dimana jumlah user diasumsikan cukup besar.

Share

  • Programming
  • #benchmark
  • #featured
  • #go
  • #golang
  • #nodejs
  • #php
  • #swoole

Cara menggunakan php swoole vs golang

Rio Astamal Follow Adalah penulis utama di TeknoCerdas.com. Rio Astamal seorang yang sangat antusias dengan web development sejak 2003. Sejak November 2021 Rio Astamal bekerja di Amazon Web Services (AWS) sebagai Developer Advocate untuk Indonesia. Dia mengelola TeknoCerdas.com di waktu senggangnya sebagai salah satu sarana untuk ikut mencerdaskan pembaca dalam dunia IT.

Apa itu PHP Swoole?

Swoole adalah sebuah asynchronus framework berbasis co-routine untuk PHP. Swoole ditulis menggunakan C dan dan didistribusikan dalam bentuk eksensi untuk PHP. Untuk menggunakannya pengguna harus melakukan instalasi lewat pecl.

Apa itu Node JS dan cara kerjanya?

Node.js adalah software open-source yang bisa digunakan untuk membuat aplikasi jaringan dan aplikasi server-side yang real-time dan scalable (bisa dikembangkan sesuai kebutuhan). Pada dasarnya, Node.js adalah runtime environment lintas platform single-thread yang dibangun berdasarkan engine JavaScript V8 Chrome.