เนื้อหา

ลองเทียบประสิทธิภาพของ Apps กับ Database ระหว่าง TCP กับ Unix socket

ปกติแล้วเวลาใช้งาน database ในระดับงานที่ไม่ใหญ่มาก ใน container เราก็มักจะเชื่อมต่อกันด้วย TCP/IP กันถูกไหมครับ แต่รู้หรือไม่ว่าเราสามารถเพิ่มประสิทธิภาพง่าย ๆ ด้วยการลด overhead ของ TCP ออกด้วยการใช้ Unix socket แทนผลจะเป็นยังไง ลองมาดูกันครับ

docker-compose.yml

เรามาเริ่มจากเปิด database ใน docker ด้วย docker compose ซึ่งพยายามให้ default ที่สุด ตามด้านล่างนี้

x-default: &deafult-env
  TZ: Asia/Bangkok
x-mariadb: &mariadb-env
  MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: true
  MARIADB_AUTO_UPGRADE: true

services:
  mariadb:
    image: mariadb:lts
    environment:
      <<: [*deafult-env, *mariadb-env]
    volumes:
      - mariadb_data:/var/lib/mysql
      - ./tmp/run:/run/mysqld
    ports:
      - 3306:3306

  redis:
    image: redis:alpine
    environment:
      <<: [*deafult-env]
    volumes:
      - redis_data:/data
      - ./tmp/run:/data/run
    command: [
        "redis-server",
        "--unixsocket /data/run/redis.sock",
      ]
    ports:
      - 6379:6379

volumes:
  mariadb_data:
  redis_data:

หลังจาก docker compose up -d ก็จะได้ประมาณนี้

/posts/linux/tcp_vs_socket/img/compose_up.webp
compose_up
หน้าตาของ Unix socket
/posts/linux/tcp_vs_socket/img/socket_files.webp
socket_files

Redis

เริ่มจาก database ที่เร็วและง่ายที่สุดในตัวอย่างกันก่อน โดยจะทดสอบ read, write

TCP/IP

redis-benchmark -n 1000000 -t set,get -P 16 -q -h 127.0.0.1 -p 6379

ผลที่ได้

/posts/linux/tcp_vs_socket/img/redis_tcp.webp
redis_tcp

UNIX socket

redis-benchmark -n 1000000 -t set,get -P 16 -q -s tmp/run/redis.sock

ผลที่ได้

/posts/linux/tcp_vs_socket/img/redis_socket.webp
redis_socket

MariaDB

มาต่อด้วย database ยอดนิยมตัวนึง โดยจะทดสอบ read, write เหมือนเดิม

เตรียมข้อมูลทำหรับทดสอบ

เริ่มจากการสร้าง database และ table สำหรับ sysbench

sysbench oltp_read_write --db-driver=mysql --mysql-host=127.0.0.1 --mysql-user=root --mysql-db=sysbenchtest --threads=16 prepare

TCP/IP

sysbench oltp_read_write --db-driver=mysql --mysql-host=127.0.0.1 --mysql-user=root --mysql-db=sysbenchtest --threads=16 run

ผลที่ได้

/posts/linux/tcp_vs_socket/img/mariadb_tcp.webp
mariadb_tcp

UNIX socket

sysbench oltp_read_write --db-driver=mysql --mysql-socket=tmp/run/mysqld.sock --mysql-user=root --mysql-db=sysbenchtest --threads=16 run

ผลที่ได้

/posts/linux/tcp_vs_socket/img/mariadb_socket.webp
mariadb_socket

สรุป

read (req/s) write (req/s) latency avg (ms)
Redis TCP 475,511.19 443,655.72 1.519 / 1.639
Redis UnixSocket 1,555,209.88 1,270,648.00 0.455 / 0.567
MariaDB TCP 75,432 21,540 29.76
MariaDB UnixSocket 212,688 60,731 10.54

จะเห็นได้ว่าหากเราลด overhead ของ TCP ออกด้วยการใช้ Unix socket แทน จะทำให้เราไม่ต้องไป up scale ทรัพยากรของเราให้ใหญ่โต ก็สามารถรับโหลดได้เพิ่มมาขึ้นอีกเยอะเลย หรือในงานบน K8S ที่มีการทำ sidecar ก็สามารถใช้ Unix socket สื่อสารระหว่างกันแทน TCP/IP ได้นะครับ

ปล. ใช้ได้ใน node ที่ใช้งาน volume ร่วมกันนะจร๊ะ