1. DPDK là gì?
DPDK (Data Plane Development Kit) là một bộ thư viện và driver được thiết kế để tăng hiệu suất xử lý gói tin của network trên các hệ thống x86 và một số kiến trúc phần cứng khác. Nó cung cấp cơ chế truy cập trực tiếp đến phần cứng của card mạng (NIC – Network Interface Card) mà không cần thông qua kernel của hệ điều hành, từ đó giảm đáng kể độ trễ và tăng throughput.
- Các đặc điểm chính:
- Xử lý gói tin tốc độ cao, hỗ trợ lên tới hàng triệu request mỗi giây.
- Tận dụng tối đa tài nguyên phần cứng, như CPU và NIC.
- Cung cấp các API cho việc xử lý gói tin trực tiếp.
- Ứng dụng:
- DPDK thường được sử dụng trong các hệ thống cần network có hiệu năng cao, như firewall, load balancer và các ứng dụng sử dụng network thời gian thực.
2. F-Stack là gì?
F-Stack là một framework sử dụng cho network được xây dựng trên DPDK, sử dụng mô hình TCP/IP stack của FreeBSD để cung cấp network có hiệu suất tốc độ cao. F-Stack được thiết kế để tích hợp dễ dàng với các ứng dụng hiện có như Nginx hoặc Redis, cải thiện throughput và giảm độ trễ.
- Đặc điểm chính:
- Tích hợp chặt chẽ với DPDK, sử dụng truy cập trực tiếp đến phần cứng network.
- Hỗ trợ TCP/IP stack từ FreeBSD, cung cấp giao diện lập trình tương tự hệ thống POSIX.
- Cho phép các ứng dụng sử dụng network truyền thống (như Nginx) chạy trên F-Stack mà không cần thay đổi lớn trong mã nguồn.
- Ứng dụng:
- Các dịch vụ network đòi hỏi throughput cao, như proxy, CDN, hoặc các hệ thống cần xử lý gói tin lớn.
Nginx là một web server mã nguồn mở phổ biến, được sử dụng như một reverse proxy, load balancer, HTTP cache và nhiều ứng dụng khác. Nginx nổi tiếng nhờ khả năng xử lý đồng thời hàng nghìn kết nối với hiệu suất cao.
- Nginx được sử dụng làm máy chủ xử lý HTTP, tuy nhiên khi sử dụng trong môi trường cần throughput cao (hàng triệu request/giây), nó có thể bị giới hạn bởi kernel của hệ điều hành.
- F-Stack giúp Nginx tận dụng DPDK để bỏ qua kernel và xử lý gói tin trực tiếp trên phần cứng mạng. Điều này cải thiện hiệu suất Nginx đáng kể:
- Tăng số lượng request/giây.
- Giảm độ trễ xử lý.
- DPDK là lớp thấp hơn, cung cấp một cổng để truy cập và xử lý gói tin nhanh hơn thông qua driver phần cứng.
3. Mô hình hoạt động.
- Truyền thống:
- Gói tin đi từ NIC → Kernel (TCP/IP stack) → Nginx xử lý.
- Kernel gây overhead lớn, ảnh hưởng đến hiệu suất.
- Gói tin đi từ NIC → Kernel (TCP/IP stack) → Nginx xử lý.
- Với F-Stack và DPDK:
- Gói tin đi từ NIC → DPDK → TCP/IP Stack của FreeBSD (F-Stack) → Nginx xử lý.
- Kernel được bỏ qua, tăng hiệu suất đáng kể.
- Gói tin đi từ NIC → DPDK → TCP/IP Stack của FreeBSD (F-Stack) → Nginx xử lý.
4. Tại sao cần sử dụng F-Stack với Nginx?
- Hiệu suất cao hơn: Bằng cách sử dụng DPDK và F-Stack, Nginx có thể đạt throughput cao hơn rất nhiều, đặc biệt trong các môi trường yêu cầu xử lý hàng triệu request/giây.
- Độ trễ thấp: Bỏ qua kernel giúp giảm độ trễ khi xử lý các gói tin mạng.
- Tận dụng phần cứng: F-Stack tận dụng khả năng tối đa của NIC và CPU, đặc biệt với hệ thống có nhiều core CPU.
- Tổng hợp lại chúng ta nói ngắn gọn như sau:
- DPDK: Cung cấp thư viện để xử lý gói tin tốc độ cao ở mức phần cứng.
- F-Stack: Tích hợp DPDK và TCP/IP stack, giúp Nginx chạy hiệu quả hơn trên môi trường cần network có hiệu suất cao.
- Nginx: Là một webserver hưởng lợi từ F-Stack để xử lý lượng lớn kết nối và request nhanh hơn, giảm thiểu bottleneck từ kernel.
TCP/IP Stack là mô hình quản lý cách dữ liệu được truyền từ máy tính này sang máy tính khác thông qua mạng IP như Internet.
5. Chuẩn bị trên F-Stack Nginx.
5.1. Cấu hình F-Stack.
File f-stack.conf.
Hãy tham khảo file cấu hình /usr/local/nginx_fstack/conf/f-stack.conf
của mình đã tối ưu để benchmark dưới đây.
cat > /usr/local/nginx_fstack/conf/f-stack.conf << 'OEF'
[dpdk]
lcore_mask=14
channel=14
promiscuous=1
numa_on=1
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
[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
Mình giải thích một số Option liên quan đến kết quả benchmard như sau:
Tại block [dpdk].
lcore_mask=14.
- Quy định các core CPU (logical cores) sẽ được sử dụng bởi DPDK.
- Giá trị
14
(1110 trong nhị phân) chỉ định các lõi CPU 1, 2, và 3 được sử dụng. - Càng nhiều core CPU được chỉ định, hệ thống xử lý đồng thời nhiều gói tin hơn, cải thiện throughput.
Cách tính lcore_mas
, ví dụ của mình đang có 16 core CPU.
Sử dụng công cụ để tính nhanh:
hex_mask = hex(int('1111000000000000', 2)) # Sử dụng core 12-15
print(hex_mask) # Kết quả: 0xF000
Ví dụ với 16 core CPU.
Lõi sử dụng | Binary Mask | Hexadecimal Mask (lcore_mask ) |
---|---|---|
Core 0-3 | 0000000000001111 | 0x000F |
Core 4-7 | 0000000011110000 | 0x00F0 |
Core 8-11 | 0000111100000000 | 0x0F00 |
Core 12-15 | 1111000000000000 | 0xF000 |
Áp dụng
- Bạn có 16 core CPU:
- Nếu muốn DPDK sử dụng tất cả các core, mask nhị phân là
1111111111111111
→ hex là0xFFFF
. - Nếu muốn giới hạn số core, bạn chỉ cần thay đổi các bit tương ứng.
- Nếu muốn DPDK sử dụng tất cả các core, mask nhị phân là
- Lưu ý:
- Chỉ chọn số core đủ cần thiết, vì chọn quá nhiều core có thể gây lãng phí tài nguyên.
- Đảm bảo rằng các core được chọn không bị sử dụng bởi các tiến trình khác (ví dụ: OS hoặc ứng dụng).
channel=14.
- Xác định số lượng queues (hàng đợi) được sử dụng trên mỗi port mạng.
- Giá trị này thường đồng bộ với
lcore_mask
để tối ưu việc phân bổ gói tin. - Số lượng queue đủ lớn đảm bảo không xảy ra bottleneck khi xử lý gói tin.
Giá trị của channel
trong cấu hình DPDK (f-stack.conf
) xác định queue mà mỗi port mạng sẽ sử dụng cho việc xử lý gói tin. Lựa chọn giá trị tối ưu cho channel
phụ thuộc vào số lượng core CPU và đặc điểm của lưu lượng mạng.
Mỗi queue được gắn với một core CPU để xử lý. Số lượng channel
thường không vượt quá số core CPU được phân bổ. Nếu không, một số queue sẽ không được xử lý.
Công thức cơ bản:
channel ≤ số core được bật bởi lcore_mask
Liên quan đến phần cứng NIC:
- Một số card mạng (NIC) hỗ trợ nhiều queue (multi-queue), thường sử dụng RSS (Receive Side Scaling) để phân phối gói tin đến các queue khác nhau.
- Số lượng queue tối đa phụ thuộc vào card mạng:
- Ví dụ: Một NIC có thể hỗ trợ tối đa 16 hoặc 32 queue.
Công thức ràng buộc:
channel ≤ số queue tối đa của NIC
- Nếu lưu lượng cao (nhiều gói tin/giây): Tăng
channel
để phân tải công việc qua nhiều core CPU. - Nếu lưu lượng thấp: Không cần thiết sử dụng quá nhiều queue, vì điều này có thể làm tăng overhead.
Tính toán tối ưu cho channel
:
Giả sử:
- NIC: Hỗ trợ 16 hàng đợi.
- Số core CPU được sử dụng (
lcore_mask
): 14 (kích hoạt 14 CPU, chừa 2 CPU xử lý cho tác vụ khác, ví dụ cho OS hoặc cho Kernel). - Tốc độ mạng: 25 Gbps, lưu lượng cao.
Lựa chọn channel
:
Số hàng đợi tối đa khả dụng:
Min(số lõi CPU, số queue NIC) = Min(14, 16) = 14
Lựa chọn kịch bản tối ưu:
- Khi cần hiệu năng tối đa: Sử dụng toàn bộ 14 queue (channel = 14). Mỗi core CPU sẽ gắn với một queue tương đương với 1 channel.
- Khi lưu lượng thấp: Giảm
channel
(ví dụ: 8 hoặc 10), để tiết kiệm tài nguyên mà vẫn đảm bảo hiệu năng.
Kiểm tra hiệu năng:
- Sau khi thiết lập
channel=14
, chạy thử nghiệm benchmark (ví dụ:wrk
) để kiểm tra hiệu năng. - Nếu thấy độ trễ tăng cao hoặc CPU không được sử dụng đều (một số lõi bị quá tải):
- Giảm
channel
để tối ưu hóa. - Tăng RSS của NIC nếu hỗ trợ (cần kiểm tra cấu hình phần cứng).
- Giảm
Một số lưu ý:
- RSS (Receive Side Scaling): Đảm bảo RSS được bật trên NIC để gói tin được phân phối đều qua các hàng đợi.
- NUMA (Non-Uniform Memory Access):
- Nếu hệ thống có nhiều nút NUMA, cần gắn các core CPU với các queue thuộc cùng nút NUMA của NIC.
- Kiểm tra tài nguyên phần cứng: Dùng lệnh như
dpdk-devbind
hoặclscpu
để kiểm tra số channel hỗ trợ của NIC và khả năng phần cứng.
Trong trường hợp của mình, channel=14
là hợp lý vì khớp với số core của CPU được phân bổ. Nếu muốn giảm tải hoặc tối ưu hơn, có thể thử nghiệm với các giá trị nhỏ hơn như 8 hoặc 10 để xem mức độ cải thiện hiệu năng.
promiscuous=1
- Kích hoạt chế độ Promiscuous, cho phép nhận tất cả các gói tin đến port mạng, không phân biệt địa chỉ MAC.
- Chế độ này tăng cường khả năng benchmark nhưng có thể gây giảm hiệu suất thực tế.
numa_on=1
- Bật hỗ trợ NUMA (Non-Uniform Memory Access) để đảm bảo core CPU chỉ sử dụng bộ nhớ cục bộ.
- Cải thiện hiệu suất trên hệ thống đa socket bằng cách giảm độ trễ truy cập bộ nhớ.
tx_csum_offoad_skip=0
- Bật tính năng tính toán checksum (CSUM) tự động khi gửi gói tin.
- Tính năng này giảm tải CPU, tăng throughput khi xử lý gói tin.
tso=0
- Tắt TCP Segmentation Offload (TSO), NIC sẽ không tự động phân chia gói tin lớn thành các gói tin nhỏ.
- Tắt TSO giúp kiểm soát tốt hơn lưu lượng trong môi trường benchmark nhưng có thể giảm throughput.
pkt_tx_delay=100
- Định nghĩa độ trễ giữa các lần gửi gói tin.
- Giá trị lớn hơn có thể giảm throughput, nhưng nhỏ hơn giúp tăng tốc độ xử lý.
nb_vdev=0, nb_bond=0
- Quy định số lượng vdev và bonding.
- Trong trường hợp không dùng vdev hoặc bonding, giá trị 0 tối ưu hiệu suất.
Tại block [freebsd.boot]
hz=100
- Quy định số lần hệ thống thực hiện ngắt mỗi giây.
- Tần suất ngắt cao hơn giúp xử lý sự kiện nhanh hơn nhưng có thể tăng tải CPU.
fd_reserve=1024
- Giữ lại 1024 descriptor file cho mục đích sử dụng nội bộ.
- Tránh việc thiếu file descriptor khi benchmark ở mức tải cao.
kern.ipc.maxsockets=262144
- Tăng giới hạn số socket tối đa mà hệ thống có thể mở.
- Cần thiết khi xử lý lượng kết nối đồng thời lớn.
Các thông số hash (net.inet.tcp.syncache.*
)
- Tăng kích thước và số lượng hash bucket cho bảng TCP syncache.
- Giúp quản lý kết nối TCP đồng thời lớn hiệu quả hơn.
kern.features.inet6=1, net.inet6.*
- Bật hỗ trợ IPv6 và các thiết lập liên quan.
- Tăng khả năng xử lý gói tin IPv6, quan trọng nếu hệ thống hỗ trợ cả IPv4 và IPv6.
Tại block [freebsd.sysctl]
kern.ipc.somaxconn=32768
- Tăng giới hạn hàng đợi kết nối đến (listen queue) cho mỗi socket.
- Giúp ngăn chặn hiện tượng
kết nối bị từ chối
khi lượng kết nối đồng thời lớn.
kern.ipc.maxsockbuf=16777216
- Tăng kích thước tối đa của buffer socket.
- Cải thiện throughput khi xử lý gói tin lớn.
net.inet.tcp.*
fast_finwait2_recycle=1
: Tăng tốc độ giải phóng socket sau khi kết thúc kết nối.sendbuf_max
&recvbuf_max
: Tăng kích thước buffer gửi và nhận tối đa.delayed_ack=0
: Tắt tính năng delayed acknowledgment, giảm độ trễ khi xử lý TCP.- Các tùy chọn này giúp tối ưu hóa xử lý TCP, giảm độ trễ và tăng throughput.
net.inet.udp.blackhole=1, net.inet.ip.redirect=0
- UDP Blackhole: Bỏ qua gói tin UDP không cần thiết.
- IP Redirect: Tắt chuyển tiếp IP.
- Ảnh hưởng benchmark: Giảm tải không cần thiết khi xử lý gói tin.
- Với các thiết lập như trên chúng ta sẽ có một kết quả:
- Throughput cao hơn: Nhờ vào cấu hình tối ưu của DPDK và F-Stack (ví dụ:
lcore_mask
,kern.ipc.maxsockbuf
). - Giảm độ trễ: Cấu hình TCP như
delayed_ack=0
vàpkt_tx_delay=100
giảm thiểu độ trễ trong quá trình xử lý gói tin. - Khả năng mở rộng: Cấu hình như
kern.ipc.maxsockets
vàkern.ipc.somaxconn
hỗ trợ lượng kết nối lớn. - Kiểm soát chính xác: Tắt TSO (
tso=0
) và bật chế độ Promiscuous đảm bảo kết quả benchmark chính xác.
- Throughput cao hơn: Nhờ vào cấu hình tối ưu của DPDK và F-Stack (ví dụ:
File nginx.conf.
Tham khảo cấu hình nginx.conf
của mình, nó ra có một số tùy chọn quan trọng ảnh hưởng trực tiếp đến hiệu năng benchmark khi sử dụng F-Stack Nginx.
cat > /usr/local/nginx_fstack/conf/nginx.conf << 'OEF'
user root;
worker_processes auto;
fstack_conf f-stack.conf;
events {
worker_connections 102400;
use kqueue;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile off;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
access_log /dev/null;
location / {
return 200 "<title>Welcome to F-Stack Nginx!</title>\r\n pad data:0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789";
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
OEF
Các tham số cần quan tâm.
Worker_processes auto.
- Ý nghĩa:
- Tự động thiết lập số lượng quy trình làm việc (worker processes) dựa trên số lượng CPU khả dụng trên hệ thống.
- Trong F-Stack, mỗi worker process thường được gắn với một core CPU (
lcore
) để xử lý luồng gói tin, đảm bảo sử dụng tối đa tài nguyên CPU.
- Tác động đến benchmark:
- Khi kết hợp với
lcore_mask
trongf-stack.conf
, số lượng worker process sẽ khớp với số lượng core CPU được chỉ định để xử lý. - Nếu số lượng worker processes quá ít so với số lõi CPU khả dụng, sẽ không tận dụng hết tài nguyên.
- Nếu quá nhiều, có thể gây xung đột và giảm hiệu năng.
- Khi kết hợp với
Worker_connections.
Ý nghĩa:
- Thiết lập số lượng kết nối tối đa mà mỗi worker process có thể xử lý đồng thời.
- Giá trị lớn như
102400
phù hợp cho các hệ thống benchmark cao, nơi nhiều kết nối song song được gửi đến máy chủ.
Tác động đến benchmark:
- Nếu giá trị này thấp hơn số lượng kết nối cần kiểm tra (ví dụ:
wrk -c2000
), một số kết nối sẽ bị từ chối. - Với giá trị lớn, máy chủ có thể xử lý nhiều kết nối đồng thời mà không gặp giới hạn.
Fstack_conf
- Ý nghĩa:
- Chỉ định file cấu hình của F-Stack (
f-stack.conf
), nơi định nghĩa cách DPDK và F-Stack hoạt động (ví dụ: cấu hình port mạng, queues, core CPU).
- Chỉ định file cấu hình của F-Stack (
- Tác động đến benchmark:
- Hiệu năng phụ thuộc trực tiếp vào các tùy chọn trong
f-stack.conf
, nhưlcore_mask
,channel
,nb_bond
,tx_csum_offload_skip
, v.v.
- Hiệu năng phụ thuộc trực tiếp vào các tùy chọn trong
Use kqueue
- Ý nghĩa:
- Chỉ định cơ chế sự kiện (event mechanism) sử dụng trong Nginx.
kqueue
là cơ chế sự kiện hiệu quả trên hệ thống FreeBSD (và cũng được F-Stack hỗ trợ).
- Chỉ định cơ chế sự kiện (event mechanism) sử dụng trong Nginx.
- Tác động đến benchmark:
kqueue
hoạt động tốt khi xử lý nhiều kết nối đồng thời, giảm tài nguyên xử lý của CPU so với cơ chế khác nhưpoll
.
Sendfile
- Ý nghĩa:
- Tắt chế độ
sendfile
, vốn tối ưu hóa việc gửi file trực tiếp từ bộ nhớ kernel tới socket. - F-Stack không sử dụng stack TCP/IP của kernel, nên chế độ này không hoạt động và cần tắt.
- Tắt chế độ
- Tác động đến benchmark:
- Loại bỏ các overhead không cần thiết, cải thiện hiệu năng khi xử lý lưu lượng chỉ là văn bản hoặc dữ liệu nhỏ.
Keepalive_timeout.
- Ý nghĩa:
- Định nghĩa thời gian chờ (timeout) để giữ một kết nối HTTP mở sau khi xử lý xong yêu cầu trước.
- Tác động đến benchmark:
- Với giá trị
65s
, các kết nối sẽ không bị đóng ngay lập tức sau khi phục vụ xong, giảm overhead cho việc thiết lập lại kết nối trong các thử nghiệm với nhiều kết nối liên tục.
- Với giá trị
Trả về nội dung lớn trong location /
.
- Ý nghĩa:
- Trả về một chuỗi dữ liệu lớn (bao gồm cả
pad data
) trong response.
- Trả về một chuỗi dữ liệu lớn (bao gồm cả
- Tác động đến benchmark:
- Nội dung trả về ảnh hưởng đến lượng dữ liệu truyền đi trong mỗi kết nối.
- Dữ liệu lớn hơn yêu cầu hệ thống xử lý nhiều hơn (đọc, ghi, gửi qua mạng), gây tải nặng hơn so với trả về response nhỏ.
Access_log
- Ý nghĩa:
- Tắt ghi log truy cập vào file bằng cách ghi trực tiếp vào
/dev/null
.
- Tắt ghi log truy cập vào file bằng cách ghi trực tiếp vào
- Tác động đến benchmark:
- Loại bỏ tiến trình ghi log, giảm I/O disk, giúp tăng tốc độ xử lý và tối ưu hóa hiệu năng khi benchmark.
Các tối ưu liên quan đến lỗi:
error_page 500 502 503 504 /50x.html
:- Định nghĩa trang lỗi mặc định.
- Trong trường hợp benchmark, nếu gặp lỗi server, máy chủ sẽ gửi trang lỗi này, có thể làm tăng thời gian phản hồi do phải tìm và gửi file HTML.
Tối ưu hóa thêm.
- Sử dụng
reuseport
:- Thêm tùy chọn
reuseport
vào lệnhlisten
:
- Thêm tùy chọn
listen 80 reuseport;
Cho phép nhiều worker process xử lý song song trên cùng một cổng.
Giảm thời gian keepalive_timeout
:
Nếu thử nghiệm chỉ đo hiệu năng xử lý request, giảm giá trị này xuống (ví dụ: 10s
) để giảm tài nguyên bị chiếm bởi các kết nối không cần thiết.
Kiểm tra cấu hình f-stack.conf
:
Đảm bảo lcore_mask
và channel
phù hợp với số worker processes.
Tăng giá trị net.inet.tcp.syncache.bucketlimit
và kern.ipc.somaxconn
:
Cấu hình trong f-stack.conf
này sẽ đảm bảo xử lý tốt hơn các kết nối đồng thời.
Việc cấu hình trên được thiết kế để tận dụng hiệu năng của F-Stack khi benchmark, nhưng có thể cải thiện thêm bằng cách điều chỉnh các tùy chọn như reuseport
, worker_connections
, và các giá trị timeout.
6. Chuẩn bị trên máy Client.
Cài đặt công cụ wrk
.
Mình sử dụng một server chạy Ubuntu 18.04 cùng subnet. Sử dụng công cụ wrk
để gửi yêu cầu HTTP đến webserver và đo lường các thông số như độ trễ, số lượng yêu cầu mỗi giây, tỷ lệ lỗi, tốc độ chuyển dữ liệu, v.v.
shell> lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 18.04.6 LTS
Release: 18.04
Codename: bionic
Cài đặt các gói hỗ trợ biên dịch.
apt update
apt install make unzip -y
apt install build-essential -y
Tải source code của WRK về và build nó.
git clone https://github.com/wg/wrk.git wrk
cd wrk
make
Đây là các tùy chọn của lệnh wrk, tham khảo link.
shell> wrk-cmm -v
wrk 4.1.0-16-g8d0a45d [epoll] Copyright (C) 2012 Will Glozer
Usage: wrk <options> <url>
Options:
-c, --connections <N> Connections to keep open
-d, --duration <T> Duration of test
-t, --threads <N> Number of threads to use
-b, --bind-ip <S> Source IP (or CIDR mask)
-s, --script <S> Load Lua script file
-H, --header <H> Add header to request
--latency Print latency statistics
--breakout Print breakout statistics
--timeout <T> Socket/request timeout
-v, --version Print version details
Numeric arguments may include a SI unit (1k, 1M, 1G)
Time arguments may include a time unit (2s, 2m, 2h
Kiểm tra giới hạn ulimit
.
Kiểm tra giới hạn hiện tại bằng lệnh:
ulimit -n
Nếu giá trị này quá thấp (vd: 1024), cần tăng lên. Do đây là server chạy công cụ test nên mình chỉ tăng giới hạn tạm thời:
ulimit -n 65536
Tăng giới hạn số lượng threads tạm thời trong hệ thống.
ulimit -u 65536
Kiểm tra giới hạn thread:
ulimit -u
Mở file /etc/sysctl.conf
thêm hoặc chỉnh sửa các dòng dưới để tăng giá trị file descriptors và thread tối đa trong kernel.
fs.file-max = 2097152
kernel.threads-max = 2097152
Áp dụng cấu hình.
sysctl -p
7. Benchmark.
Sử dụng lệnh này sử dụng công cụ wrk để thực hiện kiểm tra hiệu suất của một webserver. Cụ thể:
./wrk -t10 -c1000 -d30s http://10.237.7.78
-t10
: Sử dụng 10 threads (luồng) để gửi các yêu cầu đồng thời đến máy chủ.-c1000
: Mở 1000 kết nối đồng thời với webserver. Đây là số lượng kết nối mà công cụ sẽ duy trì trong suốt thời gian chạy bài kiểm tra.-d30s
: Thực hiện bài kiểm tra trong 30 giây.http://<webserver>
: Địa chỉ của webserver mà bài kiểm tra sẽ gửi yêu cầu tới.
Kết quả khi xử lý qua Kernel.
root@node78:~/wrk# ./wrk -t10 -c1000 -d30s http://10.237.7.78
Running 30s test @ http://10.237.7.78
10 threads and 1000 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 8.25ms 7.28ms 76.76ms 84.81%
Req/Sec 14.33k 2.55k 28.16k 65.85%
4275390 requests in 30.07s, 3.42GB read
Requests/sec: 142183.73
Transfer/sec: 116.47MB
Khi xử lý qua DPDK.
root@node78:~/wrk# ./wrk -t10 -c1000 -d30s http://10.237.7.79
Running 30s test @ http://10.237.7.79
10 threads and 1000 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 21.73ms 52.38ms 690.81ms 88.45%
Req/Sec 38.10k 4.25k 63.18k 76.79%
11383918 requests in 30.03s, 8.11GB read
Requests/sec: 379046.45
Transfer/sec: 276.54MB
Phân tích kết quả benchmark.
Kết quả Kernel (http://10.237.7.78):
- Thread Stats:
- Latency (Độ trễ):
- Avg (Trung bình): 8.25ms (thấp, ổn định hơn kết quả của DPDK).
- Stdev (Độ lệch chuẩn): 7.28ms (biến động thấp, hiệu suất ổn định hơn).
- Max (Tối đa): 76.76ms (rất thấp).
- +/- Stdev: 84.81% (phần lớn yêu cầu nằm trong khoảng ±1 độ lệch chuẩn).
- Req/Sec (Yêu cầu mỗi giây):
- Avg (Trung bình): 14.33k (khá cao).
- Stdev: 2.55k.
- Max: 28.16k.
- +/- Stdev: 65.85%.
- Latency (Độ trễ):
- Tổng quan:
- Requests (Tổng số yêu cầu): 4,275,390 yêu cầu trong 30 giây.
- Requests/sec: 142,183.73 request mỗi giây.
- Transfer/sec (Tốc độ chuyển dữ liệu): 116.47MB/s.
Kết quả DPDK (http://10.237.7.79):
- Thread Stats:
- Latency (Độ trễ):
- Avg (Trung bình): 21.73ms (chưa hiểu tại sao vẫn cao hơn Kernel).
- Stdev (Độ lệch chuẩn): 52.38ms (cao hơn Kernel, biểu hiện của sự không ổn định bằng Kernel).
- Max (Tối đa): 690.81ms.
- +/- Stdev: 88.45%.
- Req/Sec (Yêu cầu mỗi giây):
- Avg (Trung bình): 38.10k.
- Stdev: 4.25k (cao hơn Kernel, biểu thị sự dao động trong số yêu cầu mỗi giây).
- Max: 63.18k.
- +/- Stdev: 76.79%.
- Latency (Độ trễ):
- Tổng quan:
- Requests (Tổng số yêu cầu): 11,383,918 yêu cầu trong 30 giây.
- Requests/sec: 379,046.45 yêu cầu mỗi giây (gấp nhiều lần và vượt trội so với Kernel).
- Transfer/sec (Tốc độ chuyển dữ liệu): 276.54MB/s (cao hơn gấp đôi so với Kernel).
So sánh hiệu suất giữa Kernel và DPDK.
Metric | Kernel (10.237.7.78) | DPDK (10.237.7.79) | Nhận xét |
---|---|---|---|
Latency Avg | 8.25ms | 21.73ms | Kernel có độ trễ thấp hơn. |
Latency Max | 76.76ms | 690.81ms | Kernel ổn định hơn. |
Requests/sec | 142,183.73 | 379,046.45 | DPDK vượt trội về RPS. |
Transfer/sec | 116.47MB/s | 276.54MB/s | DPDK có băng thông cao hơn. |
Tổng số yêu cầu | 4.27 triệu | 11.38 triệu | DPDK xử lý nhiều yêu cầu hơn. |
Kết luận.
- Hiệu suất:
- DPDK vượt trội về số lượng yêu cầu mỗi giây và băng thông. Đây là lợi thế khi hệ thống yêu cầu throughput cao.
- Kernel có độ trễ thấp hơn và hiệu suất ổn định hơn, phù hợp hơn với các yêu cầu thời gian thực.
- Ứng dụng:
- DPDK: Phù hợp với các trường hợp yêu cầu throughput cực lớn như xử lý lưu lượng mạng hoặc các ứng dụng tập trung vào hiệu suất.
- Kernel: Lý tưởng cho các hệ thống cần độ trễ thấp và ổn định, chẳng hạn như các dịch vụ yêu cầu phản hồi nhanh.
- Khuyến nghị:
- Kernel: Sử dụng khi yêu cầu độ trễ thấp là ưu tiên hàng đầu.
- DPDK: Sử dụng khi throughput cao là yêu cầu chính và có thể chấp nhận độ trễ lớn hơn một chút.
Kết quả trên chưa hoàn toàn tối ưu với DPDK vì mình đang thực hiện trên card mạng của máy ảo VMWare, mình nghĩ với card mạng vật lý và thì DPDK sẽ vượt trội so với Kernel, mình sẽ có bài benchmark với phần cứng và cho các bạn xem kết quả ở bài sau nhé.