Người quản lý của tôi tại một chủ nhân trước đây đã từng mô tả Red Hat [RHEL] là "được tối ưu hóa cho tư vấn". . Làm rất nhiều điều chỉnh để tăng các giới hạn và bộ đệm khác nhau. Điều này tạo ra một thị trường sinh lợi cho các chuyên gia tư vấn biết tất cả các núm cần quay.
Gần đây, chúng tôi muốn điểm chuẩn về cách MongoDB hành xử với một số lượng lớn các kết nối. Điều này khiến tôi phải xem lại chủ đề này và làm mới bộ nhớ của tôi về cách tạo một số lượng lớn các kết nối và luồng trên máy chủ Linux. Trong quá trình tôi tìm thấy một số điều chỉnh mới, tôi đã không sử dụng lần cuối cùng tôi làm điều này.
Cấu hình MongoDB
Ngay cả MongoDB cũng có một tùy chọn để giới hạn số lượng kết nối đến tối đa. Nó mặc định là 64K.
# mongod.conf
net:
maxIncomingConnections: 999999
Lưu ý rằng theo mặc định MongoDB tạo một luồng công nhân chuyên dụng cho mỗi kết nối đến. Tôi muốn kiểm tra mặc định này, nhưng tôi nên chỉ ra một cài đặt liên quan thay đổi đối với mô hình nhóm công nhân. Có lẽ điều này cho phép số lượng lớn hơn các kết nối đến và sử dụng ít luồng hơn. Lưu ý rằng tùy chọn này vẫn được dán nhãn thử nghiệm, ngay cả khi nó được ghi lại chính thức:
net:
serviceExecutor: adaptive
Nhưng đối với các thử nghiệm của tôi, tôi sẽ tạo một luồng cho mỗi kết nối, vì vậy tất cả các cấu hình dưới đây cũng cần thiết ...
Cấu hình Linux
Để thiết lập các ulimit một cách chính xác, tôi cần phải quay lại và nhớ tất cả các nguyên tắc Unix cơ bản tôi học được ở trường đại học:
- Mọi thứ đều là một tập tin. Cụ thể, các kết nối TCP/IP là các tệp mở theo như ULIMIT.
- Vì lý do lịch sử, NPROC thực sự là số lượng chủ đề. Trong lịch sử, một quá trình Linux là một chủ đề duy nhất và khối lượng công việc đồng thời là đa quá trình.
- Chủ đề phân bổ bộ nhớ từ ngăn xếp, cũng có kích thước tối đa.
# Connections are files because in Unix everything is a file.
echo "ec2-user soft nofile 9999999" | sudo tee -a /etc/security/limits.conf
echo "ec2-user hard nofile 9999999" | sudo tee -a /etc/security/limits.conf
# nproc is really number of threads.
echo "ec2-user soft nproc 9999999" | sudo tee -a /etc/security/limits.conf
echo "ec2-user hard nproc 9999999" | sudo tee -a /etc/security/limits.conf
# Threads need memory from the stack.
echo "ec2-user soft stack 9999999" | sudo tee -a /etc/security/limits.conf
echo "ec2-user hard stack 9999999" | sudo tee -a /etc/security/limits.conf
Để biết thêm thông tin, hãy xem trang Hướng dẫn MongoDB trên Cài đặt Ulimit.
Nhưng xin chờ chút nữa! Tạo chủ đề sử dụng MMAP để phân bổ bộ nhớ từ ngăn xếp. Và ở cấp độ kernel, có một cài đặt cho số lượng khối bộ nhớ mmap tối đa cho mỗi quá trình, cũng phải tăng lên:
echo 9999999 > /proc/sys/vm/max_map_count
# If you want to persist across reboots
echo "vm.max_map_count=9999999" | sudo tee -a /etc/sysctl.conf
Cuối cùng, trên máy khách điểm chuẩn, tôi bắt đầu đạt giới hạn với TCP/IP. Trong giao thức TCP, một ổ cắm được xác định với bộ tuple [địa chỉ cục bộ, cổng cục bộ, địa chỉ từ xa, cổng từ xa] và bộ tu này phải là duy nhất cho mỗi ổ cắm. Các số cổng nằm trong khoảng từ 1 đến 65535. Vì vậy, từ một ứng dụng ứng dụng điểm chuẩn duy nhất, tôi chỉ có thể tạo 65535 kết nối đi. Để điểm chuẩn nhiều kết nối hơn thế này, giải pháp thay thế duy nhất là có nhiều hơn một máy chủ khách hoặc ít nhất là nhiều hơn một địa chỉ IP cho máy khách. Nhưng tôi đã không đi xa đến thế.
[Ở phía máy chủ, cổng tất nhiên là Cổng Mongod nổi tiếng 27017.]
Tôi đã rất ngạc nhiên khi biết rằng theo mặc định, Linux thậm chí sẽ không sử dụng toàn bộ các cổng 65K mà TCP có thể. Ngay cả điều này phải được cấu hình:
echo 1024 65530 > /proc/sys/net/ipv4/ip_local_port_range
# If you want to persist across reboots
echo "net.ipv4.ip_local_port_range = 1024 65530" | sudo tee -a /etc/sysctl.conf
Hai số là các cổng tối đa và tối đa. Lưu ý rằng cấu hình này không cần thiết trên máy chủ, chỉ là ứng dụng khách chuẩn.
Cấu hình EC2
Trên AWS, tôi thấy rằng trên các trường hợp M5 của EC2 mà tôi đã thử - lên đến M5.2xlarge - Tôi chỉ có thể tạo các kết nối và chủ đề 32K. Với cùng một cấu hình, nhưng chuyển sang loại thể hiện C3.8xlarge, tôi có thể tạo nhiều hơn thế, đạt đến giới hạn gần 65K được chỉ định bởi IP_LOCAL_PORT_RANGE ở trên.
Tôi đã không tìm thấy bất kỳ tài liệu AWS nào sẽ xác nhận quan sát của tôi về các trường hợp M5. AWS cũng không hỗ trợ xác nhận nó. Vì vậy, nó vẫn có thể là một lỗi về phía tôi.
Bản tóm tắt
Vì vậy, đây là tất cả các bước trong một bản sao và kịch bản có thể làm được. Đây là mục đích được xây dựng cho các trường hợp AWS chạy Amazon Linux 2. Bạn có thể cần điều chỉnh cho các phiên bản khác của Linux. Cụ thể, trên Centos và Rhel thay đổi tên người dùng từ ec2-user
thành root
.
# This assumes a fresh Linux host from standard Amazon Linux 2 images.
# Adaptable to Centos/RHEL too.
sudo su
sed -i .orig 's/net\:/net\:\n maxIncomingConnections: 999999/' /etc/mongod.conf
# Connections are files because in Unix everything is a file.
echo "ec2-user soft nofile 9999999" | sudo tee -a /etc/security/limits.conf
echo "ec2-user hard nofile 9999999" | sudo tee -a /etc/security/limits.conf
# nproc is really number of threads.
echo "ec2-user soft nproc 9999999" | sudo tee -a /etc/security/limits.conf
echo "ec2-user hard nproc 9999999" | sudo tee -a /etc/security/limits.conf
# Threads need memory from the stack.
echo "ec2-user soft stack 9999999" | sudo tee -a /etc/security/limits.conf
echo "ec2-user hard stack 9999999" | sudo tee -a /etc/security/limits.conf
# Threads allocate memory with mmap
echo 9999999 > /proc/sys/vm/max_map_count
# If you want to persist across reboots
echo "vm.max_map_count=9999999" | sudo tee -a /etc/sysctl.conf
# Needed for outgoing connections [on client]
echo 1024 65530 > /proc/sys/net/ipv4/ip_local_port_range
echo "net.ipv4.ip_local_port_range = 1024 65530" | sudo tee -a /etc/sysctl.conf
# Checks EC2 instance type but doesn't do anything about it
curl //169.254.169.254/latest/meta-data/instance-type