Sửa lỗi Nginx: could not allocate new entry in shm zone "mylimit"

intermediate Nginx2026-05-29| Linux (Ubuntu, Debian, CentOS), Nginx 1.18.0+, đã bật Rate Limiting (limit_req).

Error Message

could not allocate new entry in shm zone "mylimit" while logging request
#nginx#rate-limiting#shm-zone#limit_req

Vấn đềKhi Nginx bắt đầu từ chối các yêu cầu và nhật ký lỗi của bạn tràn ngập dòng chữ could not allocate new entry in shm zone "mylimit" while logging request, điều đó có nghĩa là vùng bộ nhớ chia sẻ (shm zone) của bạn đã bị cạn kiệt. Điều này thường xảy ra trên các trang web có lưu lượng truy cập cao, nơi mô-đun rate-limiting của Nginx đang theo dõi nhiều địa chỉ IP duy nhất hơn mức bộ nhớ được cấp phát có thể xử lý.

Về cơ bản, Nginx đã hết các ô để lưu trữ trạng thái của các yêu cầu đến, và vì nó không thể theo dõi liệu một IP mới có nên bị giới hạn hay không, nó sẽ mặc định từ chối mục nhập đó hoặc hoạt động không ổn định.

Lỗi trong nhật ký```

2024/05/28 10:15:30 [error] 1234#0: *5678 could not allocate new entry in shm zone "mylimit" while logging request, client: 192.168.1.1, server: example.com, request: "GET /api/v1/resource HTTP/1.1", host: "example.com"


## Giải pháp tức thời: Tăng kích thước vùng nhớCách khắc phục trực tiếp nhất là tăng kích thước của vùng bộ nhớ chia sẻ trong cấu hình Nginx của bạn. Nginx cấp phát một lượng bộ nhớ cố định khi khởi động cho mỗi vùng rate-limiting.
- Mở tệp cấu hình Nginx của bạn (thường là `/etc/nginx/nginx.conf` hoặc một tệp cụ thể trong `/etc/nginx/conf.d/`).- Tìm chỉ thị `limit_req_zone`.- Tăng tham số kích thước (ví dụ: từ `10m` lên `50m` hoặc `100m`).### Cấu hình ví dụTrước:

http { # 10MB có thể chứa khoảng 160.000 trạng thái limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s; }


Sau:

http { # 100MB có thể chứa khoảng 1,6 triệu trạng thái limit_req_zone $binary_remote_addr zone=mylimit:100m rate=10r/s; }


## Tại sao điều này xảy ra: Phép tính toánNginx sử dụng bộ nhớ chia sẻ để lưu trữ trạng thái cho `$binary_remote_addr` (hoặc bất kỳ khóa nào bạn sử dụng). Trong hệ thống 64-bit:
- Một mục nhập trạng thái thường tiêu tốn **128 bytes**.- Một vùng **1MB** có thể lưu trữ khoảng **8.000 đến 16.000** mục nhập tùy thuộc vào kiến trúc và độ dài khóa.- Một vùng **10MB** (mặc định tiêu chuẩn trong nhiều hướng dẫn) xử lý khoảng **160.000** IP duy nhất.Nếu bạn gặp sự gia tăng đột biến về lưu lượng truy cập, một cuộc tấn công DDoS hoặc đơn giản là một trang web rất phổ biến nơi hàng trăm nghìn người dùng duy nhất truy cập trong một khoảng thời gian ngắn, giới hạn 10MB sẽ bị chạm tới nhanh chóng.
## Tối ưu hóa: Sử dụng Binary Remote AddressNếu bạn hiện đang sử dụng `$remote_addr`, hãy chuyển sang `$binary_remote_addr`. Đây là một tối ưu hóa quan trọng cho việc sử dụng bộ nhớ.
- `$remote_addr`: Lưu trữ IP dưới dạng chuỗi (ví dụ: "192.168.1.1"), tốn từ 7 đến 15 bytes cho mỗi mục nhập.- `$binary_remote_addr`: Lưu trữ IP ở định dạng nhị phân (4 bytes cho IPv4, 16 bytes cho IPv6).Việc sử dụng phiên bản nhị phân làm giảm đáng kể dung lượng của mỗi mục nhập trong vùng `shm`, cho phép bạn lưu trữ nhiều trạng thái hơn trong cùng một lượng bộ nhớ.

Luôn ưu tiên dùng binary_remote_addr để giới hạn tốc độ

limit_req_zone $binary_remote_addr zone=mylimit:20m rate=5r/s;


## Cách xác minh bản sửa lỗiSau khi cập nhật cấu hình, bạn phải kiểm tra cú pháp và tải lại Nginx:

Kiểm tra lỗi cú pháp

sudo nginx -t

Nếu thành công, tải lại dịch vụ

sudo systemctl reload nginx


Để xác nhận lỗi đã hết, hãy theo dõi nhật ký lỗi của bạn trong thời gian thực khi trang web đang tải:

tail -f /var/log/nginx/error.log | grep "shm zone"


Nếu lỗi không còn xuất hiện, việc cấp phát bộ nhớ mới đã đủ. Nếu nó xuất hiện lại nhanh chóng, bạn có thể đang bị tấn công phân tán hoặc khối lượng lưu lượng truy cập của bạn yêu cầu một vùng lớn hơn nữa (ví dụ: 200m hoặc 500m).
## Những sai lầm phổ biến### 1. Giới hạn tốc độ quá mứcNếu `rate` của bạn được đặt quá thấp (ví dụ: `1r/s`), Nginx sẽ giữ trạng thái trong bộ nhớ lâu hơn để đảm bảo máy khách tuân thủ giới hạn. Điều này làm đầy vùng nhớ nhanh hơn. Hãy đánh giá xem các giới hạn tốc độ của bạn có quá khắt khe đối với lượng người dùng hợp lệ hay không.
### 2. Theo dõi sai biếnNếu bạn sử dụng `$http_user_agent` làm khóa và nhận được hàng nghìn tác nhân người dùng duy nhất (hoặc giả mạo), bộ nhớ sẽ đầy gần như ngay lập tức. Hãy gắn bó với `$binary_remote_addr` trừ khi bạn có một trường hợp sử dụng rất cụ thể.
### 3. Giới hạn bộ nhớ trên máy chủĐừng chỉ đặt `zone=mylimit:2g` nếu máy chủ của bạn chỉ có 1GB RAM. Nginx sẽ không khởi động được nếu nó không thể cấp phát bộ nhớ chia sẻ được yêu cầu từ hệ điều hành.
## Bài học rút ra- **Tính toán trước dung lượng:** Ước tính số lượng khách truy cập duy nhất cao nhất mỗi phút và cấp phát ít nhất 1MB cho mỗi 10.000 IP duy nhất đồng thời dự kiến.- **Theo dõi RAM:** Các vùng bộ nhớ chia sẻ được cấp phát khi khởi động. Đảm bảo hệ thống của bạn có đủ RAM vật lý trống để chứa các vùng lớn.- **Sử dụng Binary:** Luôn sử dụng `$binary_remote_addr` để tối đa hóa số lượng mục nhập trên mỗi megabyte.- **Dọn dẹp:** Nginx tự động xóa các mục cũ khi vùng nhớ đầy, nhưng nó không thể theo kịp nếu lượng IP mới tràn vào nhanh hơn tốc độ hết hạn LRU (Least Recently Used). Các vùng nhớ lớn hơn cung cấp bộ đệm cần thiết.

Related Error Notes