Published on

Unix socket, “ma tốc độ” thường bị lãng quên

Authors

Nếu bạn có từng để ý rằng, các webserver như Apache hay Nginx kết nối tới PHP-FPM ở cổng 9000, PHP kết nối với MySQL ở cổng 3306, hay kết nối với Redis ở cổng 6379, Memcache ở cổng 11211. Tuy nhiên, còn một cách kết nối khác ít được biết đến đem lại khả năng tăng tốc hơn 50% so với TCP/IP, đó là sử dụng Unix socket.

Nếu bạn đang sử dụng VPSSIM hoặc HocVPS hoặc CentOS, hãy đọc qua bài này để biết Unix socket là gì và chuyển sang Phần hai: Hướng dẫn cài đặt trên VPSSIM / HocVPS 🔗 để dễ thực hiện theo nhé.

Unix socket là gì?

Unix socket là một điểm giao tiếp để trao đổi dữ liệu giữa các ứng dụng trên cùng một máy tính. Khác với giao thức TCP/IP thực hiện ở giao thức mạng, Unix socket thực hiện ở nhân hệ điều hành, nhờ vậy có thể tránh được cách bước như kiểm tra hoặc routing, đem lại tốc độ kết nối nhanh hơn và nhẹ hơn so với TCP/IP.

Ưu điểm của Unix socket

Thật là đơn giản để chứng minh bằng các bài benchmark để dụ dỗ các bạn chuyển sang sử dụng Unix socket:

Unix socket giúp tốc độ truy cập MySQL tăng 30-50% 🔗 hay giảm latency từ 60ms xuống còn 5ms 🔗, còn nữa PostgreSQL tăng hơn 30% 🔗Redis tăng 50% 🔗,... so với TCP/IP.

Những con số đó có làm các bạn trầm trồ chưa? Và cũng thật là thiếu sót nếu chỉ đưa ra lời khen, mà bỏ qua đi một số nhược điểm của Unix socket.

Nhược điểm của Unix socket

Nhược điểm cố hữu và không thể khắc phục của Unix socket là hai ứng dụng chỉ có thể kết nối với nhau trên cùng một máy chủ. Không thể kết nối hai ứng dụng bằng kết nối Unix socket nếu chúng ta có dự định scale ứng dụng ở nhiều máy chủ khác nhau, kể cả private network.

Thêm nữa, Unix socket thực chất là một "tập tin" trên máy chủ, nên đôi khi chúng ta sẽ gặp vấn đề về phân quyền. Tuy nhiên, mình rất ít khi gặp vấn đề này và có vẻ nó cũng an toàn hơn khi lỡ public các cổng của ứng dụng ra ngoài internet ;)

Nếu các bạn không scale, không phân chia ứng dụng web ra làm nhiều phần, database và webserver riêng thì không có gì phải đắn đo. Chuyển sang socket là điều nên làm.

Bài viết này sẽ hướng dẫn các bạn cấu hình các loại phần mềm sau:

Cách sử dụng Unix socket

Trong một buổi sáng thứ Bảy đẹp trời hôm nay, mình tiến hành nâng cấp các ứng dụng trên máy chủ và cũng cố gắng chuyển sang Unix socket tất cả có thể. Và bạn đoán xem, chỉ tốn khoảng 15p để Tuấn chuyển PHP, MySQL, WordPress,... sang Unix socket. Đó là vì các ứng dụng đa số đã hỗ trợ rồi, bạn chỉ việc thay đổi cấu hình từ TCP/IP sang Unix socket thôi.

Có downtime! Những thay đổi này sẽ khiến website bạn down trong khoảng 30s - 1 phút. Vì vậy, nếu website quan trọng, hãy đọc hết bài viết thật kĩ rồi mới tiến hành thay đổi.

Nên thực hiện theo thứ tự này để đảm bảo downtime ít nhất có thể bạn nhé.

MySQL

Thông thường MySQL đã chạy sẵn ở TCP và Unix socket rồi nên chúng ta không cần cấu hình hay khởi động lại gì cả. Tuy nhiên, để chắc chắn, hãy chạy lệnh sau để kiểm tra xem MySQL có đang LISTEN bằng Unix socket hay chưa:

netstat -ln | grep "unix.\*mysql"

true

Nếu trả về kết quả như hình trên thì quá đơn giản, hãy thay đổi source code của website để kết nối bằng Unix socket thay vì TCP.

Với WordPress, hãy mở tập tin wp-config.php và thay đổi dòng:

define('DB_HOST', 'localhost');

thành đường dẫn socket của MySQL vừa tìm được ở trên:

define('DB_HOST', 'localhost:/var/run/mysqld/mysqld.sock');

Vậy là xong. Bạn thử truy cập vào website WordPress của bạn xem có hoạt động không nhé. Để chắc chắn WordPress đang kết nối MySQL bằng socket, hãy cài plugin Server Info 🔗 và xem ở Settings > Server Info.

Redis

Nếu bạn không sử dụng Redis có thể bỏ qua phần này.

Đối với Redis thì chúng ta có thể chạy song song TCP và socket nên bạn cũng không phải lo lắng rằng sẽ bị ảnh hưởng đến website. Hãy mở tập tin /etc/redis/**redis.conf** và tìm, chỉnh sửa hai dòng bên dưới nhé.

unixsocket /var/run/redis/redis.sock
unixsocketperm 777

Sau đó khởi động lại bằng lệnh service redis-server restart và tiếp tục một số chỉnh sửa để WordPress và Nginx có thể kết nối tới. Nếu đang sử dụng plugin Redis Object Cache 🔗 để kết nối WordPress tới Redis, hãy chèn 2 dòng bên dưới vào tập tin wp-config.php:

define('WP_REDIS_SCHEME', 'unix');  
define('WP_REDIS_PATH', '/var/run/redis/redis.sock');

Nếu đang sử dụng Nginx kết nối tới Redis, hãy tiếp tục thực hiện những bước khác và thay đổi đường dẫn socket của Redis ở phần cấu hình Nginx. Khi đã hiện dòng chữ Status Connected với Path là đường dẫn của tập tin socket có nghĩa là chúng ta để kết nối thành công.

true

Trang quản lý của plugin Redis Object Cache.

Tiếp tục kiểm tra một lần nữa, hãy chắc chắn rằng WordPress đang đọc và ghi tới Redis bởi socket bằng câu lệnh:

redis-cli monitor

true

Chúng ta sẽ thấy đường dẫn tới tập tin socket thay vì 127.0.0.1:6379 như trước.

PHP-FPM

Việc chuyển từ TCP qua Unix socket với PHP-FPM là rất dễ. Bạn chỉ cần truy cập vào đường dẫn /etc/php/7.2/fpm/pool.d/ và chỉnh sửa tập tin www.conf 🔗.

Chỉnh sửa dòng bên dưới (cổng 9000 có thể khác nhau tùy phiên bản PHP của bạn hoặc ngẫu hứng):

listen = 127.0.0.1:9000

thành một đường dẫn, ví dụ:

listen = /var/run/php72-fpm.sock

Nếu khởi động lại ngay bây giờ, website của bạn sẽ gặp lỗi 502 Bad Gateway, chuyện này là bình thường thôi. Lí do là webserver như Nginx và Apache không thể kết nối tới PHP-FPM ở cổng 9000 nữa vì chúng ta mới thay đổi mà, nào chuyển sang bước tiếp theo thôi.

Nginx

Đối với Nginx, sẽ không có sự thay đổi từ TCP sang Unix socket vì Nginx đóng vai trò như webserver, phải luôn LISTEN ở một cổng nào đó và public ra bên ngoài để người dùng có thể truy cập.

Mục đích khi chỉnh sửa Nginx là giúp webserver này có thể kết nối tới các upstream, ví dụ như PHP-FPM, Redis (sau khi các upstream này chuyển sang Unix socket) để sử dụng mà thôi.

Hãy mở tập tin chứa các cấu hình upstream của bạn. Mình dùng EasyEngine thì nằm ở tập tin /etc/nginx/conf/**upstream.conf**.

Tại đây chúng ta sẽ thấy các upstream php, php7 (nếu có), redis (nếu có), memcache (nếu có) đều đang kết nối qua TCP. Hãy thay đổi lại thành đường dẫn mà bạn đã cấu hình ở phía trên cho PHP-FPM và Redis như sau:

upstream php {  
   server unix:/run/php5-fpm.sock;  
   # server 127.0.0.1:9000;  
}  
  
upstream php7 {  
   # server 127.0.0.1:9070;  
   # server unix:/var/run/php/php71-fpm.sock; # php7.1  
   server unix:/var/run/php/php72-fpm.sock; # php7.2  
   # server unix:/run/php/php73-fpm.sock; # php7.3  
}  
  
upstream redis {  
   server unix:/var/run/redis/redis.sock;  
   keepalive 10;  
}  

Chắc chắn chúng ta cấu hình Nginx đúng bằng lệnh nginx -t, sau đó restart lại Nginx (service nginx restart) là được.

Ngay sau đó khởi động lại PHP-FPM bằng lệnh service php7.2-fpm restart. Bạn sẽ thấy một tập tin có tên /var/run/**php72-fpm.sock, vậy là thành công rồi.

Bạn hãy truy cập website xem có bị 502 Bad Gateway nữa không nhé.

Apache

Tương tự Nginx, Apache bắt buộc phải chạy ở mode TCP, chúng ta chỉ việc thay đổi cấu hình của Apache để nó có thể kết nối các ứng dụng ở socket thay vì TCP. Trang document 🔗 của phần mềm có hướng dẫn khá chi tiết về cách sử dụng:

<FilesMatch "\.php$">  
 SetHandler "proxy:unix:/var/run/php72-fpm.sock"  
</FilesMatch>

Restart Apache và tận hưởng thành quả thôi. Lưu ý: Apache chỉ hỗ trợ unix socket ở phiên bản 2.4.7 trở lên.

Kết bài

Mong rằng các bước cấu hình của bạn đều thành công và quan trọng hơn hết là tốc độ xử lý nhanh hơn so với trước kia. Nếu có vấn đề với việc cấu hình các ứng dụng hay muốn hướng dẫn các ứng dụng mới, đừng ngần ngại để lại comment để mình biết và hỗ trợ bạn nhé.