1. Mở đầu.
Ở trong bài triển khai F-Stack Nginx ở trước đó mình đã có giải thích sơ qua rồi, nhưng bài này mình sẽ đi chi tiết hơn về lý thuyết bám sát tài liệu của tác giả.
- Tham khảo tài liệu gốc https://github.com/F-Stack/f-stack/blob/dev/doc/F-Stack_Nginx_APP_Guide.md
- Hoặc https://xajhuang.com:3100/cmhi/f-stack/src/commit/3f59e4d37dd8ea5c98a3e18bbca8129715048134/doc/F-Stack_Nginx_APP_Guide.md
2. Tổng quan về F-Stack.
- F-Stack là một framework mạng mã nguồn mở dựa trên DPDK (Data Plane Development Kit).
- Nó cải thiện hiệu năng xử lý gói tin bằng cách chạy các tác vụ mạng trong không gian người dùng (user-space) thay vì kernel.
- F-Stack hỗ trợ Nginx làm HTTP framework, giúp các ứng dụng web sử dụng giao thức HTTP dễ dàng tích hợp với F-Stack.
3. Kiến trúc Nginx sử dụng F-Stack.
Kiến trúc của Nginx tích hợp với F-Stack được mô tả như sau:
- Master Process:
- Điều khiển các tín hiệu như cập nhật lại cấu hình (
reload
) hoặc thoát (quit
). - Tạo và quản lý các worker process.
- Điều khiển các tín hiệu như cập nhật lại cấu hình (
- Worker Process:
- Mỗi worker process sẽ xử lý các kết nối mạng và request HTTP/HTTPS.
- Primary Worker được tạo đầu tiên để thiết lập cơ chế hoạt động với F-Stack.
- Secondary Workers được khởi tạo sau khi Primary Worker sẵn sàng.
- F-Stack Handling:
- Các worker process tích hợp thêm khả năng xử lý F-Stack thông qua các hàm:
ff_init()
– Khởi tạo F-Stack.ff_run(worker_process_cycle)
– Chạy vòng lặp xử lý của worker process, bao gồm cả sự kiện F-Stack và kernel.
- Các worker process tích hợp thêm khả năng xử lý F-Stack thông qua các hàm:
Giải thích sơ đồ Nginx tích hợp F-Stack.
Cấu trúc tổng thể.
Sơ đồ mô tả cách Nginx tích hợp với F-Stack xử lý yêu cầu từ bên ngoài theo cơ chế đa tiến trình (multi-process):
+--------+
+------------------------+ |
channel: socketpair |
+------------------------+ | signal(reload, quit..)
|
|
+---------v--------+
| |
+----------------+ master process +---------------+
| | | |
| channel +----------+-------+ |
| | channel |
| channel | |
| | |
+---------+----------+ +----------+--------+ +---------+--------+
first one to start | | | | | |
last one to exit<-+ primary worker | | secondary worker | | secondary worker |
| | | | | |
+--------------------+ +-------------------+ +------------------+
+--------------------+ +-------------------+
| | | |
| fstack,kernel | | fstack,kernel |
| and channel | | and channel |
| loop thread | | loop thread |
| | | |
+--------------------+ +-------------------+
woker process cycle woker process cycle
- Master Process:
- Chịu trách nhiệm:
- Quản lý các tín hiệu điều khiển như
reload
,quit
. - Tạo và giám sát các worker process.
- Quản lý các tín hiệu điều khiển như
- Sử dụng channel (cơ chế liên lạc giữa các tiến trình, thường là
socketpair
) để giao tiếp với các worker process.
- Chịu trách nhiệm:
- Worker Process:
- Chịu trách nhiệm xử lý các kết nối mạng, bao gồm:
- Primary Worker:
- Tiến trình worker đầu tiên được khởi tạo.
- Thiết lập và đảm bảo F-Stack hoạt động đúng cách.
- Là tiến trình cuối cùng kết thúc khi Nginx dừng hoạt động.
- Secondary Workers:
- Các tiến trình worker bổ sung để xử lý nhiều kết nối đồng thời.
- Tất cả các worker đều xử lý request theo vòng lặp (worker process cycle).
- Primary Worker:
- Chịu trách nhiệm xử lý các kết nối mạng, bao gồm:
- F-Stack và Kernel:
- F-Stack:
- Xử lý các gói tin trong user-space (thay vì kernel), giúp tăng hiệu năng mạng.
- Kernel:
- Một số tác vụ nhất định (nếu cấu hình
kernel_network_stack on
) sẽ được xử lý qua stack mạng của kernel.
- Một số tác vụ nhất định (nếu cấu hình
- Các worker có thể xử lý cả sự kiện từ kernel và F-Stack, tùy thuộc vào cấu hình.
- F-Stack:
Quy trình xử lý yêu cầu.
Dưới đây là quy trình xử lý khi có một request đến Nginx tích hợp F-Stack:
- Request đến từ Client:
- Ví dụ: Một trình duyệt gửi request đến server qua
http://example.com
.
- Ví dụ: Một trình duyệt gửi request đến server qua
- Master Process không xử lý trực tiếp request:
- Master process chỉ giao nhiệm vụ cho các worker process qua cơ chế channel.
- Worker Process nhận request:
- Request sẽ được nhận bởi một trong các worker process (Primary hoặc Secondary).
- Worker process kiểm tra cấu hình:
- Nếu request dành cho kernel network stack (khi
kernel_network_stack on
): Request sẽ được xử lý qua kernel. - Nếu request dành cho F-Stack: Request sẽ được xử lý hoàn toàn trong user-space qua F-Stack.
- Nếu request dành cho kernel network stack (khi
- Xử lý request với F-Stack:
- F-Stack sử dụng vòng lặp sự kiện (event loop) để xử lý:
- Nhận gói tin từ card mạng thông qua DPDK.
- Phân tích và xử lý HTTP (thông qua Nginx).
- Tạo response và gửi lại qua F-Stack.
- F-Stack sử dụng vòng lặp sự kiện (event loop) để xử lý:
- Response gửi lại Client:
- Sau khi hoàn thành xử lý, worker gửi phản hồi qua F-Stack hoặc kernel (tùy cấu hình) trở lại client.
Ví dụ minh họa với 1 request.
Bối cảnh:
- Server sử dụng Nginx tích hợp F-Stack.
- Cấu hình:
- Port 80, 443 được xử lý qua F-Stack (
kernel_network_stack off
). - Port 22 (SSH) được xử lý qua kernel (
kernel_network_stack on
).
- Port 80, 443 được xử lý qua F-Stack (
Quy trình:
- Request đến server:
- Một trình duyệt gửi HTTP request đến
http://example.com
qua port 80. - Request được nhận bởi card mạng (NIC).
- Một trình duyệt gửi HTTP request đến
- F-Stack nhận request:
- Worker process của Nginx nhận gói tin qua F-Stack (do port 80 được cấu hình sử dụng F-Stack).
- Worker phân tích gói tin HTTP.
- Xử lý request:
- Worker process kiểm tra cấu hình Nginx (ví dụ: tìm file hoặc nội dung cần phản hồi).
- Nếu là một file tĩnh, Nginx truy cập hệ thống file để lấy dữ liệu.
- Nếu là một yêu cầu proxy, Nginx chuyển tiếp qua proxy backend (nếu được cấu hình).
- Gửi phản hồi:
- Worker tạo response HTTP.
- Response được gửi lại qua F-Stack đến card mạng và trả về client.
Trường hợp khác (port 22):
- Nếu có một kết nối SSH qua port 22:
- Request được chuyển thẳng đến kernel network stack vì F-Stack không xử lý SSH.
- Kernel xử lý kết nối SSH và phản hồi client.
Ý nghĩa của vòng lặp xử lý (Worker Process Cycle)
- Worker Process Cycle là vòng lặp chính để worker process xử lý:
- Channel: Lắng nghe và phản hồi tín hiệu từ Master Process.
- F-Stack và Kernel: Xử lý các sự kiện mạng dựa trên cấu hình (như nhận gói tin, phân tích HTTP, gửi phản hồi).
- Với F-Stack, vòng lặp này tối ưu hiệu năng xử lý gói tin qua user-space.
Tóm tắt quy trình.
Bước | Hoạt động |
---|---|
1. Nhận request | Gói tin từ client được nhận qua NIC và chuyển vào F-Stack hoặc kernel tùy cấu hình. |
2. Phân tích | Worker process phân tích và xử lý yêu cầu (HTTP hoặc proxy). |
3. Tạo phản hồi | Worker process tạo response dựa trên cấu hình và dữ liệu được yêu cầu. |
4. Gửi response | Response được gửi lại client qua F-Stack hoặc kernel. |
4. Điểm khác biệt khi tích hợp F-Stack.
F-Stack thêm một số chỉ thị mới vào cấu hình Nginx khi NGX_HAVE_FSTACK
được định nghĩa.
kernel_network_stack
:- Mục đích: Quyết định server sử dụng kernel network stack hay F-Stack.
- Cách dùng:
kernel_network_stack on; # Sử dụng kernel network stack.
kernel_network_stack off; # Sử dụng F-Stack (mặc định).
proxy_kernel_network_stack
:
- Mục đích: Quyết định proxy (trong các block
http
,stream
,mail
, hoặcserver
) sử dụng kernel network stack hay F-Stack. - Cách dùng:
proxy_kernel_network_stack on; # Proxy sử dụng kernel network stack.
proxy_kernel_network_stack off; # Proxy sử dụng F-Stack (mặc định).
schedule_timeout
:
- Mục đích: Thiết lập khoảng thời gian polling để tương tác với kernel network stack.
- Cách dùng:
schedule_timeout 30ms; # Giá trị mặc định là 30ms.
5. Thay đổi cấu hình cần thiết.
Một số thay đổi quan trọng trong file cấu hình nginx.conf
khi sử dụng F-Stack:
user root;
:- Tài khoản
root
cần thiết để F-Stack hoạt động vì DPDK yêu cầu quyền root để tương tác trực tiếp với phần cứng mạng.
- Tài khoản
fstack_conf f-stack.conf;
:- Chỉ định đường dẫn file cấu hình F-Stack (
f-stack.conf
), mặc định nằm trong$NGX_PREFIX/conf/f-stack.conf
.
- Chỉ định đường dẫn file cấu hình F-Stack (
worker_processes
:- Phải bằng với số lõi CPU (lcore) được chỉ định trong
dpdk.lcore_mask
của file cấu hìnhf-stack.conf
.
- Phải bằng với số lõi CPU (lcore) được chỉ định trong
- Block
events
:worker_connections 102400;
: Tăng số lượng kết nối có thể xử lý đồng thời.use kqueue;
: Sử dụng cơ chế sự kiệnkqueue
(trên FreeBSD hoặc macOS).
sendfile off;
:- Tắt tính năng
sendfile
để tương thích với F-Stack (vì tính năng này dựa vào kernel network stack).
- Tắt tính năng
Với file nginx.conf
.
Các tùy chọn cài đặt này bạn có thể xem trong file cấu hình Nginx, ví dụ của mình đang đặt ở đây /usr/local/nginx_fstack/conf/nginx.conf
.
Dưới đây là phiên bản tối ưu và đầy đủ của file cấu hình Nginx, đảm bảo tương thích với F-Stack. Cấu hình này được chỉnh sửa để tối ưu hiệu suất và tuân thủ các yêu cầu đặc biệt của F-Stack.
cat > /usr/local/nginx_fstack/conf/nginx.conf << 'OEF'
user root;
worker_processes 1; # Cần phù hợp với dpdk.lcore_mask trong f-stack.conf
fstack_conf /usr/local/nginx_fstack/conf/f-stack.conf; # Đường dẫn chính xác tới f-stack.conf
events {
worker_connections 102400; # Tăng giới hạn kết nối đồng thời
use kqueue; # Cần thiết để tương thích với F-Stack
}
http {
include mime.types;
default_type application/octet-stream;
sendfile off; # Bắt buộc phải tắt sendfile cho F-Stack
keepalive_timeout 65;
# Log cấu hình, giúp giám sát
access_log /var/log/nginx/access.log combined;
error_log /var/log/nginx/error.log error;
# Tăng giới hạn kích thước request
client_max_body_size 2048m;
# Server chính chạy trên port 80
server {
listen 80; # Lắng nghe trên port 80
server_name hoanghd.com;
root /home/www/; # Thư mục gốc của website
index index.html; # File mặc định
charset utf-8;
location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering on;
# Timeout tối ưu cho request dài
proxy_connect_timeout 30s;
proxy_read_timeout 30s;
proxy_send_timeout 30s;
send_timeout 30s;
# Tăng cường bảo mật
add_header Content-Security-Policy upgrade-insecure-requests;
}
}
}
OEF
Với file f-stack.conf
.
Đảm bảo rằng file f-stack.conf
tương thích với cấu hình Nginx. Dưới đây là ví dụ cơ bản:
cat > /usr/local/nginx_fstack/conf/f-stack.conf << 'OEF'
[dpdk]
lcore_mask=1
channel=4
promiscuous=1
numa_on=1
nb_mbufs=65535
rx_mbufs=2048
tx_mbufs=2048
tx_csum_offoad_skip=0
tso=0
vlan_strip=1
idle_sleep=0
pkt_tx_delay=100
symmetric_rss=0
port_list=0
nb_vdev=0
nb_bond=0
[pcap]
enable = 0
snaplen= 96
savelen= 16777216
[port0]
addr=10.237.7.79
netmask=255.255.255.0
broadcast=10.237.7.255
gateway=10.237.7.1
[kni]
enable=1
method=reject
tcp_port=80,443
[freebsd.boot]
hz=100
fd_reserve=1024
kern.ipc.maxsockets=262144
net.inet.tcp.syncache.hashsize=4096
net.inet.tcp.syncache.bucketlimit=100
net.inet.tcp.tcbhashsize=65536
kern.ncallout=262144
kern.features.inet6=1
net.inet6.ip6.auto_linklocal=1
net.inet6.ip6.accept_rtadv=2
net.inet6.icmp6.rediraccept=1
net.inet6.ip6.forwarding=0
[freebsd.sysctl]
kern.ipc.somaxconn=32768
kern.ipc.maxsockbuf=16777216
net.link.ether.inet.maxhold=5
net.inet.tcp.fast_finwait2_recycle=1
net.inet.tcp.sendspace=16384
net.inet.tcp.recvspace=8192
net.inet.tcp.cc.algorithm=cubic
net.inet.tcp.sendbuf_max=16777216
net.inet.tcp.recvbuf_max=16777216
net.inet.tcp.sendbuf_auto=1
net.inet.tcp.recvbuf_auto=1
net.inet.tcp.sendbuf_inc=16384
net.inet.tcp.recvbuf_inc=524288
net.inet.tcp.sack.enable=1
net.inet.tcp.blackhole=1
net.inet.tcp.msl=2000
net.inet.tcp.delayed_ack=0
net.inet.udp.blackhole=1
net.inet.ip.redirect=0
net.inet.ip.forwarding=0
OEF
Hoặc bạn có thể tách ra nhiều file config theo nhu cầu với block [stack]
, đây là một tùy chọn để cung cấp thêm cấu hình chi tiết hơn cho các tham số của network stack. Nếu không có phần này, F-Stack sẽ sử dụng các giá trị mặc định đã được định nghĩa trong mã nguồn hoặc trong các file cấu hình DPDK.
Ví dụ ở dưới đây mình vẫn giữ cấu hình trên nhưng mình tách [freebsd.sysctl]
ra một file riêng, lúc đó file f-stack.conf
chính bạn chỉ cần khai báo thêm block [stack]
với conf=/usr/local/nginx_fstack/conf/stack-custom.conf
là đường dẫn đến file chứa block [freebsd.sysctl]
nhé.
cat > /usr/local/nginx_fstack/conf/stack-custom.conf << 'OEF'
[dpdk]
lcore_mask=1
channel=4
promiscuous=1
numa_on=1
nb_mbufs=65535
rx_mbufs=2048
tx_mbufs=2048
tx_csum_offoad_skip=0
tso=0
vlan_strip=1
idle_sleep=0
pkt_tx_delay=100
symmetric_rss=0
port_list=0
nb_vdev=0
nb_bond=0
[pcap]
enable = 0
snaplen= 96
savelen= 16777216
[port0]
addr=10.237.7.79
netmask=255.255.255.0
broadcast=10.237.7.255
gateway=10.237.7.1
[kni]
enable=1
method=reject
tcp_port=80,443
[freebsd.boot]
hz=100
fd_reserve=1024
kern.ipc.maxsockets=262144
net.inet.tcp.syncache.hashsize=4096
net.inet.tcp.syncache.bucketlimit=100
net.inet.tcp.tcbhashsize=65536
kern.ncallout=262144
kern.features.inet6=1
net.inet6.ip6.auto_linklocal=1
net.inet6.ip6.accept_rtadv=2
net.inet6.icmp6.rediraccept=1
net.inet6.ip6.forwarding=0
[stack]
conf=/usr/local/nginx_fstack/conf/stack-custom.conf
OEF
Đây là file chứa nội dung config /usr/local/nginx_fstack/conf/stack-custom.conf
của block [freebsd.sysctl]
.
cat > /usr/local/nginx_fstack/conf/stack-custom.conf << 'OEF'
[freebsd.sysctl]
kern.ipc.somaxconn=32768
kern.ipc.maxsockbuf=16777216
net.link.ether.inet.maxhold=5
net.inet.tcp.fast_finwait2_recycle=1
net.inet.tcp.sendspace=16384
net.inet.tcp.recvspace=8192
net.inet.tcp.cc.algorithm=cubic
net.inet.tcp.sendbuf_max=16777216
net.inet.tcp.recvbuf_max=16777216
net.inet.tcp.sendbuf_auto=1
net.inet.tcp.recvbuf_auto=1
net.inet.tcp.sendbuf_inc=16384
net.inet.tcp.recvbuf_inc=524288
net.inet.tcp.sack.enable=1
net.inet.tcp.blackhole=1
net.inet.tcp.msl=2000
net.inet.tcp.delayed_ack=0
net.inet.udp.blackhole=1
net.inet.ip.redirect=0
net.inet.ip.forwarding=0
OEF
Tối ưu hóa
- F-Stack Configuration
- Xác định
dpdk.port_list
tương ứng với giao diện mạng được sử dụng. - Đảm bảo card mạng hỗ trợ DPDK và đã bind đúng với
vfio-pci
.
- Xác định
- Hệ thống log
- Tăng quyền ghi log để tránh lỗi khi ghi:
mkdir -p /var/log/nginx/
chmod 644 /var/log/nginx/*.log
- Hiệu suất
- Sử dụng cấu hình
worker_connections
cao để hỗ trợ nhiều kết nối đồng thời. - Đảm bảo
keepalive_timeout
vừa đủ để tránh giữ kết nối quá lâu.
- Sử dụng cấu hình
- Kiểm tra tính tương thích
- Sau khi khởi động Nginx, kiểm tra log
/var/log/nginx/error.log
và/var/log/f-stack.log
để xác nhận F-Stack đang chạy.
- Sau khi khởi động Nginx, kiểm tra log
Khởi động Nginx.
Check cấu hình, nếu không có lỗi, bạn sẽ thấy dòng syntax is ok
.
shell> /usr/local/nginx_fstack/sbin/nginx -t
nginx: the configuration file /usr/local/nginx_fstack/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx_fstack/conf/nginx.conf test is successful
Khởi động Nginx.
/usr/local/nginx_fstack/sbin/nginx -s stop
/usr/local/nginx_fstack/sbin/nginx
Kiểm tra dịch vụ Nginx.
shell> ps -aef | grep nginx
root 24849 1 0 01:44 ? 00:00:00 nginx: master process /usr/local/nginx_fstack/sbin/nginx
root 24850 24849 99 01:44 ? 06:04:25 nginx: worker process
root 25354 22170 0 07:49 pts/2 00:00:00 grep nginx
Với cấu hình này, Nginx sẽ chạy trên nền F-Stack và được tối ưu để xử lý nhiều kết nối với độ trễ thấp.
6. Quá trình biên dịch Nginx với F-Stack.
Để tích hợp F-Stack, bạn cần biên dịch lại Nginx:
- Lệnh cấu hình (
configure
):
./configure --prefix=/usr/local/nginx_fstack --with-ff_module
--prefix=/usr/local/nginx_fstack
: Đường dẫn cài đặt Nginx tích hợp F-Stack.--with-ff_module
: Bật module F-Stack.
Biên dịch và cài đặt:
make
make install
7. Kết luận.
Khi sử dụng Nginx với F-Stack:
- F-Stack thay thế kernel network stack, xử lý trực tiếp các gói tin trong user-space để đạt hiệu năng cao hơn.
- File cấu hình cần thay đổi để tối ưu với F-Stack (ví dụ: tắt
sendfile
, tăngworker_connections
). - Một số chỉ thị mới (
kernel_network_stack
,proxy_kernel_network_stack
,schedule_timeout
) cho phép điều chỉnh cách Nginx tương tác với F-Stack và kernel network stack.