TL;DR: Cách khắc phục nhanh
Lỗi này xuất hiện khi Redis nhận được một yêu cầu không tuân thủ định dạng RESP (Redis Serialization Protocol). Nó thường có nghĩa là tiền tố độ dài cho một bulk string (phần bắt đầu bằng $) bị thiếu, sai hoặc không phải là một số hợp lệ.
- Sử dụng Telnet hoặc Netcat? Bạn phải tuân thủ chính xác định dạng RESP. Một lệnh
GET keyđơn giản sẽ không hoạt động ở chế độ thô (raw mode); bạn cần*2\r\n$3\r\nGET\r\n$4\r\nkey1\r\n. - Thấy lỗi này trên trình duyệt? Có khả năng bạn đang gửi lưu lượng HTTP đến cổng Redis. Redis không hỗ trợ giao thức HTTP.
- Sử dụng thư viện Client? Hãy kiểm tra kích thước dữ liệu của bạn. Đảm bảo bạn không vượt quá giới hạn
proto-max-bulk-len, mặc định là 512MB.
Tại sao lỗi này xảy ra
Redis sử dụng một ngôn ngữ gọi là RESP. Khi bạn gửi một lệnh, Redis mong đợi một cấu trúc nghiêm ngặt. Một "bulk string" bắt đầu bằng ký tự $, theo sau là số byte chính xác trong chuỗi đó, một CRLF (\r\n), chính dữ liệu đó và một CRLF khác.
Lỗi ERR Protocol error: invalid bulk length kích hoạt nếu ký tự sau $ không phải là một số. Redis sẽ ngắt kết nối ngay lập tức. Điều này nhằm tự bảo vệ khỏi việc hỏng bộ nhớ hoặc tràn bộ đệm do dữ liệu rác gây ra.
Các kịch bản phổ biến và giải pháp
1. Các lệnh thủ công qua Telnet hoặc Netcat
Kiểm tra Redis thủ công là một cách hay, nhưng việc nhập các lệnh dưới dạng văn bản thuần túy thường thất bại. Redis có chế độ "inline command" cho các yêu cầu đơn giản như PING. Tuy nhiên, các thao tác phức tạp yêu cầu định dạng RESP chuẩn.
Lỗi thường gặp:
$ telnet localhost 6379
$ SET mykey
# Nếu bạn nhập $ theo sau là văn bản thay vì một con số:
$invalid_length
-ERR Protocol error: invalid bulk length
Cách khắc phục: Hãy sử dụng redis-cli để kiểm tra thủ công. Nếu bạn bắt buộc phải sử dụng Telnet, hãy sử dụng cấu trúc RESP đầy đủ. Ví dụ, để đặt "name" thành "John", bạn cần gửi số lượng byte chính xác cho từng phần của lệnh.
# Định dạng RESP đầy đủ
*3
$3
SET
$4
name
$4
John
2. Các yêu cầu HTTP vô tình
Lỗi này thường xuyên xuất hiện trong log khi một trình duyệt web hoặc trình quét bảo mật truy cập vào cổng 6379. Một yêu cầu HTTP bắt đầu bằng GET / HTTP/1.1. Redis thấy dấu / hoặc các header và cố gắng phân tích chúng dưới dạng RESP. Nó sẽ thất bại ngay lập tức.
Cách khắc phục:
- Kiểm tra các biến môi trường
REDIS_URLcủa bạn. Đảm bảo chúng không vô tình trỏ đến một dịch vụ web. - Kiểm tra các bản kiểm tra sức khỏe (health checks) của bộ cân bằng tải. Các công cụ như AWS ELB hoặc Kubernetes Liveness Probes nên sử dụng kiểm tra tương thích với Redis, không phải một lệnh HTTP GET thô.
3. Lỗi mã hóa và tuần tự hóa
Các thư viện client tùy chỉnh hoặc cũ hơn trong các ngôn ngữ như C hoặc Go đôi khi tính toán sai độ dài chuỗi. Điều này thường xảy ra với các ký tự multi-byte như emoji UTF-8 hoặc văn bản tiếng Việt.
Nếu thư viện của bạn đếm ký tự thay vì byte, phép tính sẽ không khớp. Redis mong đợi số lượng byte. Nếu độ dài khai báo là 8 nhưng payload thực tế là 9 byte, giao thức sẽ bị lỗi.
Cách khắc phục:
- Luôn sử dụng
Buffer.byteLength()hoặc hàm tương đương thay vìstring.length. - Cập nhật client Redis của bạn lên phiên bản ổn định mới nhất.
Ví dụ Node.js:
const val = "Xin chào";
console.log(val.length); // 8 (Sai đối với Redis!)
console.log(Buffer.byteLength(val)); // 9 (Đúng!)
4. Payload quá lớn
Mặc dù lỗi này thường báo hiệu lỗi định dạng, nó cũng có thể xảy ra nếu client gửi một giá trị độ dài lớn bất thường. Redis thậm chí sẽ không cố gắng phân tích yêu cầu nếu header tuyên bố dữ liệu lớn hơn mức máy chủ có thể xử lý.
Cách khắc phục: Kiểm tra tệp redis.conf của bạn để xem giới hạn proto-max-bulk-len. Mặc định là 512MB. Nếu bạn cần lưu trữ các tệp lớn hơn, hãy chia nhỏ dữ liệu thành các phần hoặc sử dụng APPEND để xây dựng giá trị dần dần.
# Kiểm tra giới hạn hiện tại của bạn qua CLI
CONFIG GET proto-max-bulk-len
Cách xác minh bản sửa lỗi
Bạn cần xem chính xác những gì client đang gửi. Sử dụng ngrep để đánh hơi lưu lượng thô đi vào máy chủ Redis của bạn. Đây là cách nhanh nhất để phát hiện dữ liệu sai định dạng.
Chạy lệnh này để theo dõi lưu lượng truy cập đến:
sudo ngrep -W byline -d any port 6379
Hãy chú ý đến các dấu $. Nếu bạn thấy $NaN, $-5, hoặc $ theo sau là văn bản, mã client của bạn đang bị lỗi. Một yêu cầu "khỏe mạnh" trông giống như một chồng các dấu sao và dấu đô la sạch sẽ. Khi giao thức được sửa, các lỗi sẽ dừng lại và client của bạn sẽ nhận được phản hồi +OK tiêu chuẩn.

