เนื้อหา

ลองเทียบประสิทธิภาพของ 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 TCP475,511.19443,655.721.519 / 1.639
Redis UnixSocket1,555,209.881,270,648.000.455 / 0.567
MariaDB TCP75,43221,54029.76
MariaDB UnixSocket212,68860,73110.54

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

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